前端(哥)和 Sass(妹)的爱恨情仇:从入门到躺赢

105 阅读15分钟

前言:Sass 这小妖精,凭啥让前端 er 魂牵梦绕?

在前端开发的花花世界里,CSS 预处理器界的顶流 ——Sass(Syntactically Awesome Stylesheets)那可是横空出世的狠角色!它直接把写样式这事儿从 "搬砖" 升级成 "开挖掘机",效率和可维护性直接拉满到外太空!作为一个对网页设计爱得死去活来的开发者,我太懂掌握 Sass 有多香了 —— 简直是给前端人的超能力 Buff!所以我揣着激动的心、颤抖的手,踏上了这场和 Sass 妹妹的恋爱修行,顺便把笔记记下来给兄弟们抄作业~

一、拿捏 Sass 的正确姿势:从入门到装 X

1.1 Sass 的基本语法:骚操作集中营

A、变量:给 CSS 装个 "记忆大脑"

这波操作直接让 CSS 原地封神 —— 终于能像 JS 大佬那样玩变量了!用$符号给值办个 "身份证",想在哪用就在哪用,改一次全文档生效,简直不要太爽!

\$color: #f00; // 给红色办个"户口本"

.container {

  border: 1px solid \$color; // 叫它一声就来

  background: \$color; // 再叫一声还来

}

编译后直接原地变身:

.container {

  border: 1px solid #f00;

  background: #f00;

}

B、嵌套:像剥洋葱一样写样式,爽!

这玩意儿简单到离谱,地球人都知道!就跟 HTML 的父子关系一模一样,一层套一层,再也不用写一堆重复的选择器,简直是强迫症的福音!(具体用法就不啰嗦了,懂的都懂,不懂的抄作业也能会)

C、文件引入:模块化管理,告别 "一锅乱炖"

文件名前面加个_(比如_variables.scss),这文件就成了 "幕后英雄"—— 不单独编译,专给别人当靠山!新版本推荐用@use替代老掉牙的@import(别问为啥,问就是怕全局污染搞事情),还能起个别名,喊起来更顺口~

@use 'variables'; // 召唤变量文件,后缀名可省,嚣张!

body { color: variables.\$primary-color; } // 用命名空间喊它,免得认错人

\$color: red;

@mixin box { padding: 10px; }

// main.scss

@use 'theme' as t; // 给theme起个小名叫t,亲昵\~

.box {

  color: t.\$color; // 喊小名更方便

  @include t.box; // 混合宏也这么喊

}

D、混入(Mixin):CSS 界的 "万能模板"

这东西就是样式界的 "预制菜"—— 提前做好一段 CSS,要用的时候微波炉加热(@include)一下就成!还能传参数,比外卖还贴心!

// 定义一个"居中神器",默认横排,想竖排也行

@mixin flex-center(\$direction: row) {

  display: flex;

  flex-direction: \$direction;

  justify-content: center;

  align-items: center;

}

.container { @include flex-center(column); } // 喊它一声,竖着居中安排上!

// 重点来了!@content这货是"占位符刺客"——调用时塞点代码,它直接原地替换!

// 定义一个响应式"变形金刚"

@mixin responsive(\$breakpoint) {

  @media (\$breakpoint) {

    @content; // 这里会被替换成你传的代码,超灵活!

  }

}

// 调用它,传点样式让它变身

@include responsive(min-width: 768px) {

  .box { width: 50%; float: left; }

  .title { font-size: 20px; }

}

// 编译后直接成了媒体查询大佬:

@media (min-width: 768px) {

  .box { width: 50%; float: left; }

  .title { font-size: 20px; }

}

// 进阶玩法:带条件的"主题切换器"

@mixin theme(\$mode: light) {

  .theme-#{\$mode} {

    @if \$mode == light {

      background: white; color: black; // 白天模式

    } @else {

      background: black; color: white; // 黑夜模式

    }

    @content; // 留个口子让你塞自定义样式,够意思吧?

  }

}

// 调用它,加点私货

