I found one disappointing thing while introducing vanilla-extract to my project.
Tailwind CSS v4 includes a normalize style called preflight by default, so browser default styles are normalized without any additional setup, but vanilla-extract doesn't have such a feature.
So I decided to make it myself.
Created by referring to modern-normalize
I referred to modern-normalize, which Tailwind's preflight is based on.
modern-normalize is a library designed to minimize style inconsistencies between browsers while refraining from removing unnecessary styles as much as possible.
Utilizing CSS Cascade Layers
The normalize style should have a lower priority than other styles. Using CSS Cascade Layers (hereafter layers) allows you to explicitly manage priority between styles, preventing normalize styles from unintentionally overwriting other styles.
I first defined the layer with vanilla-extract's globalLayer. globalLayer takes a layer name as an argument, creates the layer, and returns the created layer reference value.
The official documentation recommends exporting this reference value from layers.css.ts and using the reference value instead of the layer name string when writing styles. This is because if you use the layer name as a string directly, it's hard to notice even if there's a typo, and the reference value must be used to guarantee the correct name when the name is automatically calculated, such as nested layers.
// layers.css.ts
import { globalLayer } from "@vanilla-extract/css";
export const normalize = globalLayer("normalize");Writing normalize.css
When applying styles to global selectors in vanilla-extract, use globalStyle. It takes a selector string as the first argument and a style object as the second argument.
import { globalStyle } from "@vanilla-extract/css";
import { normalize } from "./layers.css.ts";
/**
* CSS Normalize based on modern-normalize v3.0.1
* https://github.com/sindresorhus/modern-normalize
* MIT License
*/
/*
Document
========
*/
/**
Use a better box model (opinionated).
*/
globalStyle("*, ::before, ::after", {
"@layer": {
[normalize]: {
boxSizing: "border-box",
},
},
});
/**
1. Use a consistent default font in all browsers.
2. Correct the line height in all browsers.
3. Prevent adjustments of font size after orientation changes in iOS.
4. Use a more readable tab size (opinionated).
*/
globalStyle("html", {
"@layer": {
[normalize]: {
fontFamily:
'system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"',
lineHeight: 1.15,
WebkitTextSizeAdjust: "100%",
tabSize: 4,
},
},
});
/*
Sections
========
*/
/**
Remove the margin in all browsers.
*/
globalStyle("body", {
"@layer": {
[normalize]: {
margin: 0,
},
},
});
/*
Text-level semantics
====================
*/
/**
Add the correct font weight in Chrome and Safari.
*/
globalStyle("b, strong", {
"@layer": {
[normalize]: {
fontWeight: "bolder",
},
},
});
/**
1. Use a consistent default font in all browsers.
2. Correct the odd 'em' font sizing in all browsers.
*/
globalStyle("code, kbd, samp, pre", {
"@layer": {
[normalize]: {
fontFamily:
'ui-monospace, SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace',
fontSize: "1em",
},
},
});
/**
Add the correct font size in all browsers.
*/
globalStyle("small", {
"@layer": {
[normalize]: {
fontSize: "80%",
},
},
});
/**
Prevent 'sub' and 'sup' elements from affecting the line height in all browsers.
*/
globalStyle("sub, sup", {
"@layer": {
[normalize]: {
fontSize: "75%",
lineHeight: 0,
position: "relative",
verticalAlign: "baseline",
},
},
});
globalStyle("sub", {
"@layer": {
[normalize]: {
bottom: "-0.25em",
},
},
});
globalStyle("sup", {
"@layer": {
[normalize]: {
top: "-0.5em",
},
},
});
/*
Tabular data
============
*/
/**
Correct table border color inheritance in Chrome and Safari.
*/
globalStyle("table", {
"@layer": {
[normalize]: {
borderColor: "currentcolor",
},
},
});
/*
Forms
=====
*/
/**
1. Change the font styles in all browsers.
2. Remove the margin in Firefox and Safari.
*/
globalStyle("button, input, optgroup, select, textarea", {
"@layer": {
[normalize]: {
fontFamily: "inherit",
fontSize: "100%",
lineHeight: 1.15,
margin: 0,
},
},
});
/**
Correct the inability to style clickable types in iOS and Safari.
*/
globalStyle('button, [type="button"], [type="reset"], [type="submit"]', {
"@layer": {
[normalize]: {
WebkitAppearance: "button",
},
},
});
/**
Remove the padding so that developers are not caught out when they zero out 'fieldset' elements in all browsers.
*/
globalStyle("legend", {
"@layer": {
[normalize]: {
padding: 0,
},
},
});
/**
Add the correct vertical alignment in Chrome and Firefox.
*/
globalStyle("progress", {
"@layer": {
[normalize]: {
verticalAlign: "baseline",
},
},
});
/**
Correct the cursor style of increment and decrement buttons in Safari.
*/
globalStyle("::-webkit-inner-spin-button, ::-webkit-outer-spin-button", {
"@layer": {
[normalize]: {
height: "auto",
},
},
});
/**
1. Correct the odd appearance in Chrome and Safari.
2. Correct the outline style in Safari.
*/
globalStyle('[type="search"]', {
"@layer": {
[normalize]: {
WebkitAppearance: "textfield",
outlineOffset: "-2px",
},
},
});
/**
Remove the inner padding in Chrome and Safari on macOS.
*/
globalStyle("::-webkit-search-decoration", {
"@layer": {
[normalize]: {
WebkitAppearance: "none",
},
},
});
/**
1. Correct the inability to style clickable types in iOS and Safari.
2. Change font properties to 'inherit' in Safari.
*/
globalStyle("::-webkit-file-upload-button", {
"@layer": {
[normalize]: {
WebkitAppearance: "button",
font: "inherit",
},
},
});
/*
Interactive
===========
*/
/**
Add the correct display in Chrome and Safari.
*/
globalStyle("summary", {
"@layer": {
[normalize]: {
display: "list-item",
},
},
});I also uploaded it to GitHub Gist! -> Modern CSS Normalize with Vanilla Extract & CSS Layers
global.css.ts
Finally, the layer definition file must be imported first. Since the declaration order of CSS layers directly affects priority, if the order is not guaranteed, the normalize style may not work as intended.
// global.css.ts
import "./layers.css"; // Must be first
import "./normalize.css";Now you just need to import the global.css file at the project entry point!
import "../global.css";References