为什么先定义变量,再写样式
新手写样式常常是「遇到一处写一处颜色」:这里 #fafafa,
那里 #f9f9f9,半年后已经分不清哪个是正式的背景色。
变量做的事很简单 —— 给每个颜色一个名字,
让「用途」而不是「色号」出现在代码里。
好处是立刻能感受到的:想调整主色调,只改一行;想支持深色模式, 只写一套覆盖规则,而不必复制整份样式表。
第一步:给颜色起有意义的名字
名字应该描述用途,而不是外观。比如不要叫「浅灰」,而叫「次要文字」:
:root {
/* 背景与表面 */
--bg: #faf8f5; /* 页面底色 */
--surface: #ffffff; /* 卡片、面板 */
--border: #e7e1d8; /* 分隔线 */
/* 文字层级 */
--text: #1b1917; /* 正文 */
--text-soft: #55504a; /* 摘要、说明 */
--text-mute: #8b8379; /* 日期、标注 */
/* 强调色 */
--accent: #c2410c;
--accent-soft: #fdeee5;
}
第二步:用一套覆盖规则实现深色模式
深色模式不是把颜色反转,而是重新配一遍。同一组变量名, 换一组值,整个网站的外观就跟着变了:
:root[data-theme="dark"] {
--bg: #131211;
--surface: #1c1a18;
--border: #2e2a26;
--text: #eceae6;
--text-soft: #b5aea6;
--accent: #f97316;
}
/* 尊重系统设置:用户没手动选过时,跟随系统 */
@media (prefers-color-scheme: dark) {
:root:not([data-theme="light"]) {
/* 同样的一组深色值 */
}
}
color-scheme: dark,它能让滚动条、表单控件一起切换配色。
第三步:切换按钮其实只有几行 JS
var root = document.documentElement;
var saved = localStorage.getItem('site-theme');
if (saved) root.setAttribute('data-theme', saved);
// 点击时:算出下一个主题、应用、记住
document.querySelector('[data-theme-toggle]')
.addEventListener('click', function () {
var next = root.getAttribute('data-theme') === 'dark' ? 'light' : 'dark';
root.setAttribute('data-theme', next);
localStorage.setItem('site-theme', next);
});
这里有个容易忽略的坑:如果等页面渲染完再读 localStorage,
深色用户会先看到一闪而过的白屏。解决办法是把这几行放进
<head> 里同步执行,在首屏绘制之前就把属性写好。
顺手统一其他「感觉」
变量不只管颜色。间距、圆角、阴影同样值得收进来 ——
当所有卡片用的是同一个 --radius,
整站的气质自然就统一了:
:root {
--radius: 16px;
--radius-sm: 10px;
--shadow-sm: 0 1px 2px rgba(28, 25, 23, .06);
--shadow-md: 0 6px 16px -6px rgba(28, 25, 23, .14);
--ease: cubic-bezier(.22, .61, .36, 1);
/* 用一个变量统一控制所有过渡时长,方便整体调速 */
--duration: .28s;
}
.card { transition: transform var(--duration) var(--ease); }
最后一点心得
设计系统这个词听起来很重,落到个人项目上其实就是 把重复出现的东西起个名字。 一开始不必追求完备,用一处就抽一处; 抽到第十个变量的时候你会发现,改版这件事忽然变得很轻。
想看看实际效果?点一下右上角的太阳/月亮图标, 整站的每个颜色都会跟着一起呼吸。