encre_css/
preflight.rs

1//! Define the default set of base CSS styles used to make websites consistent across browsers.
2//!
3//! By default, this base CSS is included in the generated CSS and you can customize it
4//! by manually setting the [`Config::preflight`] configuration field to `Preflight::new_full()`
5//! and by using [`Preflight::ring_color`], [`Preflight::border_color`],
6//! [`Preflight::placeholder_color`], [`Preflight::font_family_sans`]
7//! or [`Preflight::font_family_mono`].
8//!
9//! ```
10//! use encre_css::{Preflight, Config};
11//!
12//! let mut config = Config::default();
13//! config.preflight = Preflight::new_full()
14//!     .border_color("#444");
15//!
16//! assert!(encre_css::generate([], &config).starts_with("*, ::before, ::after {
17//!   box-sizing: border-box;
18//!   border-width: 0;
19//!   border-style: solid;
20//!   border-color: #444;
21//! }"));
22//! ```
23//!
24//! You can also use your own default CSS using [`Preflight::new_custom`].
25//!
26//! ```
27//! use encre_css::{Preflight, Config};
28//!
29//! let mut config = Config::default();
30//! config.preflight = Preflight::new_custom("html, body {
31//!   width: 100vw;
32//!   height: 100vh;
33//!   margin: 0;
34//! }");
35//!
36//! assert_eq!(encre_css::generate([], &config), "html, body {
37//!   width: 100vw;
38//!   height: 100vh;
39//!   margin: 0;
40//! }");
41//! ```
42//!
43//! Finally you can disable it using [`Preflight::new_none`].
44//!
45//! ```
46//! use encre_css::{Preflight, Config};
47//!
48//! let mut config = Config::default();
49//! config.preflight = Preflight::new_none();
50//!
51//! assert_eq!(encre_css::generate([], &config), "");
52//! ```
53//!
54//! Based on [Tailwind's default preflight](https://tailwindcss.com/docs/preflight).
55//!
56//! [`Config::preflight`]: crate::config::Config::preflight
57use serde::{Deserialize, Serialize};
58use std::borrow::Cow;
59
60const DEFAULT_RING_COLOR: &str = "rgb(59 130 246 / 0.5)";
61const DEFAULT_BORDER_COLOR: &str = "currentColor";
62const DEFAULT_PLACEHOLDER_COLOR: &str = "#9ca3af";
63const DEFAULT_FONT_FAMILY_SANS: &str = r#"ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji""#;
64const DEFAULT_FONT_FAMILY_MONO: &str = r#"ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace"#;
65
66const DEFAULT_PREFLIGHT: &str = concat!(
67    // 1. Prevent padding and border from affecting element width.
68    // 2. Allow adding a border to an element by just adding a border-width.
69    r#"*, ::before, ::after {
70  box-sizing: border-box;
71  border-width: 0;
72  border-style: solid;
73  border-color: theme('borderColor');
74}
75
76::before, ::after {
77  --en-content: '';
78}
79
80"#,
81    // 1. Use a consistent sensible line-height in all browsers.
82    // 2. Prevent adjustments of font size after orientation changes in iOS.
83    // 3. Use a more readable tab size.
84    // 4. Use the user's configured `sans` font-family by default.
85    r#"html {
86  line-height: 1.5;
87  -webkit-text-size-adjust: 100%;
88  -moz-tab-size: 4;
89  tab-size: 4;
90  font-family: theme('fontFamily.sans');
91}
92
93"#,
94    // 1. Remove the margin in all browsers.
95    // 2. Inherit line-height from `html` so users can set them as a class directly on the `html` element.
96    r#"body {
97  margin: 0;
98  line-height: inherit;
99}
100
101"#,
102    // 1. Add the correct height in Firefox.
103    // 2. Correct the inheritance of border color in Firefox.
104    // 3. Ensure horizontal rules are visible by default.
105    r#"hr {
106  height: 0;
107  color: inherit;
108  border-top-width: 1px;
109}
110
111"#,
112    // Add the correct text decoration in Chrome, Edge, and Safari.
113    r#"abbr:where([title]) {
114  text-decoration: underline dotted;
115}
116
117"#,
118    // Remove the default font size and weight for headings.
119    r#"h1, h2, h3, h4, h5, h6 {
120  font-size: inherit;
121  font-weight: inherit;
122}
123
124"#,
125    // Reset links to optimize for opt-in styling instead of opt-out.
126    r#"a {
127  color: inherit;
128  text-decoration: inherit;
129}
130
131"#,
132    // Add the correct font weight in Edge and Safari.
133    r#"b, strong {
134  font-weight: bolder;
135}
136
137"#,
138    // 1. Use the user's configured `mono` font family by default.
139    // 2. Correct the odd `em` font sizing in all browsers.
140    r#"code, kbd, samp, pre {
141  font-family: theme('fontFamily.mono');
142  font-size: 1em;
143}
144
145"#,
146    // Add the correct font size in all browsers.
147    r#"small {
148  font-size: 80%;
149}
150
151"#,
152    // Prevent `sub` and `sup` elements from affecting the line height in all browsers.
153    r#"sub, sup {
154  font-size: 75%;
155  line-height: 0;
156  position: relative;
157  vertical-align: baseline;
158}
159
160sub {
161  bottom: -0.25em;
162}
163
164sup {
165  top: -0.5em;
166}
167
168"#,
169    // 1. Remove text indentation from table contents in Chrome and Safari.
170    // 2. Correct table border color inheritance in all Chrome and Safari.
171    // 3. Remove gaps between table borders by default.
172    r#"table {
173  text-indent: 0;
174  border-color: inherit;
175  border-collapse: collapse;
176}
177
178"#,
179    // 1. Change the font styles in all browsers.
180    // 2. Remove the margin in Firefox and Safari.
181    // 3. Remove default padding in all browsers.
182    r#"button, input, optgroup, select, textarea {
183  font-family: inherit;
184  font-size: 100%;
185  font-weight: inherit;
186  line-height: inherit;
187  color: inherit;
188  margin: 0;
189  padding: 0;
190}
191
192"#,
193    // Remove the inheritance of text transform in Edge and Firefox.
194    r#"button, select {
195  text-transform: none;
196}
197
198"#,
199    // 1. Correct the inability to style clickable types in iOS and Safari.
200    // 2. Remove default button styles.
201    r#"button, [type='button'], [type='reset'], [type='submit'] {
202  -webkit-appearance: button;
203  background-color: transparent;
204  background-image: none;
205}
206
207"#,
208    // Use the modern Firefox focus style for all focusable elements.
209    r#":-moz-focusring {
210  outline: auto;
211}
212
213"#,
214    // Remove the additional `:invalid` styles in Firefox.
215    r#":-moz-ui-invalid {
216  box-shadow: none;
217}
218
219"#,
220    // Add the correct vertical alignment in Chrome and Firefox.
221    r#"progress {
222  vertical-align: baseline;
223}
224
225"#,
226    // Correct the cursor style of increment and decrement buttons in Safari.
227    r#"::-webkit-inner-spin-button, ::-webkit-outer-spin-button {
228  height: auto;
229}
230
231"#,
232    // 1. Correct the odd appearance in Chrome and Safari.
233    // 2. Correct the outline style in Safari.
234    r#"[type='search'] {
235  -webkit-appearance: textfield;
236  outline-offset: -2px;
237}
238
239"#,
240    // Remove the inner padding in Chrome and Safari on macOS.
241    r#"::-webkit-search-decoration {
242  -webkit-appearance: none;
243}
244
245"#,
246    // 1. Correct the inability to style clickable types in iOS and Safari.
247    // 2. Change font properties to `inherit` in Safari.
248    r#"::-webkit-file-upload-button {
249  -webkit-appearance: button;
250  font: inherit;
251}
252
253"#,
254    // Add the correct display in Chrome and Safari.
255    r#"summary {
256  display: list-item;
257}
258
259"#,
260    // Removes the default spacing and border for appropriate elements.
261    r#"blockquote, dl, dd, h1, h2, h3, h4, h5, h6, hr, figure, p, pre {
262  margin: 0;
263}
264
265fieldset {
266  margin: 0;
267  padding: 0;
268}
269
270legend {
271  padding: 0;
272}
273
274ol, ul, menu {
275  list-style: none;
276  margin: 0;
277  padding: 0;
278}
279
280"#,
281    // Prevent resizing textareas horizontally by default.
282    r#"textarea {
283  resize: vertical;
284}
285
286"#,
287    // 1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300)
288    // 2. Set the default placeholder color to the user's configured gray 400 color.
289    r#"input::placeholder, textarea::placeholder {
290  opacity: 1;
291  color: theme('placeholderColor');
292}
293
294"#,
295    // Set the default cursor for buttons.
296    r#"button, [role="button"] {
297  cursor: pointer;
298}
299
300"#,
301    // Make sure disabled buttons don't get the pointer cursor.
302    r#":disabled {
303  cursor: default;
304}
305
306"#,
307    // 1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14)
308    // 2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210)
309    //    This can trigger a poorly considered lint error in some tools but is included by design.
310    r#"img, svg, video, canvas, audio, iframe, embed, object {
311  display: block;
312  vertical-align: middle;
313}
314
315"#,
316    // Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14)
317    r#"img, video {
318  max-width: 100%;
319  height: auto;
320}
321
322"#,
323    // Defaults
324    r#"*, ::before, ::after {
325  --en-border-spacing-x: 0;
326  --en-border-spacing-y: 0;
327  --en-translate-x: 0;
328  --en-translate-y: 0;
329  --en-rotate: 0;
330  --en-skew-x: 0;
331  --en-skew-y: 0;
332  --en-scale-x: 1;
333  --en-scale-y: 1;
334  --en-pan-x: ;
335  --en-pan-y: ;
336  --en-pinch-zoom: ;
337  --en-scroll-snap-strictness: proximity;
338  --en-ordinal: ;
339  --en-slashed-zero: ;
340  --en-numeric-figure: ;
341  --en-numeric-spacing: ;
342  --en-numeric-fraction: ;
343  --en-ring-inset: ;
344  --en-ring-offset-width: 0px;
345  --en-ring-offset-color: #fff;
346  --en-ring-color: theme('ringColor');
347  --en-ring-offset-shadow: 0 0 #0000;
348  --en-ring-shadow: 0 0 #0000;
349  --en-shadow: 0 0 #0000;
350  --en-shadow-colored: 0 0 #0000;
351  --en-blur: ;
352  --en-brightness: ;
353  --en-contrast: ;
354  --en-grayscale: ;
355  --en-hue-rotate: ;
356  --en-invert: ;
357  --en-saturate: ;
358  --en-sepia: ;
359  --en-drop-shadow: ;
360  --en-backdrop-blur: ;
361  --en-backdrop-brightness: ;
362  --en-backdrop-contrast: ;
363  --en-backdrop-grayscale: ;
364  --en-backdrop-hue-rotate: ;
365  --en-backdrop-invert: ;
366  --en-backdrop-opacity: ;
367  --en-backdrop-saturate: ;
368  --en-backdrop-sepia: ;
369}
370
371::-webkit-backdrop {
372  --en-border-spacing-x: 0;
373  --en-border-spacing-y: 0;
374  --en-translate-x: 0;
375  --en-translate-y: 0;
376  --en-rotate: 0;
377  --en-skew-x: 0;
378  --en-skew-y: 0;
379  --en-scale-x: 1;
380  --en-scale-y: 1;
381  --en-pan-x: ;
382  --en-pan-y: ;
383  --en-pinch-zoom: ;
384  --en-scroll-snap-strictness: proximity;
385  --en-ordinal: ;
386  --en-slashed-zero: ;
387  --en-numeric-figure: ;
388  --en-numeric-spacing: ;
389  --en-numeric-fraction: ;
390  --en-ring-inset: ;
391  --en-ring-offset-width: 0px;
392  --en-ring-offset-color: #fff;
393  --en-ring-color: theme('ringColor');
394  --en-ring-offset-shadow: 0 0 #0000;
395  --en-ring-shadow: 0 0 #0000;
396  --en-shadow: 0 0 #0000;
397  --en-shadow-colored: 0 0 #0000;
398  --en-blur: ;
399  --en-brightness: ;
400  --en-contrast: ;
401  --en-grayscale: ;
402  --en-hue-rotate: ;
403  --en-invert: ;
404  --en-saturate: ;
405  --en-sepia: ;
406  --en-drop-shadow: ;
407  --en-backdrop-blur: ;
408  --en-backdrop-brightness: ;
409  --en-backdrop-contrast: ;
410  --en-backdrop-grayscale: ;
411  --en-backdrop-hue-rotate: ;
412  --en-backdrop-invert: ;
413  --en-backdrop-opacity: ;
414  --en-backdrop-saturate: ;
415  --en-backdrop-sepia: ;
416}
417
418::backdrop {
419  --en-border-spacing-x: 0;
420  --en-border-spacing-y: 0;
421  --en-translate-x: 0;
422  --en-translate-y: 0;
423  --en-rotate: 0;
424  --en-skew-x: 0;
425  --en-skew-y: 0;
426  --en-scale-x: 1;
427  --en-scale-y: 1;
428  --en-pan-x: ;
429  --en-pan-y: ;
430  --en-pinch-zoom: ;
431  --en-scroll-snap-strictness: proximity;
432  --en-ordinal: ;
433  --en-slashed-zero: ;
434  --en-numeric-figure: ;
435  --en-numeric-spacing: ;
436  --en-numeric-fraction: ;
437  --en-ring-inset: ;
438  --en-ring-offset-width: 0px;
439  --en-ring-offset-color: #fff;
440  --en-ring-color: theme('ringColor');
441  --en-ring-offset-shadow: 0 0 #0000;
442  --en-ring-shadow: 0 0 #0000;
443  --en-shadow: 0 0 #0000;
444  --en-shadow-colored: 0 0 #0000;
445  --en-blur: ;
446  --en-brightness: ;
447  --en-contrast: ;
448  --en-grayscale: ;
449  --en-hue-rotate: ;
450  --en-invert: ;
451  --en-saturate: ;
452  --en-sepia: ;
453  --en-drop-shadow: ;
454  --en-backdrop-blur: ;
455  --en-backdrop-brightness: ;
456  --en-backdrop-contrast: ;
457  --en-backdrop-grayscale: ;
458  --en-backdrop-hue-rotate: ;
459  --en-backdrop-invert: ;
460  --en-backdrop-opacity: ;
461  --en-backdrop-saturate: ;
462  --en-backdrop-sepia: ;
463}"#
464);
465
466/// The set of default styles.
467///
468/// See [`crate::preflight`].
469#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone)]
470#[serde(rename_all = "lowercase")]
471#[serde(tag = "type", content = "css")]
472pub enum Preflight {
473    /// No preflight will be generated.
474    None,
475
476    /// A custom preflight will be used.
477    Custom(Cow<'static, str>),
478
479    /// The full default preflight will be generated with some configuration options.
480    Full {
481        /// Set the default ring color.
482        ring_color: Option<Cow<'static, str>>,
483
484        /// Set the default border color.
485        border_color: Option<Cow<'static, str>>,
486
487        /// Set the default placeholder color.
488        placeholder_color: Option<Cow<'static, str>>,
489
490        /// Set the default sans-serif font family.
491        font_family_sans: Option<Cow<'static, str>>,
492
493        /// Set the default monospace font family.
494        font_family_mono: Option<Cow<'static, str>>,
495    },
496}
497
498impl Preflight {
499    /// Create a new [`Preflight::None`].
500    pub fn new_none() -> Self {
501        Self::None
502    }
503
504    /// Create a new [`Preflight::Custom`].
505    pub fn new_custom<T: Into<Cow<'static, str>>>(css: T) -> Self {
506        Self::Custom(css.into())
507    }
508
509    /// Create a new [`Preflight::Full`] with default values for options.
510    pub fn new_full() -> Self {
511        Self::Full {
512            ring_color: None,
513            border_color: None,
514            placeholder_color: None,
515            font_family_sans: None,
516            font_family_mono: None,
517        }
518    }
519
520    /// Set the default ring color.
521    ///
522    /// The default value is `rgb(59 130 246 / 0.5)`.
523    #[must_use]
524    pub fn ring_color<T: Into<Cow<'static, str>>>(mut self, new_ring_color: T) -> Self {
525        if let Self::Full {
526            ref mut ring_color, ..
527        } = self
528        {
529            *ring_color = Some(new_ring_color.into());
530        }
531
532        self
533    }
534
535    /// Set the default border color.
536    ///
537    /// The default value is `currentColor`.
538    #[must_use]
539    pub fn border_color<T: Into<Cow<'static, str>>>(mut self, new_border_color: T) -> Self {
540        if let Self::Full {
541            ref mut border_color,
542            ..
543        } = self
544        {
545            *border_color = Some(new_border_color.into());
546        }
547
548        self
549    }
550
551    /// Set the default placeholder color.
552    ///
553    /// The default value is `#9ca3af`.
554    #[must_use]
555    pub fn placeholder_color<T: Into<Cow<'static, str>>>(
556        mut self,
557        new_placeholder_color: T,
558    ) -> Self {
559        if let Self::Full {
560            ref mut placeholder_color,
561            ..
562        } = self
563        {
564            *placeholder_color = Some(new_placeholder_color.into());
565        }
566
567        self
568    }
569
570    /// Set the default sans-serif font family.
571    ///
572    /// The default value is `ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"`.
573    #[must_use]
574    pub fn font_family_sans<T: Into<Cow<'static, str>>>(mut self, new_font_family_sans: T) -> Self {
575        if let Self::Full {
576            ref mut font_family_sans,
577            ..
578        } = self
579        {
580            *font_family_sans = Some(new_font_family_sans.into());
581        }
582
583        self
584    }
585
586    /// Set the default monospace font family.
587    ///
588    /// The default value is `ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace`.
589    #[must_use]
590    pub fn font_family_mono<T: Into<Cow<'static, str>>>(mut self, new_font_family_mono: T) -> Self {
591        if let Self::Full {
592            ref mut font_family_mono,
593            ..
594        } = self
595        {
596            *font_family_mono = Some(new_font_family_mono.into());
597        }
598
599        self
600    }
601
602    pub(crate) fn build(&self) -> Cow<'static, str> {
603        match self {
604            Self::None => Cow::from(""),
605            Self::Custom(css) => css.clone(),
606            Self::Full {
607                ring_color,
608                border_color,
609                font_family_sans,
610                font_family_mono,
611                placeholder_color,
612            } => Cow::from(
613                DEFAULT_PREFLIGHT
614                    .replace(
615                        "theme('ringColor')",
616                        ring_color
617                            .as_ref()
618                            .unwrap_or(&Cow::Borrowed(DEFAULT_RING_COLOR)),
619                    )
620                    .replace(
621                        "theme('borderColor')",
622                        border_color
623                            .as_ref()
624                            .unwrap_or(&Cow::Borrowed(DEFAULT_BORDER_COLOR)),
625                    )
626                    .replace(
627                        "theme('placeholderColor')",
628                        placeholder_color
629                            .as_ref()
630                            .unwrap_or(&Cow::Borrowed(DEFAULT_PLACEHOLDER_COLOR)),
631                    )
632                    .replace(
633                        "theme('fontFamily.sans')",
634                        font_family_sans
635                            .as_ref()
636                            .unwrap_or(&Cow::Borrowed(DEFAULT_FONT_FAMILY_SANS)),
637                    )
638                    .replace(
639                        "theme('fontFamily.mono')",
640                        font_family_mono
641                            .as_ref()
642                            .unwrap_or(&Cow::Borrowed(DEFAULT_FONT_FAMILY_MONO)),
643                    ),
644            ),
645        }
646    }
647}
648
649impl Default for Preflight {
650    fn default() -> Self {
651        Self::Full {
652            ring_color: None,
653            border_color: None,
654            placeholder_color: None,
655            font_family_sans: None,
656            font_family_mono: None,
657        }
658    }
659}
660
661#[cfg(test)]
662mod tests {
663    use super::*;
664    use crate::{generate, Config};
665
666    use pretty_assertions::assert_eq;
667
668    #[test]
669    #[allow(clippy::too_many_lines)]
670    fn full_preflight() {
671        let preflight = Preflight::new_full()
672            .ring_color("#f00")
673            .border_color("#0f0")
674            .placeholder_color("#00f")
675            .font_family_sans("sans-serif")
676            .font_family_mono("monospace");
677        let config = Config {
678            preflight,
679            ..Default::default()
680        };
681
682        let generated = generate(["w-full"], &config);
683
684        assert_eq!(
685            generated,
686            String::from(
687                r#"*, ::before, ::after {
688  box-sizing: border-box;
689  border-width: 0;
690  border-style: solid;
691  border-color: #0f0;
692}
693
694::before, ::after {
695  --en-content: '';
696}
697
698html {
699  line-height: 1.5;
700  -webkit-text-size-adjust: 100%;
701  -moz-tab-size: 4;
702  tab-size: 4;
703  font-family: sans-serif;
704}
705
706body {
707  margin: 0;
708  line-height: inherit;
709}
710
711hr {
712  height: 0;
713  color: inherit;
714  border-top-width: 1px;
715}
716
717abbr:where([title]) {
718  text-decoration: underline dotted;
719}
720
721h1, h2, h3, h4, h5, h6 {
722  font-size: inherit;
723  font-weight: inherit;
724}
725
726a {
727  color: inherit;
728  text-decoration: inherit;
729}
730
731b, strong {
732  font-weight: bolder;
733}
734
735code, kbd, samp, pre {
736  font-family: monospace;
737  font-size: 1em;
738}
739
740small {
741  font-size: 80%;
742}
743
744sub, sup {
745  font-size: 75%;
746  line-height: 0;
747  position: relative;
748  vertical-align: baseline;
749}
750
751sub {
752  bottom: -0.25em;
753}
754
755sup {
756  top: -0.5em;
757}
758
759table {
760  text-indent: 0;
761  border-color: inherit;
762  border-collapse: collapse;
763}
764
765button, input, optgroup, select, textarea {
766  font-family: inherit;
767  font-size: 100%;
768  font-weight: inherit;
769  line-height: inherit;
770  color: inherit;
771  margin: 0;
772  padding: 0;
773}
774
775button, select {
776  text-transform: none;
777}
778
779button, [type='button'], [type='reset'], [type='submit'] {
780  -webkit-appearance: button;
781  background-color: transparent;
782  background-image: none;
783}
784
785:-moz-focusring {
786  outline: auto;
787}
788
789:-moz-ui-invalid {
790  box-shadow: none;
791}
792
793progress {
794  vertical-align: baseline;
795}
796
797::-webkit-inner-spin-button, ::-webkit-outer-spin-button {
798  height: auto;
799}
800
801[type='search'] {
802  -webkit-appearance: textfield;
803  outline-offset: -2px;
804}
805
806::-webkit-search-decoration {
807  -webkit-appearance: none;
808}
809
810::-webkit-file-upload-button {
811  -webkit-appearance: button;
812  font: inherit;
813}
814
815summary {
816  display: list-item;
817}
818
819blockquote, dl, dd, h1, h2, h3, h4, h5, h6, hr, figure, p, pre {
820  margin: 0;
821}
822
823fieldset {
824  margin: 0;
825  padding: 0;
826}
827
828legend {
829  padding: 0;
830}
831
832ol, ul, menu {
833  list-style: none;
834  margin: 0;
835  padding: 0;
836}
837
838textarea {
839  resize: vertical;
840}
841
842input::placeholder, textarea::placeholder {
843  opacity: 1;
844  color: #00f;
845}
846
847button, [role="button"] {
848  cursor: pointer;
849}
850
851:disabled {
852  cursor: default;
853}
854
855img, svg, video, canvas, audio, iframe, embed, object {
856  display: block;
857  vertical-align: middle;
858}
859
860img, video {
861  max-width: 100%;
862  height: auto;
863}
864
865*, ::before, ::after {
866  --en-border-spacing-x: 0;
867  --en-border-spacing-y: 0;
868  --en-translate-x: 0;
869  --en-translate-y: 0;
870  --en-rotate: 0;
871  --en-skew-x: 0;
872  --en-skew-y: 0;
873  --en-scale-x: 1;
874  --en-scale-y: 1;
875  --en-pan-x: ;
876  --en-pan-y: ;
877  --en-pinch-zoom: ;
878  --en-scroll-snap-strictness: proximity;
879  --en-ordinal: ;
880  --en-slashed-zero: ;
881  --en-numeric-figure: ;
882  --en-numeric-spacing: ;
883  --en-numeric-fraction: ;
884  --en-ring-inset: ;
885  --en-ring-offset-width: 0px;
886  --en-ring-offset-color: #fff;
887  --en-ring-color: #f00;
888  --en-ring-offset-shadow: 0 0 #0000;
889  --en-ring-shadow: 0 0 #0000;
890  --en-shadow: 0 0 #0000;
891  --en-shadow-colored: 0 0 #0000;
892  --en-blur: ;
893  --en-brightness: ;
894  --en-contrast: ;
895  --en-grayscale: ;
896  --en-hue-rotate: ;
897  --en-invert: ;
898  --en-saturate: ;
899  --en-sepia: ;
900  --en-drop-shadow: ;
901  --en-backdrop-blur: ;
902  --en-backdrop-brightness: ;
903  --en-backdrop-contrast: ;
904  --en-backdrop-grayscale: ;
905  --en-backdrop-hue-rotate: ;
906  --en-backdrop-invert: ;
907  --en-backdrop-opacity: ;
908  --en-backdrop-saturate: ;
909  --en-backdrop-sepia: ;
910}
911
912::-webkit-backdrop {
913  --en-border-spacing-x: 0;
914  --en-border-spacing-y: 0;
915  --en-translate-x: 0;
916  --en-translate-y: 0;
917  --en-rotate: 0;
918  --en-skew-x: 0;
919  --en-skew-y: 0;
920  --en-scale-x: 1;
921  --en-scale-y: 1;
922  --en-pan-x: ;
923  --en-pan-y: ;
924  --en-pinch-zoom: ;
925  --en-scroll-snap-strictness: proximity;
926  --en-ordinal: ;
927  --en-slashed-zero: ;
928  --en-numeric-figure: ;
929  --en-numeric-spacing: ;
930  --en-numeric-fraction: ;
931  --en-ring-inset: ;
932  --en-ring-offset-width: 0px;
933  --en-ring-offset-color: #fff;
934  --en-ring-color: #f00;
935  --en-ring-offset-shadow: 0 0 #0000;
936  --en-ring-shadow: 0 0 #0000;
937  --en-shadow: 0 0 #0000;
938  --en-shadow-colored: 0 0 #0000;
939  --en-blur: ;
940  --en-brightness: ;
941  --en-contrast: ;
942  --en-grayscale: ;
943  --en-hue-rotate: ;
944  --en-invert: ;
945  --en-saturate: ;
946  --en-sepia: ;
947  --en-drop-shadow: ;
948  --en-backdrop-blur: ;
949  --en-backdrop-brightness: ;
950  --en-backdrop-contrast: ;
951  --en-backdrop-grayscale: ;
952  --en-backdrop-hue-rotate: ;
953  --en-backdrop-invert: ;
954  --en-backdrop-opacity: ;
955  --en-backdrop-saturate: ;
956  --en-backdrop-sepia: ;
957}
958
959::backdrop {
960  --en-border-spacing-x: 0;
961  --en-border-spacing-y: 0;
962  --en-translate-x: 0;
963  --en-translate-y: 0;
964  --en-rotate: 0;
965  --en-skew-x: 0;
966  --en-skew-y: 0;
967  --en-scale-x: 1;
968  --en-scale-y: 1;
969  --en-pan-x: ;
970  --en-pan-y: ;
971  --en-pinch-zoom: ;
972  --en-scroll-snap-strictness: proximity;
973  --en-ordinal: ;
974  --en-slashed-zero: ;
975  --en-numeric-figure: ;
976  --en-numeric-spacing: ;
977  --en-numeric-fraction: ;
978  --en-ring-inset: ;
979  --en-ring-offset-width: 0px;
980  --en-ring-offset-color: #fff;
981  --en-ring-color: #f00;
982  --en-ring-offset-shadow: 0 0 #0000;
983  --en-ring-shadow: 0 0 #0000;
984  --en-shadow: 0 0 #0000;
985  --en-shadow-colored: 0 0 #0000;
986  --en-blur: ;
987  --en-brightness: ;
988  --en-contrast: ;
989  --en-grayscale: ;
990  --en-hue-rotate: ;
991  --en-invert: ;
992  --en-saturate: ;
993  --en-sepia: ;
994  --en-drop-shadow: ;
995  --en-backdrop-blur: ;
996  --en-backdrop-brightness: ;
997  --en-backdrop-contrast: ;
998  --en-backdrop-grayscale: ;
999  --en-backdrop-hue-rotate: ;
1000  --en-backdrop-invert: ;
1001  --en-backdrop-opacity: ;
1002  --en-backdrop-saturate: ;
1003  --en-backdrop-sepia: ;
1004}
1005
1006.w-full {
1007  width: 100%;
1008}"#
1009            )
1010        );
1011    }
1012
1013    #[test]
1014    fn custom_preflight() {
1015        let preflight = Preflight::new_custom(
1016            "html, body {
1017  width: 100%;
1018  height: 100%;
1019  padding: 0;
1020  margin: 0;
1021  overflow-x: hidden;
1022}",
1023        );
1024        let config = Config {
1025            preflight,
1026            ..Default::default()
1027        };
1028
1029        let generated = generate(["w-full"], &config);
1030
1031        assert_eq!(
1032            generated,
1033            "html, body {
1034  width: 100%;
1035  height: 100%;
1036  padding: 0;
1037  margin: 0;
1038  overflow-x: hidden;
1039}
1040
1041.w-full {
1042  width: 100%;
1043}"
1044        );
1045    }
1046
1047    #[test]
1048    fn no_preflight() {
1049        let config = Config {
1050            preflight: Preflight::new_none(),
1051            ..Default::default()
1052        };
1053
1054        let generated = generate(["w-full"], &config);
1055
1056        assert_eq!(
1057            generated,
1058            ".w-full {
1059  width: 100%;
1060}"
1061        );
1062    }
1063}