在项目中引入 vanilla-extract 时,我发现了一个遗憾点。
Tailwind CSS v4 默认包含了名为 preflight 的 normalize 样式,因此无需额外配置即可规范化浏览器默认样式,但 vanilla-extract 并没有这种功能。
所以我决定自己动手。
参考 modern-normalize 编写
我参考了 Tailwind 的 preflight 所基于的 modern-normalize。
modern-normalize 是一个旨在最大限度减少浏览器间样式不一致,同时尽可能避免删除不必要样式的库。
利用 CSS Cascade Layers
normalize 样式的优先级应低于其他样式。使用 CSS Cascade Layers(以下简称 Layer)可以显式管理样式间的优先级,从而防止 normalize 样式意外覆盖其他样式。
我首先使用 vanilla-extract 的 globalLayer 定义了 Layer。globalLayer 接收 Layer 名称作为参数来创建 Layer,并返回创建的 Layer 引用值。
官方文档建议在 layers.css.ts 中 export 这个引用值,并在编写样式时使用引用值而不是 Layer 名称字符串。这是因为直接使用字符串形式的 Layer 名称,即使拼写错误也很难发现,而且在嵌套 Layer 等名称自动计算的情况下,使用引用值才能确保名称准确。
// layers.css.ts
import { globalLayer } from "@vanilla-extract/css";
export const normalize = globalLayer("normalize");编写 normalize.css
在 vanilla-extract 中为全局选择器应用样式时使用 globalStyle。第一个参数是选择器字符串,第二个参数是样式对象。
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
========
*/
/**
使用更好的盒模型 (opinionated)。
*/
globalStyle("*, ::before, ::after", {
"@layer": {
[normalize]: {
boxSizing: "border-box",
},
},
});
/**
1. 在所有浏览器中使用一致的默认字体
2. 在所有浏览器中设置正确的 line height
3. 防止 iOS 在方向转换后调整字体大小
4. 使用更易读的 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
========
*/
/**
在所有浏览器中移除 margin
*/
globalStyle("body", {
"@layer": {
[normalize]: {
margin: 0,
},
},
});
/*
Text-level semantics
====================
*/
/**
在 Chrome 和 Safari 中添加正确的字体粗细
*/
globalStyle("b, strong", {
"@layer": {
[normalize]: {
fontWeight: "bolder",
},
},
});
/**
1. 在所有浏览器中使用一致的默认字体
2. 修复所有浏览器中奇怪的 'em' 字体大小
*/
globalStyle("code, kbd, samp, pre", {
"@layer": {
[normalize]: {
fontFamily:
'ui-monospace, SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace',
fontSize: "1em",
},
},
});
/**
在所有浏览器中添加正确的字体大小
*/
globalStyle("small", {
"@layer": {
[normalize]: {
fontSize: "80%",
},
},
});
/**
防止 'sub' 和 'sup' 元素在所有浏览器中影响 line height
*/
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
============
*/
/**
修复 Chrome 和 Safari 中表格 border 颜色继承
*/
globalStyle("table", {
"@layer": {
[normalize]: {
borderColor: "currentcolor",
},
},
});
/*
Forms
=====
*/
/**
1. 在所有浏览器中更改字体样式
2. 在 Firefox 和 Safari 中移除 margin
*/
globalStyle("button, input, optgroup, select, textarea", {
"@layer": {
[normalize]: {
fontFamily: "inherit",
fontSize: "100%",
lineHeight: 1.15,
margin: 0,
},
},
});
/**
修复 iOS 和 Safari 中可点击类型的样式
*/
globalStyle('button, [type="button"], [type="reset"], [type="submit"]', {
"@layer": {
[normalize]: {
WebkitAppearance: "button",
},
},
});
/**
在所有浏览器中移除 padding,以免开发者将 'fieldset' 元素的值设为 0 时感到困惑
*/
globalStyle("legend", {
"@layer": {
[normalize]: {
padding: 0,
},
},
});
/**
在 Chrome 和 Firefox 中添加正确的垂直对齐
*/
globalStyle("progress", {
"@layer": {
[normalize]: {
verticalAlign: "baseline",
},
},
});
/**
修复 Safari 中增量/减量按钮的游标样式
*/
globalStyle("::-webkit-inner-spin-button, ::-webkit-outer-spin-button", {
"@layer": {
[normalize]: {
height: "auto",
},
},
});
/**
1. 修复 Chrome 和 Safari 中奇怪的外观
2. 修复 Safari 中的 outline 样式
*/
globalStyle('[type="search"]', {
"@layer": {
[normalize]: {
WebkitAppearance: "textfield",
outlineOffset: "-2px",
},
},
});
/**
移除 macOS 上 Chrome 和 Safari 中的内部 padding
*/
globalStyle("::-webkit-search-decoration", {
"@layer": {
[normalize]: {
WebkitAppearance: "none",
},
},
});
/**
1. 修复 iOS 和 Safari 中可点击类型的样式
2. 在 Safari 中将字体属性更改为 'inherit'
*/
globalStyle("::-webkit-file-upload-button", {
"@layer": {
[normalize]: {
WebkitAppearance: "button",
font: "inherit",
},
},
});
/*
Interactive
===========
*/
/**
在 Chrome 和 Safari 中添加正确的 display
*/
globalStyle("summary", {
"@layer": {
[normalize]: {
display: "list-item",
},
},
});我也上传到了 GitHub Gist! -> Modern CSS Normalize with Vanilla Extract & CSS Layers
global.css.ts
最后,必须最先导入 Layer 定义文件。由于 CSS Layer 的声明顺序直接影响优先级,如果不能保证顺序,normalize 样式可能无法按预期工作。
// global.css.ts
import "./layers.css"; // 必须最先导入
import "./normalize.css";现在只需在项目入口点导入 global.css 文件即可!
import "../global.css";参考