@include theme(dark) {

  .btn { border-color: #333; }

  .link { text-decoration: underline; }

}

// 编译后直接生成带私货的暗黑主题:

.theme-dark {

  background: black; color: white;

  .btn { border-color: #333; }

  .link { text-decoration: underline; }

}

E、继承:CSS 界的 "抄作业大师"

这玩意儿跟 JS 的继承一个德性 ——B 继承 A,A 有的 B 全有,还能加自己的新东西!用@extend一声令下,直接把别人的样式扒过来,爽到飞起!

.btn { padding: 8px 16px; } // 基础按钮样式

.btn-primary {

  @extend .btn; // 抄作业!把.btn的样式全拿过来

  background: blue; // 再加个自己的特色

}

// 编译后直接合体:

.btn, .btn-primary { padding: 8px 16px; }

.btn-primary { background: blue; }

F、运算:CSS 也能当计算器,秀!

Sass 这货直接给 CSS 装了个 "计算器",加减乘除取模样样行,数字、颜色、字符串都能算,单位还能自动转换 —— 数学不好的同学也能轻松拿捏(优先级跟数学一样,别慌)!

// 加法 (+):两个数贴贴

\$width: 200px;

\$margin: 10px;

.element { width: \$width + \$margin; } // 结果:210px

// 减法 (-):数字吵架

\$base-font-size: 16px;

\$small-font-size: 14px;

.small-text { font-size: \$base-font-size - \$small-font-size; } // 结果:2px

// 乘法 (\*):数字翻倍玩

\$base-spacing: 8px;

.double-spacing { margin-bottom: \$base-spacing \* 2; } // 结果:16px

// 除法 (/):数字分家

\$base-font-size: 16px;

\$scale-factor: 1.5;

.large-text { font-size: \$base-font-size / \$scale-factor; } // 结果:10.6666666667px

// 取模 (%):数字找余数

\$columns: 12;

\$column-width: 80px;

.grid-item { width: (\$column-width \* 4) % \$columns; } // 结果:4px

// 混合运算:先乘后除,规矩得很

\$base-font-size: 16px;

.text { font-size: (\$base-font-size \* 0.5) / 2; } // 结果:4px

// 四舍五入:强迫症福音

\$base-font-size: 16px;

.rounded-text { font-size: round(\$base-font-size \* 1.5); } // 结果:24px

// 单位魔法:给数字加单位

\$width: 100;

\$height: 200px;

.box { width: \$width + unit(\$height); } // 结果:100px

1.2 Sass 的数据类型:装 X 必备知识点

Sass 的 "数据家族" 人丁兴旺,个个都是狠角色,掌握它们,你就是 CSS 界的 "数据大佬"!

  • 数值类型:1、2、13、10px(带不带单位都嚣张)

  • 字符串类型:有引号的 "foo"、'bar',没引号的 baz(放荡不羁爱自由)

  • 布尔类型:true、false(非黑即白,从不摸鱼)

  • 空值:null(存在感为 0,但偶尔很有用)

  • 数组(list):用空格或逗号分隔,比如 1px 10px 15px 5px、1px,10px,15px,5px(排队整齐)

  • 字典(map):小括号包着键值对,(key1:value1, key2:value2)(查字典专用)

  • 颜色类型:blue、#04a012、rgba (0,0,12,0.5)(五彩斑斓的黑都能整)

1.2.1 数值类型:数字界的 "多面手"

整数、小数、带单位的,啥样都有,运算起来贼溜!

\$my-age: 19; // 整数,年轻就是资本

\$your-age: 19.5; // 小数,半岁也算数

\$height: 120px; // 带单位,身高必须精准

1.2.2 字符串类型:文字界的 "戏精"

带不带引号都能活,还能拼接,玩得花!

\$name: 'Tom Bob'; // 带单引号,害羞型

\$container: "top bottom"; // 带双引号,张扬型

\$what: heart; // 没引号,放飞自我型

div {

  background-image: url(\$what + ".png"); // 拼接一下,变成heart.png

}

// 最终结果:

div { background-image: url(heart.png); }

1.2.3 布尔类型:是非分明的 "杠精"

就俩值:true 和 false,还会用 and、or、not 吵架,逻辑清晰得很!

\$a: 1>0 and 0>5; // false1>0是对的,但0>5是错的,合起来错)

\$b: "a" == a; // true(字符串a和无引号a是一家)

\$c: false; // 就是错

\$d: not \$c; // true(反过来就对了)

1.2.4 null 类型:透明的 "隐身人"

存在感为 0,但有时候能帮大忙(比如控制样式是否生成)。

\$a: null; // 我在,但又没完全在

1.2.5 list 类型:排队整齐的 "小方队"

元素排好队,用空格或逗号分隔,拿来循环超方便!

\$p: 1px 1px 1px 1px; // 四个1px排好队

.div {

  padding: \$p; // 直接用,相当于padding:1px 1px 1px 1px

}

1.2.6 字典类型:查东西超快的 "新华字典"

键值对打包,用 map 函数查起来比翻书还快!

\$map: (name:"张三", age:99, sex:"男"); // 张三的信息打包

\$primary: map-get(\$colors, "name"); // 查name,直接跳出"张三"

// 新版用法,更嚣张

@use "sass:map";

\$font-weights: ("regular": 400, "medium": 500, "bold": 700);

@debug map.get(\$font-weights, "medium"); // 500(一下子就查到)

@debug map.get(\$font-weights, "extra-bold"); // null(查无此货)

1.2.7 颜色类型:色彩界的 "调色大师"

跟 CSS 颜色一样,但 Sass 能对它们动手动脚(调整亮度、饱和度啥的),十六进制、颜色名、rgb/rgba 都能整!

1.3 函数:Sass 的 "超能力外挂"

这玩意儿简直是 Sass 的 "王炸"!配合变量、数组、字典、循环一起玩,能上天!注意:函数也能当值用,高级玩法直接拉满(虽然不能直接写,但能通过内置函数调用,懂的都懂)。

不多逼逼,直接上才艺(把它当 JS 看就行,没难度)!

// 先引入内置模块,跟JS的工具库一个意思

@use "sass:list";

@use "sass:meta";

@use "sass:string";

/// 自定义函数:把列表中符合条件的元素踢出去

@function remove-where(\$list, \$condition) {

  \$new-list: (); // 空列表,准备装新东西

  \$separator: list.separator(\$list); // 记录分隔符类型

  // 循环列表,逐个检查

  @each \$element in \$list {

    @if not meta.call(\$condition, \$element) { // 不符合条件的留下

      \$new-list: list.append(\$new-list, \$element, \$separator: \$separator);

    }

  }

  @return \$new-list; // 返回新列表

}

\$fonts: Tahoma, Geneva, "Helvetica Neue", Helvetica, Arial, sans-serif;

.content {

  @function contains-helvetica(\$string) { // 内部小函数:检查是否含"Helvetica"

    @return string.index(\$string, "Helvetica");

  }

  font-family: remove-where(\$fonts, meta.get-function("contains-helvetica")); // 踢掉含"Helvetica"的字体

}

1.3.1 自定义函数:自己造轮子,想咋玩咋玩

自定义函数就是自己写的 "专属工具",有函数名、@function声明和函数体,跟 JS 函数一模一样,想实现啥功能自己说了算!

// 自定义函数:根据基础色生成随机"亲戚色"

@function random-color(\$base-color) {

  // 从基础色里扒出色相、饱和度、亮度

  \$hue: hue(\$base-color);

  \$saturation: saturation(\$base-color);

  \$lightness: lightness(\$base-color);

  

  // 随机色相偏移(-60到+60之间),既相关又不同

  \$random-hue-offset: random(120) - 60; // 生成-60到60的随机数

  \$new-hue: \$hue + \$random-hue-offset;

  

  // 确保色相在0-360范围内(循环一下,不越界)

&#x20; @if \$new-hue < 0 {

&#x20;   \$new-hue: \$new-hue + 360;

&#x20; } @else if \$new-hue > 360 {

&#x20;   \$new-hue: \$new-hue - 360;

&#x20; }

&#x20;&#x20;

&#x20; // 随机调整饱和度(±10%),不能太离谱

&#x20; \$random-saturation: \$saturation + (random(20) - 10);

&#x20; \$new-saturation: clamp(0%, \$random-saturation, 100%); // 锁死在0-100%

&#x20;&#x20;

&#x20; // 随机调整亮度(±10%),同样不能太疯

&#x20; \$random-lightness: \$lightness + (random(20) - 10);

&#x20; \$new-lightness: clamp(0%, \$random-lightness, 100%); // 锁死范围

&#x20;&#x20;

&#x20; // 返回新颜色,搞定!

&#x20; @return hsl(\$new-hue, \$new-saturation, \$new-lightness);

}

// 实战一下

\$base: #4285f4; // 基础蓝色

// 生成5个"亲戚色"

.color-1 { background: random-color(\$base); }

.color-2 { background: random-color(\$base); }

.color-3 { background: random-color(\$base); }

.color-4 { background: random-color(\$base); }

.color-5 { background: random-color(\$base); }

1.3.2 SASS 内置函数:官方给的 "作弊神器"

Sass 自带一堆函数,处理字符串、数字、数组、字典、颜色啥的,比自己写的好用一万倍,直接拿来主义!

1.3.2.1 字符串内置函数:文字处理小能手

这些函数能给字符串加引号、找子串、插入文字... 比 Word 的查找替换还强!(示例用@debug打印结果,方便调试,不是生成 CSS 哦)

函数老版函数名返回值功能描述
string.quote($string)quote($string)string给字符串加引号,带引号的不变
string.index($string, $substring)str-index($string, $substring)number找子串位置,找不到返回 null
string.insert($string, $insert, $index)str-insert($string, $insert, $index)string在指定位置插入子串
string.length($string)str-length($string)number算字符串长度
string.slice($string, $start-at, $end-at)str-slice($string, $start-at, $end-at)string截取字符串,包含首尾
string.split($string, $separator, $limit)-list按分隔符拆分字符串,$limit 限制拆分次数
string.to-upper-case($string)to-upper-case($string)string转大写(仅 ASCII 字母)
string.to-lower-case($string)to-lower-case($string)string转小写(仅 ASCII 字母)
string.unique-id()-string生成唯一 ID,每次都不一样
string.unquote($string)unquote($string)string移除引号,只移外层
@use "sass:string";

// 1. 给字符串加引号,仪式感拉满

@debug string.quote(Open Sans); // 输出:"Open Sans"(没引号的加上)

@debug string.quote("Roboto");   // 输出:"Roboto"(有引号的不动)

// 2. 找子串位置,跟找对象一样准

@debug string.index("Hello World", "W");      // 输出:7(W在第7位)

@debug string.index("sass is cool", "is");    // 输出:6(is从第6位开始)

@debug string.index("abcdef", "x");           // 输出:null(查无此串)

// 3. 插入子串,想插哪就插哪

@debug string.insert("Hello", " beautiful", 6);  // 输出:"Hello beautiful"(末尾加)

@debug string.insert("abc123", "-", 4);          // 输出:"abc-123"(第4位插横线)

@debug string.insert("test", "pre-", -10);       // 输出:"pre-test"(索引太小就放开头)

// 4. 算长度,一个字符都不放过

@debug string.length("CSS");         // 输出:3(3个字符)

@debug string.length("Sass Script"); // 输出:11(11个字符,空格也算)

@debug string.length("");            // 输出:0(空字符串,没脾气)

// 5. 截取字符串,想留哪段留哪段

@debug string.slice("Programming", 5);        // 输出:"amming"(从第5位到末尾)

@debug string.slice("123456789", 2, 5);       // 输出:"2345"(第2到第5位)

@debug string.slice("abcdefgh", 1, -3);       // 输出:"abcde"(开头到倒数第3位前)

// 6. 拆分字符串,按规则分家

@debug string.split("a,b,c,d", ",");          // 输出:\["a", "b", "c", "d"](按逗号拆)

@debug string.split("2024-08-12", "-", 1);    // 输出:\["2024", "08-12"](只拆1次)

@debug string.split("foo|bar|baz", "|", 2);   // 输出:\["foo", "bar", "baz"](拆2次够了)

// 7. 转大写,气场全开

@debug string.to-upper-case("sass");          // 输出:"SASS"(小写变大写)

@debug string.to-upper-case("Hello World");   // 输出:"HELLO WORLD"(单词全大写)

// 8. 转小写,低调做人

@debug string.to-lower-case("CSS3");          // 输出:"css3"(大写变小写)

@debug string.to-lower-case("HELLO");         // 输出:"hello"(全变小写)

// 9. 生成唯一ID,永不重复

@debug string.unique-id();                    // 输出:u1a2b3c4d(随机一串)

@debug string.unique-id();                    // 输出:u5e6f7g8h(每次都不一样)

// 10. 移除引号,放飞自我

@debug string.unquote("Arial");               // 输出:Arial(引号没了)

@debug string.unquote('"quoted"');            // 输出:"quoted"(只移外层引号)
1.3.2.2 数字内置函数:数学不好也能玩转

加减乘除、取整、比较大小... 这些函数比计算器还好用,再也不用手算样式值了!

函数返回值功能描述
math.abs($number)number取绝对值
math.ceil($number)number向上取整(往大了整)
math.floor($number)number向下取整(往小了整)
math.round($number)number四舍五入
math.max($numbers...)number找最大值
math.min($numbers...)number找最小值
math.pow($base, $exponent)number算乘方(base 的 exponent 次方)
math.sqrt($number)number算平方根
math.rad($angle)number角度转弧度
math.deg($angle)number弧度转角度
math.random()number生成 0-1 随机浮点数
math.clamp($value, $min, $max)number把值锁在 min 和 max 之间(超了就取边界)
math.sign($number)number返回符号(正数 1,负数 - 1,0 返回 0)
@use "sass:math";

// 1. 基础数值处理,正负大小全搞定

\$num: -3.76;

.basic-ops {

&#x20; absolute: math.abs(\$num);       // 3.76(绝对值,负变正)

&#x20; rounded: math.round(\$num);      // -4(四舍五入,够意思)

&#x20; ceiling: math.ceil(\$num);       // -3(向上取整,往大了整)

&#x20; flooring: math.floor(\$num);     // -4(向下取整,往小了整)

&#x20; sign: math.sign(\$num);          // -1(返回符号,负数就是-1)

}

// 2. 范围限制,再也不怕值太离谱

\$value: 15;

.clamp-example {

&#x20; within-range: math.clamp(\$value, 10, 20);  // 15(在范围内,就用它)

&#x20; below-min: math.clamp(5, 10, 20);          // 10(低于最小,就用10)

&#x20; above-max: math.clamp(25, 10, 20);         // 20(高于最大,就用20)

}

// 3. 多值比较,谁大谁小一眼看穿

\$values: 8.5, 3.2, 12, -4, 7.9;

.extremes {

&#x20; maximum: math.max(\$values...);  // 12(最大值,C位出道)

&#x20; minimum: math.min(\$values...);  // -4(最小值,垫底)

}

// 4. 高级数学运算,装X专用

.calculations {

&#x20; power: math.pow(2, 10);         // 1024(2的10次方,1KB=1024B懂吧)

&#x20; root: math.sqrt(256);           // 16(16x16=256,没毛病)

&#x20; fractional: math.pow(8, 1/3);   // 2(8的立方根,2x2x2=8)

}

// 5. 角度转换,transform动画必备

.angle-ops {

&#x20; radians: math.rad(270deg);      // 4.71238898rad(270度转弧度)

&#x20; degrees: math.deg(math.pi()/2); // 90deg(π/2弧度转角度,刚好直角)

}

// 6. 随机数生成,抽奖就靠它

.random-values {

&#x20; basic: math.random();                  // 0-1之间的随机数(如0.6429)

&#x20; range: math.floor(math.random() \* 100); // 0-99之间的随机整数(如37)

}
1.3.2.3 数组内置函数:列表操作小能手

数组(list)在 Sass 里超常用,这些函数能增删改查、合并拆分,比 JS 数组方法还顺手!

函数功能描述
list.append($list, $value, $separator: auto)往列表末尾加元素
list.index($list, $value)找元素位置,找不到返回 null
list.join($list1, $list2, $separator: auto)合并两个列表
list.length($list)算列表长度(元素个数)
list.nth($list, $n)取第 n 个元素(索引从 1 开始,别搞错了)
list.separator($list)看列表用空格还是逗号分隔
list.set-nth($list, $n, $value)替换第 n 个元素
list.slice($list, $start-at, $end-at: -1)截取列表的一部分
@use "sass:list";

// 定义两个列表,一个空格分,一个逗号分

\$spacing: 8px 16px 24px 32px; // 空格分隔,兄弟情深

\$sizes: 12px, 14px, 16px, 18px; // 逗号分隔,保持距离

// 1. 看长度、取元素,了如指掌

.length-nth {

&#x20; spacing-length: list.length(\$spacing); // 4(4个元素,一个不少)

&#x20; second-size: list.nth(\$sizes, 2);      // 14px(第2个元素,就是它)

&#x20; last-spacing: list.nth(\$spacing, -1);  // 32px(负索引,倒数第一个)

}

// 2. 找元素位置,跟GPS定位一样准

.index-check {

&#x20; sixteen-index: list.index(\$sizes, 16px); // 3(16px在第3位)

&#x20; missing-index: list.index(\$spacing, 20px); // null(这货不在列表里)

}

// 3. 加元素、换元素,想改就改

.modify-list {

&#x20; added-size: list.append(\$sizes, 20px); // 12px, 14px, 16px, 18px, 20px(加个20px)

&#x20; replaced-spacing: list.set-nth(\$spacing, 3, 28px); // 8px 16px 28px 32px(第3个换成28px)

}

// 4. 合并列表,搞个大新闻

.combine-lists {

&#x20; joined: list.join(\$spacing, \$sizes); // 8px 16px 24px 32px, 12px, 14px, 16px, 18px(默认保持分隔符)

&#x20; forced-separator: list.join(\$spacing, \$sizes, \$separator: space); // 全用空格分隔,不分彼此

}

// 5. 截取列表,想要哪段就哪段

.sliced-lists {

&#x20; first-two: list.slice(\$spacing, 1, 2); // 8px 16px(前两个,打包带走)

&#x20; from-third: list.slice(\$sizes, 3); // 16px, 18px(从第3个到最后)

&#x20; exclude-last: list.slice(\$spacing, 1, -2); // 8px 16px(排除最后两个)

}

// 6. 实战:循环生成类名,批量干活

@each \$index, \$size in \$sizes {

&#x20; .text-#{\$index} {

&#x20;   font-size: \$size; // 生成.text-1到.text-4,分别对应不同大小

&#x20; }

}
1.3.2.4 字典内置函数:键值对管理大师

字典(map)就是键值对的集合,这些函数能查值、删键、合并,比查字典还快!

函数功能描述
map.get($map, $key)按键取值,取不到返回 null
map.has-key($map, $key)检查键是否存在,返回 true/false
map.keys($map)取所有键,组成列表
map.merge($map1, $map2)合并两个字典,重复的键后者覆盖前者
map.remove($map, $keys...)删掉指定的键和值
map.set($map, $key, $value)新增或修改键值对
map.values($map)取所有值,组成列表
@use "sass:map";

@use "sass:list";

// 定义个主题配置字典,啥都有

\$theme: (

&#x20; primary: #2563eb,

&#x20; secondary: #64748b,

&#x20; accent: #f97316,

&#x20; sizes: (

&#x20;   sm: 0.8rem,

&#x20;   md: 1rem,

&#x20;   lg: 1.25rem

&#x20; )

);

// 1. 取值、查键,基础操作

.basic-operations {

&#x20; primary-color: map.get(\$theme, primary); // #2563eb(取primary的值)

&#x20; has-accent: map.has-key(\$theme, accent); // true(accent存在,没骗你)

&#x20; has-warning: map.has-key(\$theme, warning); // false(warning不存在,别瞎找)

&#x20; medium-size: map.get(\$theme, sizes, md); // 1rem(嵌套字典取值,md大小)

}

// 2. 取所有键、所有值,一网打尽

.keys-values {

&#x20; all-keys: map.keys(\$theme); // primary, secondary, accent, sizes(所有键都在这)

&#x20; color-values: map.values(map.remove(\$theme, sizes)); // 所有颜色值,排除sizes

}

// 3. 修改、合并字典,想咋改咋改

.modify-map {

&#x20; with-warning: map.set(\$theme, warning, #ef4444); // 加个warning键,值是红色

&#x20; merged-theme: map.merge(\$theme, (

&#x20;   primary: #3b82f6, // 覆盖原primary

&#x20;   dark: #1e293b // 加个新键dark

&#x20; ));

}

// 4. 删键、循环,批量生成样式

\$colors: map.remove(\$theme, sizes); // 删掉sizes,只留颜色

// 循环颜色,生成文本颜色类

@each \$name, \$color in \$colors {

&#x20; .text-#{\$name} {

&#x20;   color: \$color;

&#x20; }

}

// 循环尺寸,生成字体大小类

@each \$name, \$size in map.get(\$theme, sizes) {

&#x20; .text-#{\$name} {

&#x20;   font-size: \$size;

&#x20; }

}
1.3.2.5 颜色内置函数:调色大师的秘密武器

这些函数能调亮度、饱和度、透明度,还能混合颜色,比 PS 调色还方便,设计师看了都直呼内行!

函数功能描述
color.adjust($color, $props...)相对调整颜色属性(如亮度 + 10%)
color.alpha($color)取透明度(0-1 之间)
color.change($color, $props...)绝对设置颜色属性(如色相固定为 120deg)
color.lighten($color, $amount)提亮颜色(变浅)
color.darken($color, $amount)变暗颜色(变深)
color.saturate($color, $amount)提高饱和度(更鲜艳)
color.desaturate($color, $amount)降低饱和度(更灰暗)
color.mix($color1, $color2, $weight: 50%)混合两种颜色,$weight 控制第一种占比
color.to-hsl($color)转成 HSL 格式字典(含色相、饱和度等)
color.to-rgb($color)转成 RGB 格式字典(含红、绿、蓝通道)
color.rgb($r, $g, $b, $alpha: 1)用 RGB 值创建颜色
color.hsl($h, $s, $l, $alpha: 1)用 HSL 值创建颜色
@use "sass:color";

@use "sass:map";

// 基础颜色,就它俩了

\$primary: #4f46e5; // 靛蓝色,高冷范

\$secondary: #ec4899; // 粉红色,小清新

// 1. 调亮度、饱和度,换个心情

.lightness-saturation {

&#x20; lightened: color.lighten(\$primary, 30%); // 亮30%,阳光点

&#x20; darkened: color.darken(\$primary, 20%);   // 暗20%,沉稳点

&#x20; saturated: color.saturate(\$secondary, 25%); // 艳25%,更骚气

&#x20; desaturated: color.desaturate(\$secondary, 40%); // 灰40%,低调点

}

// 2. 调透明度、改属性,随心变

.alpha-properties {

&#x20; half-transparent: color.change(\$primary, \$alpha: 0.5); // 半透明,朦胧美

&#x20; full-transparent: color.adjust(\$secondary, \$alpha: -0.8); // 透80%,快看不见了

&#x20; hue-changed: color.change(\$primary, \$hue: 120deg); // 色相120度,变绿色

}

// 3. 混合颜色,生个"混血儿"

.color-mixing {

&#x20; equal-mix: color.mix(\$primary, \$secondary); // 50:50混合,各占一半

&#x20; primary-heavy: color.mix(\$primary, \$secondary, 70%); // 主色70%,占主导

&#x20; secondary-heavy: color.mix(\$primary, \$secondary, 20%); // 辅助色80%,抢风头

}

// 4. 提取颜色信息,查户口专用

.color-info {

&#x20; primary-alpha: color.alpha(\$primary); // 1.0(完全不透明,很实在)

&#x20; secondary-rgb: color.to-rgb(\$secondary); // RGB通道信息,红、绿、蓝各多少

&#x20; secondary-red: map.get(color.to-rgb(\$secondary), red); // 单拿红色通道值

&#x20; primary-hsl: color.to-hsl(\$primary); // HSL信息,色相、饱和度、亮度

&#x20; primary-hue: map.get(color.to-hsl(\$primary), hue); // 单拿色相值

}

// 5. 自己造颜色,DIY专属色

.color-creation {

&#x20; custom-rgb: color.rgb(79, 70, 229); // 用RGB值造,和\$primary一样

&#x20; custom-hsl: color.hsl(243deg, 86%, 55%); // 用HSL值造,也和\$primary一样

&#x20; transparent-rgb: color.rgb(236, 72, 153, 0.6); // 带透明度的RGB色

}

// 6. 实战:生成渐变色阶,一套颜色全家桶

\$base: #10b981; // 基础绿色

@for \$i from 1 through 5 {

&#x20; .color-#{\$i}00 {

&#x20;   background-color: color.lighten(\$base, (5 - \$i) \* 15%); // 从深到浅,5个色阶

&#x20; }

}
1.3.2.6 其他内置函数:选择器操作小技巧

这些函数能玩选择器,嵌套、合并、加后缀,写组件样式超方便!

函数功能描述
selector.append($selector, $suffix)给选择器加后缀(如.btn + :hover → .btn:hover)
selector.extend($selector, $extendee)模拟 @extend,扩展选择器
selector.nest($selectors...)嵌套选择器(如.parent 和 &:hover → .parent:hover)
selector.parse($selector)把选择器字符串转成列表
selector.unify($selector1, $selector2)合并两个选择器(如.a 和.b → .a.b)
@use "sass:selector";

// 1. 嵌套选择器,父子关系一键搞定

.nesting {

&#x20; nested: selector.nest(".parent", "&:hover .child");&#x20;

&#x20; // 结果:.parent:hover .child(完美嵌套)

}

// 2. 给选择器加后缀,状态轻松加

.suffix {

&#x20; hover-state: selector.append(".btn", ":hover");&#x20;

&#x20; // 结果:.btn:hover(hover状态安排上)

&#x20; active-state: selector.append("input", "\[type='button']");&#x20;

&#x20; // 结果:input\[type='button'](按钮类型input)

}

// 3. 合并选择器,强强联合

.unifying {

&#x20; combined: selector.unify(".btn", ".primary");&#x20;

&#x20; // 结果:.btn.primary(既是btn又是primary)

&#x20; element-combined: selector.unify("a", ".active");&#x20;

&#x20; // 结果:a.active(激活状态的链接)

}

// 4. 实战:批量生成禁用样式,效率拉满

\$components: "btn", "card", "modal";

@each \$comp in \$components {

&#x20; \#{selector.append(".#{\$comp}", "--disabled")} { // 生成.btn--disabled等

&#x20;   opacity: 0.6;

&#x20;   pointer-events: none; // 禁用点击

&#x20; }

}

1.4 控制语句:Sass 的 "指挥系统"

跟 JS 一样,Sass 也有条件判断和循环,能根据情况生成不同样式,简直是 "智能生成机"!

1.4.1 @if 条件控制:看情况办事,不瞎搞

跟 JS 的 if 一模一样,单分支、双分支、多分支,还有三目运算,灵活得很!

  1. 三目运算:一行搞定简单判断
.container {

&#x20; color: if(1+1>2, red, green); // 1+1不大于2,所以是green

}

.view {

&#x20; color: if(1px + 2px == 3px, yellow, blue); // 1+2=3,所以是yellow

}

// 编译结果:

.container { color: green; }

.view { color: yellow; }
  1. @if 单分支:符合条件才执行
.app {

&#x20; @if 1+1 == 2 { color: red; } // 条件成立,执行

&#x20; @if 1+2 == 6 { color: blue; } // 条件不成立,跳过

&#x20; margin: 10px; // 不管怎样都执行

}

// 编译结果:

.app { color: red; margin: 10px; }
  1. @if...@else 双分支:二选一
p {

&#x20; @if 1+1 == 2 { color: red; } // 对的,用red

&#x20; @else { color: blue; }

&#x20; margin: 10px;

}

div {

&#x20; @if 1+1 == 3 { color: red; } // 错的,不用red

&#x20; @else { color: blue; }

&#x20; margin: 10px;

}

// 编译结果:

p { color: red; margin: 10px; }

div { color: blue; margin: 10px; }
  1. @if...@else if 多分支:多个条件选一个
\$type: monster; // 变量是monster

p {

&#x20; @if \$type == ocean { color: blue; } // 不是ocean,跳过

&#x20; @else if \$type == matador { color: red; } // 不是matador,跳过

&#x20; @else if \$type == monster { color: green; } // 是monster,用green

&#x20; @else { color: black; } // 都不是才用black

}

// 编译结果:

p { color: green; }

1.4.2 循环语句:重复的活交给机器干

跟 JS 的循环一样,有 for、each、while,批量生成样式贼快,再也不用复制粘贴了!

  1. @for 循环:按次数来,精准控制

两种写法:through包含结束值,to不包含结束值,选哪个看心情!

// @for \$var from \<start> to \<end> → 不包含end

@for \$i from 1 to 3 {

&#x20; .item-#{\$i} { width: \$i \* 2px; } // i=1、2,生成.item-1和.item-2

}

// @for \$var from \<start> through \<end> → 包含end

@for \$i from 1 through 3 {

&#x20; .item2-#{\$i} { width: \$i \* 2em; } // i=1、2、3,生成三个类

}
  1. @each 循环:遍历列表或字典,逐个处理

跟 JS 的 for...of 差不多,列表、字典都能遍历,超好用!

// 遍历列表

\$arr: puma, sea-slug, egret, salamander;

@each \$animal in \$arr { // 逐个拿动物名

&#x20; .#{\$animal}-icon {

&#x20;   background: url("/asstes/#{\$animal}.png"); // 生成对应图片路径

&#x20; }

}

// 遍历字典

\$dict: (

&#x20; h1: 2em,

&#x20; h2: 1.5em,

&#x20; h3: 1.2em,

&#x20; h4: 1em,

);

@each \$key, \$value in \$dict { // 逐个拿键和值

&#x20; \#{\$key} { font-size: \$value; } // 生成h1h4的字体大小

}
  1. @while 循环:满足条件就一直干

跟 JS 的 while 一样,条件成立就循环,小心死循环哦!

\$i: 6; // 初始值6

@while \$i > 0 { // 只要i>0就继续

&#x20; .item-#{\$i} { width: 2em \* \$i; } // 生成样式

&#x20; \$i: \$i - 2; // i减2,避免死循环

}

1.5 SASS 中的 @规则:特殊指令,各有神通

Sass 扩展了 CSS 的 @规则,功能更强大,用法更骚气!

1.5.1 @import:老古董但还能用

这是老版本的导入语法,虽然现在推荐用 @use,但还是得了解一下它的骚操作!

核心功能:
  1. 万物皆可复用:不仅能导入 CSS,还能直接用被导入文件的变量、混合宏、函数,代码复用拉满!

  2. 编译时合并:跟原生 CSS 的 @import(浏览器加载时才请求)不一样,Sass 的 @import 在编译时就把文件合并成一个,减少请求,速度飞起!

语法规则:
  1. 基础用法:导入时可以省扩展名(.scss、.sass、.css 都行)
// 导入同目录的\_variables.scss(下划线文件是"局部文件",不单独编译)

@import 'variables';

// 导入CSS文件也没问题

@import 'reset.css';
  1. 批量导入:用逗号分隔,一次导入多个,不用重复写 @import
// 一次性导入reset、variables、button三个文件,效率高

@import 'reset', 'variables', 'components/button';
  1. 缩进语法(.sass)专属:.sass 文件里导入可以不加引号,更简洁
// style.sass

@import variables  // 不用引号,直接写

body

&#x20; color: \$primary  // 用导入的变量,爽
与原生 CSS @import 的区别:
特性原生 CSS @importSass @import
处理时机浏览器渲染时才加载编译时就合并成一个文件
性能影响多文件多请求,慢!合并成一个文件,快!
可导入内容只能导 CSS 样式能导变量、混合宏、函数,啥都能复用
语法灵活性每次导入都要写 @import逗号分隔多文件,一次搞定

1.5.2 @use:现代模块化扛把子

@use是 Sass 的新宠,专门替代@import,解决全局污染问题,模块化管理贼爽!

核心功能:
  1. 命名空间隔离:导入的模块内容都在自己的命名空间里,用 "模块名。内容" 访问,再也不怕变量重名打架了!

  2. 私有默认:模块里的东西默认私有,只通过命名空间暴露,全局干干净净,强迫症狂喜!

基本语法:

@use '文件路径'导入,通过 "模块名。内容" 访问变量、混合宏、函数,清晰明了!

// \_variables.scss(局部模块,藏起来)

\$primary: #2563eb;

\$font-size: 16px;

// style.scss(主文件)

@use 'variables'; // 导入模块,默认命名空间是文件名

.box {

&#x20; color: variables.\$primary; // 用命名空间访问变量,不会错

&#x20; font-size: variables.\$font-size;

}

1.5.3 @media:响应式布局的神助攻

原生 CSS 的 @media 是媒体查询,Sass 直接把它强化了,更好用!

  1. 允许嵌套在选择器里:不用单独写在外面,结构更清晰
.navigation {

&#x20; display: flex;

&#x20; justify-content: flex-end;

&#x20; @media (max-width: 768px) { // 嵌套在.navigation里

&#x20;   flex-direction: column; // 小屏幕就竖着排

&#x20; }

}

// 编译后自动提出来:

.navigation {

&#x20; display: flex;

&#x20; justify-content: flex-end;

}

@media (max-width: 768px) {

&#x20; .navigation { flex-direction: column; }

}
  1. 能用上变量:断点值用变量存,改起来方便,不用到处找
\$mobile-breakpoint: 768px; // 手机断点存成变量

.navigation {

&#x20; display: flex;

&#x20; justify-content: flex-end;

&#x20; @media (max-width: \$mobile-breakpoint) { // 直接用变量,爽

&#x20;   flex-direction: column;

&#x20; }

}

// 编译结果:

.navigation {

&#x20; display: flex;

&#x20; justify-content: flex-end;

}

@media (max-width: 768px) {

&#x20; .navigation { flex-direction: column; }

}
  1. 还能结合混合宏:通过混合宏可以将响应式逻辑进行封装,实现代码的复用,提升开发效率。
@mixin respond-to(\$breakpoint) {

&#x20; @if \$breakpoint == "mobile" {

&#x20;   @media (max-width: 768px) {

&#x20;     @content;

&#x20;   }

&#x20; } @else if \$breakpoint == "tablet" {

&#x20;   @media (min-width: 769px) and (max-width: 1024px) {

&#x20;     @content;

&#x20;   }

&#x20; } @else if \$breakpoint == "desktop" {

&#x20;   @media (min-width: 1025px) {

&#x20;     @content;

&#x20;   }

&#x20; }

}

.container{

&#x20; width: 80%;

&#x20; @include respond-to("mobile"){

&#x20;   width: 100%;

&#x20; }

&#x20; @include respond-to("desktop"){

&#x20;   width: 70%;

&#x20; }

}

等同于传统 CSS 代码:

.container {

&#x20; width: 80%;

}

@media (max-width: 768px) {

&#x20; .container {

&#x20;   width: 100%;

&#x20;   }

}

@media (min-width: 1025px) {

&#x20; .container {

&#x20;   width: 70%;

&#x20;   }

}

@extend

在编写 CSS 样式时,常常会遇到多个元素的样式存在大量共性,仅部分样式有所差异的情况。此时,就可以借助 Sass 的@extend规则实现样式继承,让一个选择器能够复用另一个选择器的样式规则。

.button {

&#x20; display: inline-block;

&#x20; padding: 20px;

&#x20; background-color: red;

&#x20; color: white;

}

.primary-button{

&#x20; @extend .button;

&#x20; background-color: blue;

}

上述 Sass 代码编译后的 CSS 如下:

.button, .primary-button {

&#x20; display: inline-block;

&#x20; padding: 20px;

&#x20; background-color: red;

&#x20; color: white;

}

.primary-button {

&#x20; background-color: blue;

}

对于初学者来说,可能会混淆@extend@mixin,二者虽然都能提取公共样式,但存在本质区别:

  • 参数支持@mixin支持传递参数,灵活性更强;@extend不支持参数传递。

  • 生成的 CSS@extend会合并选择器,生成的 CSS 更紧凑,继承的样式真实存在于最终代码中;@mixin会在每个@include处完整生成 CSS 代码,本质是简单的代码替换。

  • 使用场景@extend适用于继承已有样式,如 UI 框架的通用样式;@mixin适用于需自定义参数的场景,如为不同组件生成相似样式。

再看一个复杂示例:

.box {

&#x20; border: 1px #f00;

&#x20; background-color: #fdd;

}

.container {

&#x20; @extend .box;

&#x20; border-width: 3px;

}

.box.a{

&#x20; background-image: url("/image/abc.png");

}

编译后的 CSS 为:

.box, .container {

&#x20; border: 1px #f00;

&#x20; background-color: #fdd;

}

.container {

&#x20; border-width: 3px;

}

.box.a, .a.container {

&#x20; background-image: url("/image/abc.png");

}

在这个例子中,.container继承了.box的所有样式。若某个元素需同时具备.box.a类才能应用特定样式(如abc样式),那么带有.container.a类的元素,同样会应用该样式。

此外,当需要定义一套仅用于继承、不希望单独编译输出的样式时,可以使用%作为占位符:

%button {

&#x20; display: inline-block;

&#x20; padding: 20px;

&#x20; background-color: red;

&#x20; color: white;

}

.primary-button{

&#x20; @extend %button;

&#x20; background-color: blue;

}

.secondary-button{

&#x20; @extend %button;

&#x20; background-color: pink;

}

编译后的 CSS:

.secondary-button, .primary-button {

&#x20; display: inline-block;

&#x20; padding: 20px;

&#x20; background-color: red;

&#x20; color: white;

}

.primary-button {

&#x20; background-color: blue;

}

.secondary-button {

&#x20; background-color: pink;

}

@at-root

当需要将嵌套规则移动到根级别(声明时不在根级别)时,可使用@at-root

.parent{

&#x20; color: red;

&#x20; @at-root .child{

&#x20;   color: blue;

&#x20; }

}

编译后的 CSS:

.parent {

&#x20; color: red;

}

.child {

&#x20; color: blue;

}

若要移动一组规则,需在@at-root后添加大括号,将目标样式组包含其中:

.parent {

&#x20; color: red;

&#x20; @at-root {

&#x20;  .child {

&#x20;     color: blue;

&#x20;   }

&#x20;  .test {

&#x20;     color: pink;

&#x20;   }

&#x20;  .test2 {

&#x20;     color: purple;

&#x20;   }

&#x20; }

}

编译后:

.parent {

&#x20; color: red;

}

.child {

&#x20; color: blue;

}

.test {

&#x20; color: pink;

}

.test2 {

&#x20; color: purple;

}

@debug、@warn、@error

这三个规则用于调试,能在编译过程中输出信息,帮助排查和诊断代码问题。

一、当前 Sass 的核心升级与最佳实践
  1. 全面转向模块化体系
  • @import 废弃与 @use/@forward 普及:自 2025 年起,Sass 官方已将@import标记为废弃语法,强烈推荐使用@use@forward构建模块化体系。

    • @use:通过命名空间(如@use 'variables' as v)隔离作用域,避免全局变量冲突,还支持使用with规则动态配置模块参数。

    • @forward:作为模块导出的中间环节,库作者可借此隐藏内部实现细节,仅暴露公共 API(如@forward 'theme' show primary-color)。

  • Dart Sass 成为唯一官方实现:LibSass 和 Node Sass 已被正式废弃。Dart Sass 通过嵌入式协议解决了跨语言调用和性能问题,支持 C++、Python 等语言通过子进程通信调用,编译速度与原生实现相当。

  1. 内置模块系统与语法革新
  • 函数命名空间化:所有内置函数(如颜色、数学运算函数)均需通过模块调用。例如:
@use 'sass:color';

@use 'sass:math';

\$dark-color: color.scale(\$primary, \$lightness: -10%); // 替代旧的scale-color()

\$result: math.div(10px, 2); // 替代/运算符,避免与CSS分隔符冲突
  • 严格的类型检查与语法规范

    • 颜色函数对参数类型要求更严格(如hsl()必须传入 0-360 的角度值)。

    • 列表和映射函数(如map-get)的参数类型检查增强,减少运行时错误。

  1. 性能与工具链整合
  • 编译速度提升:Dart Sass 借助 JIT 编译和内存优化,在大型项目中的编译速度比 Node Sass 快 30% 以上,且支持增量编译。

  • 深度集成现代构建工具

    • Vite 6 + 默认使用 Sass 现代 API,支持@use模块热更新。

    • Webpack 6 通过sass-loader实现与 Sass JavaScript API 的无缝对接,支持自定义函数和导入器。

二、未来 Sass 的发展方向
  1. 全面拥抱 CSS 原生生态
  • 更紧密的 CSS 兼容性:未来版本将优先支持 CSS 最新特性(如容器查询、嵌套规则),并通过 Sass 模块系统提供更便捷的封装方式。例如,Sass 可能推出@container混合宏,简化复杂容器查询的编写。

  • 与 CSS Houdini 的协同:尽管目前尚未明确支持,但 Sass 团队已表示将探索与 CSS Houdini 的整合,未来开发者或许能通过 Sass 函数动态生成 CSS 自定义属性(如--custom-var: sass:math.random(100))。

  1. 类型安全与开发体验升级
  • 官方类型系统探索:社区工具typed-scss-modules已实现 SCSS 类名的 TypeScript 类型推导,未来 Sass 可能内置基础类型检查功能(如变量类型标注、函数参数校验),降低运行时错误发生概率。

  • 智能提示与代码补全:借助语言服务器协议(LSP),IDE 将能够识别模块导出的变量和函数,提供更精准的自动补全功能(如 VS Code 已支持模块路径智能提示)。

  1. 性能与跨平台优化
  • 嵌入式协议的全面落地:Dart Sass 的嵌入式协议将支持更多语言(如 Rust、Go),开发者无需依赖 Node.js 环境即可调用 Sass 编译器,提升服务器端渲染(SSR)场景下的效率。

  • 并行编译与缓存机制:未来版本将优化多文件编译的并行处理逻辑,通过文件指纹缓存技术减少重复编译时间,尤其在微前端架构中大幅提升构建速度。

  1. 工具链与生态系统扩展
  • 低代码与可视化工具集成:设计工具(如 Figma、Sketch)可能通过插件直接生成 Sass 模块代码,支持动态主题切换和样式变体管理。

  • 与 CSS-in-JS 的融合:尽管 Sass 与 CSS-in-JS(如 Styled-components)定位不同,但未来可能通过 Babel 插件实现两者的语法互转,满足混合开发场景需求。

三、开发者应对策略
  1. 立即行动的迁移步骤
  • 存量项目改造:使用@use逐步替换@import,并通过@forward重构模块依赖关系。例如:
// 旧代码

@import 'variables';

// 新代码

@use 'variables' as v;

.box { color: v.\$primary; }
  • 工具链升级:确保构建工具(如 Webpack、Vite)使用最新 Sass 加载器,并配置api: 'modern'以启用模块化支持。
  1. 未来技术栈布局建议
  • 关注 Dart Sass 的新特性:定期查阅Dart Sass 更新日志,优先尝试嵌入式协议和自定义函数等高级功能。

  • 探索社区生态工具

    • 使用purgecss清理未使用的 CSS,结合 Sass 模块化减少冗余代码。

    • 使用scss-lintstylelint进行代码质量检查,确保符合模块化规范。

四、总结

Sass 正从单纯的 CSS 预处理器逐步进化为现代样式工程平台

  • 现在:通过模块化、类型安全和性能优化,有效解决大型项目的样式维护难题。

  • 未来:与 CSS 原生特性、工具链深度整合,成为全链路样式开发的核心基础设施。

开发者应尽早采用@use/@forward体系,充分发挥 Dart Sass 的工具链优势,并关注社区在类型系统和跨平台编译方面的创新,以保持技术栈的竞争力。

(注:文档部分内容可能由 AI 生成)