写 CSS 中会碰到一个问题,有一些的 “魔法数值” 很烦,每次都要回忆或者查找上次写的数值是多少。比如主色调 #4285F4 写遍所有文件,某天假如要换个主色,得全局搜色值一个个改;按钮圆角一会儿 8px 一会儿 12px,卡片间距没个统一标准,后期维护很麻烦。
那就得使用原生 CSS 的:root 全局变量,以及Sass 预处理器,不用凭感觉写数值,改样式、写新布局的效率更高,代码风格也能统一。
原生CSS ::root 全局变量,零成本实现样式统一、
无需依赖任何第三方工具,原生 CSS 就自带全局变量功能,核心就是 :root 伪类
:root 其实就是 HTML 的根元素,优先级比直接写 html 选择器稍高一点,可以在这个伪类里定义整个项目的全局 CSS 变量,供所有页面元素使用。
定义规则很简单:— 变量名:变量值;,变量名建议用短横线分隔(比如 –color-primary)
使用规则更简单:var (– 变量名),var () 函数还能加第二个参数当默认值,比如 var (–color-primary, #333),就算变量没定义,也会显示默认的 #333,超实用。
定义规则很简单:— 变量名:变量值;,变量名建议用短横线分隔(比如 –color-primary)
使用规则更简单:var (– 变量名),var () 函数还能加第二个参数当默认值,比如 var (–color-primary, #333),就算变量没定义,也会显示默认的 #333,超实用。
一般会把项目里的主色、辅助色、字体大小、间距、圆角、阴影这些重复用到的样式,全抽成全局变量,单独写在 CSS 文件最前面,或者单独建一个 global.css 文件引入,基础模板参考如下:
/* 全局CSS变量定义 - :root */
:root {
/* 主色调/辅助色/中性色,按项目需求加 */
--color-primary: #4285F4; /* 主蓝 */
--color-secondary: #FFC107; /* 辅助黄 */
--color-success: #34A853; /* 成功绿 */
--color-danger: #EA4335; /* 危险红 */
--color-text-1: #333333; /* 主文本 */
--color-text-2: #666666; /* 次文本 */
--color-text-3: #999999; /* 淡文本 */
--color-bg: #F5F7FA; /* 页面背景 */
--color-card: #FFFFFF; /* 卡片背景 */
/* 字体大小,适配不同场景 */
--font-size-xl: 24px;
--font-size-lg: 18px;
--font-size-base: 16px;
--font-size-sm: 14px;
--font-size-xs: 12px;
/* 间距,统一用gap-前缀,按4px/8px递进,方便记忆 */
--gap-4: 4px;
--gap-8: 8px;
--gap-16: 16px;
--gap-24: 24px;
--gap-32: 32px;
/* 圆角,适配按钮/卡片/输入框 */
--radius-sm: 4px;
--radius-base: 8px;
--radius-lg: 12px;
--radius-circle: 50%;
/* 阴影,轻/中/重三种,满足大部分场景 */
--shadow-light: 0 2px 4px rgba(0,0,0,0.05);
--shadow-base: 0 4px 12px rgba(0,0,0,0.08);
--shadow-heavy: 0 8px 24px rgba(0,0,0,0.12);
}
/* 全局使用示例,随便写个按钮/卡片 */
.btn-primary {
padding: var(--gap-8) var(--gap-16);
background: var(--color-primary);
color: #fff;
border-radius: var(--radius-base);
box-shadow: var(--shadow-light);
}
.card {
padding: var(--gap-24);
background: var(--color-card);
border-radius: var(--radius-lg);
box-shadow: var(--shadow-base);
color: var(--color-text-1);
}
写完之后,整个项目的样式都能直接用这些变量,再也不用重复写具体的数值。
原生:root 全局变量,好在哪?
零成本、高回报,不用装任何插件、不用配置编译,直接写原生 CSS 就能用,主流浏览器(Chrome/Edge/Safari/ 火狐)全支持,核心好处就这 3 点:
- 统一维护,改需求超轻松:产品要改主色调?只需要在:root 里改一行 –color-primary 的数值,整个项目所有用到主色的地方全变,不用全局搜色值一个个改;
- 告别魔法数值,代码语义化拉满:看代码的时候,var (–gap-24) 一眼就知道是 24px 的间距,var (–color-success) 就知道是成功状态的绿色,不用猜这个数值是干嘛的,后期维护都能快速看懂;
- 灵活拓展,支持局部覆盖 + 响应式:全局变量不是死的,如果某个模块需要特殊的颜色 / 间距,直接在这个模块的父元素里重新定义同名变量就行,会自动覆盖全局的,不影响其他地方;还能结合媒体查询做响应式,比如移动端改字体大小和间距,超方便:
/* 局部覆盖:个人中心模块的主色和全局不一样,单独定义 */
.user-center {
--color-primary: #7B68EE;
}
/* 这里的按钮会用#7B68EE,而不是全局的#4285F4 */
.user-center .btn-primary {
background: var(--color-primary);
}
/* 响应式:移动端缩小字体和间距 */
@media (max-width: 768px) {
:root {
--font-size-xl: 20px;
--font-size-lg: 16px;
--gap-24: 16px;
--gap-32: 24px;
}
}
其实JS也 能直接操作 CSS 全局变量,比如做网站换肤功能,不用写一堆样式类,直接用 JS 修改:root 的变量就行,一行代码搞定:
// 切换深色模式,修改全局背景和文本色
document.documentElement.style.setProperty('--color-bg', '#1F1F1F');
document.documentElement.style.setProperty('--color-text-1', '#FFFFFF');
Sass 预处理器写全局样式:
只需要装个依赖(npm i sass -D),把 CSS 文件的后缀改成.scss。Sass 有两种语法,一种是带缩进的.sass,一种是和 CSS 语法一致的.scss,推荐用.scss,不用改书写习惯。
先搞懂 Sass 的核心:变量 + 嵌套 + 混合器 + 运算
Sass 的核心优势,就是让 CSS 拥有了编程的基本特性,比如变量、嵌套、函数、运算,其中最常用的就是这四个。
1. Sass 变量:$ 开头,更灵活的局部 / 全局变量
Sass 的变量用 **定义,和变量类似,但更灵活可以定义全局变量,也可以定义局部变量,作用域清晰,还能做数值运算(比如gap-16 * 2)。
可以把 Sass 的全局变量单独抽成一个_variables.scss文件(下划线表示局部文件,不会被单独编译),所有页面都引入这个文件,和 CSS 的:root 对应,后期维护只需要改这一个文件:
可以把 Sass 的全局变量单独抽成一个_variables.scss文件(下划线表示局部文件,不会被单独编译),所有页面都引入这个文件,和 CSS 的:root 对应,后期维护只需要改这一个文件:
// _variables.scss - Sass全局变量
// 颜色变量
$color-primary: #4285F4;
$color-secondary: #FFC107;
$color-text-1: #333;
$color-text-2: #666;
// 间距变量
$gap-4: 4px;
$gap-8: 8px;
$gap-16: 16px;
$gap-24: 24px;
// 字体大小
$font-size-base: 16px;
$font-size-lg: $font-size-base + 2px; // 直接运算,不用calc
// 圆角
$radius-base: 8px;
2. 选择器嵌套:告别重复书写,代码更简洁
这是我最爱的 Sass 功能,没有之一!原生 CSS 写嵌套选择器,比如.nav .nav-item .nav-link,要重复写父选择器,而 Sass 可以直接嵌套,& 表示父选择器,写 hover、active、伪元素超方便,代码层级清晰,少写一堆重复代码。
举个导航栏的例子,原生 CSS 要写好几行,Sass 嵌套直接搞定:
举个导航栏的例子,原生 CSS 要写好几行,Sass 嵌套直接搞定:
// SCSS嵌套写法
.nav {
width: 100%;
background: #fff;
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
// 嵌套子选择器,不用重复写.nav
.nav-item {
float: left;
margin-right: $gap-24; // 用Sass变量
// &表示父选择器.nav-item,写hover超方便
&:hover {
color: $color-primary;
}
// 嵌套孙选择器
.nav-link {
display: block;
padding: $gap-8 0;
font-size: $font-size-base;
}
}
// 伪元素也能嵌套
&::after {
content: "";
display: block;
clear: both;
}
}
// 编译后的原生CSS(自动生成,不用自己写)
.nav {
width: 100%;
background: #fff;
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
}
.nav .nav-item {
float: left;
margin-right: 24px;
}
.nav .nav-item:hover {
color: #4285F4;
}
.nav .nav-item .nav-link {
display: block;
padding: 8px 0;
font-size: 16px;
}
.nav::after {
content: "";
display: block;
clear: both;
}
注意:不能过度嵌套!最多嵌套 3 层,不然编译后的 CSS 选择器优先级太高,后期想覆盖样式会很麻烦,还会增加文件体积(因为嵌套后编译出的css文件中的选择器太长)。
3. 混合器 @mixin:提取重复样式,支持传参,灵活复用
开发中总有很多重复的样式,比如 flex 水平垂直居中、毛玻璃效果、渐变文字,原生 CSS 要写一遍又一遍,Sass 的 **@mixin能把这些重复样式抽成一个 “模板”,用@include引入,还能传参,不同场景传不同的值。
可以把常用的混合器单独抽成_mixins.scss** 文件,和变量文件一起引入,用的时候直接 @include,一行代码搞定:
可以把常用的混合器单独抽成_mixins.scss** 文件,和变量文件一起引入,用的时候直接 @include,一行代码搞定:
// _mixins.scss - 常用混合器
// flex水平垂直居中(无参数,基础复用)
@mixin flex-center {
display: flex;
justify-content: center;
align-items: center;
}
// 毛玻璃效果(带参数,默认值8px,可自定义)
@mixin glass($blur: 8px) {
background: rgba(255,255,255,0.7);
backdrop-filter: blur($blur);
-webkit-backdrop-filter: blur($blur);
border: 1px solid rgba(255,255,255,0.9);
}
// 渐变文字(带两个颜色参数,必传)
@mixin gradient-text($color1, $color2) {
background-image: linear-gradient(135deg, $color1, $color2);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
}
// 引入混合器使用
.card {
@include flex-center; // 用无参数混合器
width: 300px;
height: 200px;
@include glass(10px); // 传参,模糊值10px
}
.title {
font-size: 24px;
font-weight: 700;
@include gradient-text($color-primary, $color-secondary); // 传颜色变量
}
混合器是 Sass 最实用的功能之一,能少写超多重复代码,开发效率直接拉满。
4. 数值运算:直接加减乘除,告别 calc ()
原生 CSS 做数值运算要写 calc (),还得注意空格,比如 calc (100% – 20px),而 Sass 可以直接做加减乘除,不用写 calc (),数值和单位一起写就行,还能结合变量运算:
// Sass运算
$width: 300px;
$gap: 20px;
.box1 {
width: $width - 50px; // 250px
height: $width / 2; // 150px
}
// 多列布局,自动计算宽度,不用手动算
.box2 {
width: (100% - $gap * 2) / 3; // 平均分成3列,间距20px
}
// 编译后的CSS
.box1 {
width: 250px;
height: 150px;
}
.box2 {
width: calc(100% - 40px) / 3;
}
还有两个小功能:@extend 继承 + @import 引入
这两个功能用的频率也很高,简单提一下,都是为了减少代码冗余:
- @extend 继承:适合复用无参数的纯样式,比如不同的按钮都有相同的基础样式,只需要继承基础样式,再写各自的特殊样式就行,比混合器更省代码:
// 基础按钮样式
.btn {
padding: $gap-8 $gap-16;
border-radius: $radius-base;
cursor: pointer;
border: none;
font-size: $font-size-base;
}
// 主按钮继承基础样式,加特殊样式
.btn-primary {
@extend .btn;
background: $color-primary;
color: #fff;
}
// 次要按钮继承基础样式
.btn-secondary {
@extend .btn;
background: #eee;
color: $color-text-1;
}
- @import 引入:Sass 的 @import 和原生 CSS 的不一样,它是编译时合并文件,不会发起网络请求,我们可以把变量、混合器、公共样式分成多个文件,用 @import 引入到主文件,代码结构更清晰:
// main.scss - 主样式文件,引入所有公共文件
@import "./variables";
@import "./mixins";
@import "./global";
// 然后写页面样式
@import "./pages/index";
@import "./pages/detail";
:root + Sass,1+1>2
讲完了原生:root 和 Sass,最香的用法来了 —— 把这俩结合起来用,既能发挥 Sass 的编程优势,又能保留 CSS 全局变量的原生特性,实现 1+1>2 的效果。
为什么要结合?各自的短板互补
单独用:root,虽然原生、能被 JS 操作,但缺少嵌套、运算、混合器这些功能,写起来还是麻烦;
单独用 Sass,虽然写起来爽,但 Sass 变量编译后就会消失,变成具体的数值,JS 无法直接操作,想做动态样式(比如换肤)就很麻烦;
而把它们结合起来,用Sass 变量定义:root 里的 CSS 全局变量,就能完美互补:既能用 Sass 的变量管理、运算、嵌套写样式,又能让 CSS 变量在页面中生效,支持 JS 操作和响应式,完美!
单独用 Sass,虽然写起来爽,但 Sass 变量编译后就会消失,变成具体的数值,JS 无法直接操作,想做动态样式(比如换肤)就很麻烦;
而把它们结合起来,用Sass 变量定义:root 里的 CSS 全局变量,就能完美互补:既能用 Sass 的变量管理、运算、嵌套写样式,又能让 CSS 变量在页面中生效,支持 JS 操作和响应式,完美!
怎么结合?核心就一个:Sass 插值 #{}
结合的方法是在 Sass 文件里定义:root,用Sass 的插值 #{} 把 Sass 变量注入到 CSS 全局变量中,一行代码搞定,这是标准写法:
// _variables.scss - 先定义Sass变量
$color-primary: #4285F4;
$color-secondary: #FFC107;
$color-bg: #F5F7FA;
$gap-16: 16px;
$font-size-base: 16px;
// global.scss - 用Sass变量定义CSS全局变量
@import "./variables";
:root {
// 用#{}插值,把Sass变量注入到CSS变量中
--color-primary: #{$color-primary};
--color-secondary: #{$color-secondary};
--color-bg: #{$color-bg};
--gap-16: #{$gap-16};
--font-size-base: #{$font-size-base};
// 其他变量同理
}
这样一来在 Sass 里写样式时,可以直接用 Sass 变量($color-primary),也可以用 CSS 全局变量(var (–color-primary)),后期只需要改 Sass 的_variables.scss 文件,CSS 全局变量也会跟着变,JS 还能直接操作 CSS 全局变量做动态样式,完美解决了各自的短板。
总结一下,用这俩到底好在哪?
1. 告别魔法数值,代码可维护性拉满
这是最核心的好处,所有的颜色、间距、字体大小都抽成变量,统一维护在一个文件里,不管是自己后期改需求,还是团队协作交接代码,都不用再猜数值的含义,改样式只需要改一个变量,全项目生效,再也不用体验全局搜色值、改到崩溃的感觉。
2. 减少代码冗余,开发效率翻倍
Sass 的嵌套、混合器、继承,能少写超多重复代码,比如 flex 居中不用每次写三行,@include flex-center 就行;按钮不用每次写基础样式,@extend .btn 就行;嵌套选择器不用重复写父选择器,代码层级清晰,写样式的速度直接翻倍。
3. 样式统一规范,团队协作更顺畅
做团队项目时,只需要定好一份 Sass 全局变量规范,所有人都按这个规范写样式,不会出现有人用 8px 圆角,有人用 10px 圆角,有人用 #4285F4 当主色,有人用 #409EFF 当主色的情况,代码风格高度统一,后期交接、联调都超轻松。
4. 适配性强,支持动态样式和响应式
结合后的方案,既支持 Sass 的灵活写法,又保留了 CSS 全局变量的原生特性:可以结合媒体查询做响应式,修改全局变量适配不同屏幕;可以用 JS 直接操作 CSS 全局变量,做网站换肤、动态修改样式等功能,不用写一堆样式类,一行代码搞定。
5. 上手成本低,零配置,新手也能会
原生:root 不用任何工具,直接写就行;Sass 现在的脚手架都自带编译,只需要装个依赖,改个文件后缀,核心用法就几个,新手半天就能学会,不用学复杂的语法,这几个常用功能就够解决 80% 的开发痛点。
6. 无侵入性,兼容所有项目
不管是小的静态页面、个人博客,还是大的 Vue/React 项目,都能用上这个方案,无侵入性,不用改项目的原有结构,直接引入就能用,适配所有开发场景。
注意事项
- Sass 嵌套别超过 3 层,不然编译后的 CSS 选择器优先级太高,后期想覆盖样式会很麻烦,还会增加文件体积;
- 变量命名要有规范,不管是 Sass 变量还是 CSS 变量,都要统一前缀,比如颜色用 color-,间距用 gap-,字体用 font-,圆角用 radius-,避免重名;
- 混合器和继承分清使用场景:有参数、需要灵活调整的重复样式用 @mixin;无参数、纯样式复用的用 @extend,后者更省代码;
- Sass 文件命名加下划线,表示局部文件,避免被单独编译,主文件不用加下划线;
- JS 操作 CSS 变量时,注意命名格式:CSS 变量是 –color-primary,JS 里用 setProperty 时,直接传字符串 ‘–color-primary’ 就行,不用转驼峰;
- 不要过度使用 Sass 的高级功能,比如函数、循环,日常开发用变量、嵌套、混合器、运算这四个就够了,过度使用会让代码变得复杂,反而不利于维护。













