Appearance
现代CSS语法
元信息
- 目标:把 CSS 当一门"可编程的样式语言"——掌握原生自定义属性(变量)与 calc/clamp/color-mix/light-dark 等函数,实现主题切换与派生配色,无需任何构建工具
- 关键概念:自定义属性、var()、calc、clamp、color-mix、主题变量
- 关联阶段:cp1
- 常见误区:以为 CSS 变量必须靠 SCSS 等构建工具(原生
--x/var()运行时可用且可继承);以为深浅主题切换要写两套样式或改 HTML(变量覆盖一处、全站跟随)
CSS 基础一篇里提到,早期 CSS 缺乏程序设计特性(变量、函数、控制结构),预处理器正是为弥补这一短板而生。而最近几年的 CSS 标准已经原生补齐了这些能力——本篇介绍现代 CSS 的可编程特性,它们无需任何构建工具,写进样式表就能在当代浏览器中运行。
自定义属性:CSS 的变量
声明与使用
自定义属性(custom property)以 -- 开头,用 var() 函数取用:
css
:root {
--brand-color: #1a73e8;
--text-color: #222;
--spacing: 8px;
}
body {
color: var(--text-color);
}
a {
color: var(--brand-color);
}
.card {
padding: calc(var(--spacing) * 2);
}:root 即文档根元素,在这里声明的变量全局可用,相当于整站的设计常量——把主题色、间距、圆角集中在一处,改一处即全站生效。
变量是"活的":继承与作用域
自定义属性沿 DOM 树继承,且可以在任何元素上重新声明——于是同一个变量在不同子树里可以有不同的值,这就是主题变量的原理:
css
:root {
--bg: #ffffff;
--text: #222222;
}
/* 深色主题:只覆盖变量,不写任何新规则 */
[data-theme="dark"] {
--bg: #1a1a2e;
--text: #eaeaea;
}
body {
background: var(--bg);
color: var(--text);
}切主题 = 切换一个属性值,所有样式自动跟随。第 3 周示例"一曲新词酒一杯"的主题切换行为,最现代的实现方式正是这一招——也再次印证了"样式与结构分离":HTML 一个 data-theme 属性都不用改。
var() 还支持缺省值,变量未定义时不至于失效:
css
.button {
color: var(--btn-text, white); /* 未定义 --btn-text 时用 white */
}组件级主题
把变量声明收窄到某个类上,就得到"组件级主题"——同一套组件,不同容器里呈现不同外观:
css
.card {
--card-bg: #f6f8fa;
--card-border: #d0d7de;
background: var(--card-bg);
border: 1px solid var(--card-border);
}
.card--warning {
--card-bg: #fff8c6;
--card-border: #d4a72c;
}这套"变量 + 覆盖"的模式,就是 design token 思想(第 14 周)的最小雏形。
原生函数:会计算的样式
现代 CSS 内置了一批函数,让样式值可以算出来而不是写死:
数学计算:calc / min / max / clamp
css
.content {
/* 屏幕宽度减去两侧留白 */
width: calc(100% - 2rem);
}
.title {
/* 不小于 16px,不大于 32px,中间随视口流动 */
font-size: clamp(16px, 2vw + 8px, 32px);
}
.sidebar {
/* 取理想宽度和可用宽度中较小者,永不溢出 */
width: min(300px, 100%);
}clamp(最小, 理想, 最大) 一个函数就实现了流动排版——过去要靠媒体查询写好几段。
颜色函数:相对颜色与混色
css
:root {
--brand: #1a73e8;
}
.button {
background: var(--brand);
/* 悬停时同色变深 20%:从品牌色派生,不必另挑一个色值 */
}
.button:hover {
background: color-mix(in srgb, var(--brand) 80%, black);
}
.badge {
/* 品牌色的半透明版 */
color: var(--brand);
background: color-mix(in srgb, var(--brand) 12%, transparent);
}颜色系统从"一堆孤立色值"变成"一个品牌色派生全家"——配色的可维护性质变。此外 light-dark() 函数配合 color-scheme 属性,一行声明同时给出浅色/深色两个值:
css
:root {
color-scheme: light dark;
--text: light-dark(#222, #eaeaea);
}与 SCSS 的对照
| 能力 | 原生 CSS | SCSS |
|---|---|---|
| 变量 | --x + var(x),运行时、可继承 | $x,编译时、不可变 |
| 函数 | calc/min/max/clamp/color-mix 等 | 自定义 @function |
| 主题切换 | 变量覆盖,零成本 | 需输出多套类 |
| 依赖 | 无,浏览器直接运行 | 需构建工具转译 |
原生变量的"运行时 + 继承"特性是 SCSS 编译期变量做不到的(SCSS 变量编译后就不存在了),这是"新项目优先原生"的根本原因。SCSS 仍有价值的部分是其嵌套语法和工程化生态,见SCSS。