阅读视图

发现新文章,点击刷新页面。

最全Scss语法,赶紧收藏起来吧

Sass/SCSS 的嵌套

作用

  • 减少重复:不再处处写 .card 前缀。
  • 表达结构:一眼看出父子/状态/修饰的关系。
  • 就地维护:媒体查询、状态样式和主体样式放在一起,改组件更集中。
  • BEM 更顺手:&__el&--mod&.is-xxx 自然生成。

下面我们来看下它嵌套编译的效果

.card {
  .title { color: #333; }        // 后代
  &:hover { box-shadow: ...; }   // 父的伪类
  .actions > .btn { ... }        // 组合器保留
}

编译后:

.card .title{color:#333}
.card:hover{box-shadow:...}
.card .actions > .btn{...}

变量与类型

$size: 16px;
$brand: #0b81ff;
$title: "Hello";
$on: true;
$none: null;

// 列表 & 映射
$spaces: 4px 8px 16px;
$palette: (primary: #0b81ff, success: #22c55e);
  • null 的属性会被跳过。
  • map.get($palette, primary) 取值。

选择器嵌套与父选择器 &

.card {
  padding: 16px;
  &--active { box-shadow: 0 4px 12px rgba(0,0,0,.08); } // BEM 修饰
  &:hover { transform: translateY(-1px); }               // 伪类
  .title { font-weight: 600; }                           // 子元素
}

嵌套尽量 ≤ 3 层,避免选择器过长。

插值 #{}(拼接变量)

$base: btn;
$radius: 8;
.#{$base} { border-radius: #{$radius}px; } // → .btn { border-radius: 8px }

Mixin / Include(可复用片段)

@mixin flex-center($gap: 8px) {
  display: flex; align-items: center; justify-content: center; gap: $gap;
}
.toolbar { @include flex-center(12px); }

// 带内容插槽
@mixin layer($z: 1) { position: relative; z-index: $z; @content; }
.badge { @include layer(10) { pointer-events: none; } }

Function(返回计算值)

@use "sass:math";
@function px2rem($px, $base: 16) { @return math.div($px, $base) * 1rem; }
.title { font-size: px2rem(20); }

Dart Sass 用 math.div 代替 / 除法。

控制指令

$theme: dark;

@if $theme == dark { body { background:#0f172a; color:#e2e8f0; } }
@else { body { background:#fff; color:#111; } }

@each $gap in (4px, 8px, 12px) { .gap-#{$gap} { gap: $gap; } }

@for $i from 1 through 3 { .col-#{$i} { width: (100%/3)*$i; } }

$i: 0;
@while $i < 3 { .ring-#{$i} { outline-width: $i+1px; } $i: $i + 1; }

占位选择器与继承(谨慎用)

%btn-base { font: inherit; padding: .5em 1em; border: 1px solid transparent; }
.primary { @extend %btn-base; background: #0b81ff; color: #fff; }

@extend 可能引发“选择器膨胀”,组件库更推荐用 mixin 复用样式。

模块化导入(现代写法)

/* tokens/_color.scss */
$primary: #0b81ff !default;
@mixin btn() { padding: 8px 12px; }

/* design/_index.scss —— 聚合出口 */
@forward "../tokens/color";

/* app.scss —— 使用与配置 */
@use "./design/index" as d with ($primary: #0052d9);
.button { color: d.$primary; @include d.btn(); }
  • @use:有命名空间、成员只读;用 with 配置带 !default 的变量。
  • @forward:做“总入口”(barrel),对外转发变量/函数/mixin。
  • 旧式 @import 已弃用;@import url(...)CSS 导入(不会带来 Sass 变量)。

调试与错误

@use "sass:meta";
@debug meta.type-of((a: b));
@warn "Deprecated var, will be removed.";
@error "Invalid token";

全局方法(旧写法)

颜色相关

写法 说明 示例/结果
darken(#fff, 10%) 调暗亮度 10%(不是透明度) #fff → #e6e6e6
lighten(#fff, 30%) 调亮亮度 30%(纯白几乎无变化;也不是透明度) #fff → #fff
hsl(0, 100%, 50%) 色相/饱和度/亮度 构造颜色(红) #ff0000
adjust-hue(#fff, 180deg) 色相旋转 180°(对白/灰无可见变化) #fff
saturate(#fff, 10%) 提高饱和度(对白/灰无效) #fff
desaturate(#fff, 10%) 降低饱和度 #fff
transparentize(#fff, 0.1) 增加透明度(α 减 0.1) rgba(255,255,255,0.9)
opacify(#fff, 0.1) 增加不透明度(α 加 0.1) rgba(255,255,255,1)

注:transparentize/opacify 的第二个参数是 0–1 的无单位数,不是百分比。

计算

写法 说明 示例/结果
abs(-10px) 绝对值 10px
ceil(-12.5px) 向上取整(朝 +∞) -12px
round(12.3px) 四舍五入 12px
floor(12.8px) 向下取整 12px
percentage(650px / 1000px) 比例转百分比 65%(因为 px/px → 无单位 0.65)
min(1, 2, 3) 取最小值(编译期) 1
max(1, 2, 3) 取最大值(编译期) 3

提醒:min/max 比较带单位时需同维度可换算(如 pxin);px vs rem/vw 等不同维度请用 CSSmin()/max()/clamp() 在浏览器端计算。

字符串相关

写法 说明 示例/结果
to-upper-case("hello") 转大写 "HELLO"
to-lower-case("HELLO") 转小写 "hello"
str-length("hello") 字符串长度 5
str-index("hello", "h") 返回首次出现位置(1 基;找不到为 null 1
str-insert("hello", "world", 5) 在索引处插入子串(1 基;负数为倒数) "hellworldo"

内置模块Api(新写法)

这里主要介绍 sass:color、sass:math、sass:string,其他有需要的可以自行去了解

sass:color(调色/透明度/混色)

@use "sass:color";
$brand: #1677ff;

/* 1) 按比例靠近极值(推荐,变化更自然) */
.bg-hover  { background: color.scale($brand, $lightness: 10%); }   // 变亮
.bg-active { background: color.scale($brand, $lightness: -12%); }  // 变暗
.bg-ghost  { background: color.scale($brand, $alpha: -30%); }      // 更透明

/* 2) 加/减固定量(严格步长) */
.more-sat  { background: color.adjust($brand, $saturation: 15%); }
.rotate    { background: color.adjust($brand, $hue: 30deg); }      // 旋转色相

/* 3) 设定绝对值(直接锁定到目标) */
.fixed-a   { background: color.change($brand, $alpha: 0.6); }      // α=0.6
.fixed-l   { background: color.change($brand, $lightness: 40%); }  // L=40%

/* 4) 混色(做浅/深阶) */
.light-1   { background: color.mix(#fff, $brand, 20%); }           // 更浅
.dark-1    { background: color.mix(#000, $brand, 15%); }           // 更深

/* 5) 反相(生成对比色) */
.invert    { color: color.invert($brand, 100%); }

小抄:

  • 变亮/变暗 → scale($lightness: ±x%);透明度 → scale($alpha: ±x%)
  • 固定步长 → adjust;锁定目标值 → change;两色过渡 → mix

sass:math(数值/单位运算)

@use "sass:math";

/* 1) 除法一定用 math.div */
.title { font-size: math.div(20, 16) * 1rem; }  // 1.25rem

/* 2) 取整/比较/钳制(编译期) */
.box  { margin: math.round(4.6px); }            // 5px
.maxw { max-width: math.min(960px, 1in); }      // 单位可换算才行
/* 混单位(px vs rem/vw)请用 CSS 的 min()/clamp() 在运行时算 */

/* 3) 常用函数 */
$pi: math.$pi;                 // 3.14159…
$len: math.hypot(3, 4);        // 5(向量长度)
$angle: math.atan2(1, -1);     // 135deg(可直接放到 rotate())

/* 4) 小工具:px→rem */
@function px2rem($px, $base: 16) { @return math.div($px, $base) * 1rem; }
.btn { padding: px2rem(10) px2rem(14); }

要点:

  • min/max/clamp 仅比较同维度可换算单位(px↔in 等);混单位用 CSSmin()/max()/clamp()
  • 乘除尽量“有单位 × 无单位”,避免产生非法复合单位。

sass:string(拼接/切片/大小写/引号)

@use "sass:string";

/* 1) 拼接请用插值 #{} */
$ns: "app"; $block: btn;
.selector { content: "#{$ns}-#{$block}"; }   // "app-btn"

/* 2) 长度/索引/切片/插入(索引从 1 开始,负数从尾部数) */
@debug string.length("hello");                    // 5
@debug string.index("btn--primary", "--");        // 4
@debug string.slice("abcdef", 2, 4);              // "bcd"
@debug string.insert("color", "-primary", 6);     // "color-primary"

/* 3) 大小写/引号 */
@debug string.to-upper-case("btn");               // "BTN"
@debug string.quote(btn);                         // "btn"
@debug string.unquote("bold");                    // bold(变标识符)

/* 4) 唯一 id(避免命名冲突) */
$uid: string.unique-id();                         // 比如 "u5ab9"
@keyframes fade-#{$uid} { from{opacity:0} to{opacity:1} }
.fade { animation: fade-#{$uid} .2s ease; }

小抄:

  • 串联字符串 → **插值 #{}**;结构化处理再用 length/index/slice/insert
  • quote/unquote 控制是否带引号;unique-id() 做不冲突的 keyframes/变量名。

Scss 的四种导入方式你都知道吗

想把样式拆模块、做主题、又不想全局变量乱飞?这篇把 SCSS 的四种“导入/组织”方式一次讲透:@use@forward、Sass 旧式 @import、以及 CSS 的 @import url(...)。含示例、对比表、迁移步骤与避坑清单。


@import "xxx":Sass 旧式导入(已弃用

作用
编译期把被导入的 SCSS 内容“直接拼接”到当前位置,变量/混入进入全局,容易重复加载、顺序踩坑。Dart Sass 已弃用,推荐使用@use/@forward

示例

@import "./tokens";   // 编译时把 tokens.scss 的内容贴进来(非 CSS 运行时)

@import url(...)CSS 的导入

作用
浏览器在运行时请求外部 CSS 文件;不会引入 Sass 的变量/混入/函数。

示例

@import url("/base.css");           /* 或者 @import "/print.css" print */

位置限制
必须在样式表最前面(在任何普通规则前;前面最多有 @charset / 其它 @import)。影响性能,一般不建议使用。


@use:模块化导入(推荐

作用
将另一个 SCSS 文件当作“模块”加载,默认通过命名空间访问变量/函数/混入;只加载一次、不污染全局,避免命名冲突。

示例

/* tokens/_color.scss */
$primary: #0b81ff !default;
@mixin btn { padding: 8px 12px; border-radius: 8px; }

/* app.scss */
@use "./tokens/color" as c; // 起别名 c

.button {
  color: c.$primary;
  @include c.btn();
}

配置默认变量(with + !default)

@use "./tokens/color" as c with (
  $primary: #0052d9   // 仅能配置标了 !default 的顶层公开变量
);

要点

  • 命名空间:@use "x" as x;不建议as *(去掉前缀,易冲突)。
  • 变量只读:c.$primary 不能在引入方直接赋值,只能用 with加载时配置。

@forward:聚合/转发导出

作用
把若干模块“转发”出去,做一个统一出口(barrel/index)。自己文件里不能直接使用转发来的成员;若要自用,再 @use 一次。

示例

/* design/_index.scss —— 聚合出口 */
@forward "../tokens/color" show $primary, btn;  // 只暴露想给外部用的成员
@forward "../tokens/spacing" as space-*;        // 导出时加前缀

/* app.scss —— 使用统一出口 */
@use "./design/index" as d;

.card {
  color: d.$primary;
  margin: d.$space-lg;
}

在出口处预配置主题(with)

/* design/_index.scss */
@forward "../tokens/color" with ($primary: #333);

注意:一个模块只能被配置一次。上游已通过 @forward ... with 配过,下游再配会报错。


五分钟速查表

能力/特性 @use @forward Sass @import "x" CSS @import url(...)
发生时机 编译期 编译期 编译期 运行时(浏览器请求)
命名空间 有(可 as * 去掉) 对外导出,不给本文件用 无(全局拼接)
去重加载 ❌ 可能重复 N/A(浏览器请求)
变量可配置 通过 with 配置 !default 通过 with 预配置并转发 通过“先定义后导入”覆盖(老做法)
全局污染
位置限制 任意 任意 任意(编译期) 顶部(在普通规则前)
适用场景 模块化使用 统一出口/SDK 旧项目遗留 引入纯 CSS(不推荐)

常见误区 & 快速排坑

  1. @import url('./variable.scss') 用后 $color 未定义

    • 这是 CSS 导入,不会带来 Sass 变量。
    • 用:@use "./variable" as v;color: v.$color;
  2. 我在文件里写 $primary: red,为啥 @use 来的变量没变?

    • @use 是模块隔离;你改的是当前文件$primary,不是模块里的。
    • 正确:@use "./tokens" with ($primary: red); 且源变量需 !default
  3. 去命名空间 as *@import 一样吗?

    • 不是。as * 只是省掉前缀,仍是模块系统(只加载一次、不污染全局)。
    • 有冲突风险:多个模块导出同名变量会报错。
  4. @forward 文件里用不了转发来的变量?

    • 对。@forward 只是出口;若当前文件要用,@use 一次
  5. 位置问题:为啥我的 @import 被忽略?

    • CSS 的 @import 必须在最顶部(普通规则之前)。Sass 旧式 @import 不限位置,但已经弃用。

迁移指北:从 @import@use/@forward

目录建议

styles/
  tokens/
    _color.scss     // 变量均加 !default
    _spacing.scss
  mixins/
    _typography.scss
  design/
    _index.scss     // 聚合出口(只 forward)
  app.scss          // 项目入口(只 use design)

改造步骤

  1. 给需要对外可配的变量都加 !default

  2. 建“总出口”:

    /* design/_index.scss */
    @forward "../tokens/color";
    @forward "../tokens/spacing";
    @forward "../mixins/typography";
    
  3. 入口使用:

    /* app.scss */
    @use "./design/index" as d with (
      $primary: #0052d9,
      $space-lg: 24px
    );
    
    .btn { color: d.$primary; margin: d.$space-lg; }
    
  4. 删除旧式 @import,逐步把业务文件改为 @use 指向 design/_index.scss


结语

  • 新项目:只用 @use + @forward
  • 做 SDK/设计系统:@forward 聚合成一个总入口,外部只 @use 它。
  • 变量可配:源头加 !default,引入处用 with
  • 避免 @import 与 CSS 的 @import url(...)(性能差、易踩坑)。

需要我按你的项目目录,直接给一份可跑的 @use/@forward 模板吗?把目录贴过来我就给你落地版。

JavaScript 严格模式

它是什么

给 JS 开个“较真模式”。一旦开启,JavaScript 会对一些原本“容忍/默默忽略”的危险写法直接抛错或改变行为,从而更早暴露 bug、更安全、更利于引擎优化。

为什么有意义

  • 更早发现错误:很多隐性 bug 当场报错,缩短排查时间。
  • 更安全:禁掉易被利用或难以理解的语法(如 witharguments.callee)。
  • 更一致:减少不同引擎下的歧义和历史包袱。
  • 更好优化:明确语义后,JS 引擎更容易做性能优化。

怎么开启

  • 在脚本或函数第一行写:"use strict";
  • ES6+ 模块与类默认就是严格模式;打包后的现代项目通常已经处于严格模式(多半不用手写这句)。

具体有什么变化(高频清单 + 例子)

  1. 禁止意外创建全局变量
"use strict";
function f() { x = 1 } // ReferenceError:x 未声明

(非严格下会悄悄变成 window.x

  1. 普通函数里的 this 不再自动指向全局
function f(){ return this }
f(); // 非严格: window/global;严格: undefined
  1. 参数名不能重复
function sum(a, a) {} // 严格: SyntaxError
  1. eval 变“隔离” (不再向外层注入变量)
"use strict";
eval("var x = 1;");
typeof x; // "undefined"
  1. 不能删除变量/函数/参数
"use strict";
var x = 1;
delete x; // SyntaxError
  1. 写入只读属性会抛错(非严格下静默失败)
"use strict";
const obj = {};
Object.defineProperty(obj, "id", { value: 1, writable: false });
obj.id = 2; // TypeError
  1. 禁用 with
"use strict";
with (obj) {} // SyntaxError
  1. 八进制字面量与转义受限
"use strict";
var n = 010; // SyntaxError(非严格下表示八进制 8)
  1. arguments 行为更“干净”
  • 不再和形参联动(改 arguments[0] 不会改到形参)。
  • 禁用 arguments.callee/arguments.caller(TypeError)。
  • 不能给 eval/arguments 赋值或作为变量名。
  1. 保留字更严格
    publicstatic(以及未来关键字)在严格模式下不可作为变量名。

什么时候我“已经在严格模式”?

  • 你用 ES modules (import/export)class:默认严格。
  • 现代打包工具(Webpack、Vite、Rollup)产物通常已严格。
  • 旧式 IIFE/脚本直连时,若没模块化,才可能需要手写 "use strict"

实战建议

  • 新项目/模块化项目:基本天然严格,无需额外处理。
  • 维护旧代码:可以按“文件或函数”为单位逐步加 "use strict",配合 eslint,把上面这些典型坑扫一遍。
  • 库作者:保持严格模式有助于用户环境一致性与可优化性。
❌