变量

  1. $base-color: #c6538c;
  2. $border-dark: rgba($base-color, 0.88);
  3. .alert {
  4. border: 1px solid $border-dark;
  5. }

⚠️注意

CSS 有自己的变量,它们与 Sass 变量完全不同。差异:

  • Sass 变量都被 Sass 编译掉了。CSS 变量包含在 CSS 输出中。
  • CSS 变量对于不同的元素可以具有不同的值,但 Sass 变量一次只有一个值。
  • Sass 变量是必不可少的,这意味着如果您使用变量然后更改其值,则较早的使用将保持不变。CSS 变量是声明性的,这意味着如果更改该值,它将影响早期使用和以后的使用。
  1. $variable: value 1;
  2. .rule-1 {
  3. value: $variable;
  4. }
  5. $variable: value 2;
  6. .rule-2 {
  7. value: $variable;
  8. }

💡有趣的事实

与所有 Sass 标识符一样,Sass 变量将连字符和下划线视为相同。这意味着,$font-size$font_size 既指代相同的变量。这是 Sass 早期的历史遗留,当时它只允许标识符名称中的下划线。一旦 Sass 添加了对连字符的支持以匹配 CSS 的语法,这两者就相当于使迁移更容易。

默认值

通常,当您为变量赋值时,如果该变量已有值,则会覆盖其旧值。

  1. // _library.scss
  2. $black: #000 !default;
  3. $border-radius: 0.25rem !default;
  4. $box-shadow: 0 0.5rem 1rem rgba($black, 0.15) !default;
  5. code {
  6. border-radius: $border-radius;
  7. box-shadow: $box-shadow;
  8. }
  1. // style.scss
  2. $black: #222;
  3. $border-radius: 0.1rem;
  4. @import 'library';

作用域

在样式表顶层声明的变量是全局变量。这意味着它们可以在声明之后的任何地方访问,甚至可以在另一个样式表中访问。但对于所有变量而言并非如此,在块中声明的那些(SCSS 中的花括号或 Sass 中的缩进代码)通常是本地的,并且只能在声明它们的块中访问。

  1. $global-variable: global value;
  2. .content {
  3. $local-variable: local value;
  4. global: $global-variable;
  5. local: $local-variable;
  6. }
  7. .sidebar {
  8. global: $global-variable;
  9. }

如果需要在局部作用域内设置全局变量的值,则可以使用 !global。标记为的变量声明 !global 将改变全局变量。该 !global 标志只能用于设置已在定义的全局变量,不能用于声明新的全局变量。

  1. $variable: first global value;
  2. .content {
  3. $variable: second global value !global;
  4. value: $variable;
  5. }
  6. .sidebar {
  7. value: $variable;
  8. }

控制语句的作用域

@if 语句中不能声明变量,必须在使用之前定义。

高级变量函数

variable-exists() 当前局部作用域是否有该变量,global-variable-exists() 当前作用域是否有该全局变量。

从变量对象中取出一个键的值使用。

  1. $theme-colors: (
  2. "success": #28a745,
  3. "info": #17a2b8,
  4. "warning": #ffc107,
  5. );
  6. .alert {
  7. background-color: map-get($theme-colors, "warning");
  8. }

插值

插值几乎可以在 Sass 样式表中的任何位置使用,以将 SassScript 表达式的结果嵌入到 CSS 中。

使用插值使用变量,color: #{$accent} 而不是写作 color: $accent

不要使用数字插值,因为插值返回不带引号的字符串,不能用于任何进一步的数学运算,它避免了 Sass 的内置安全措施,以确保正确使用单位。使用 $width * 1px 而不是 #{$width}px

功能

@import

扩展了 CSS 的 @import 规则,能够导入 Sass 和 CSS 样式表,提供对 mixin,函数和变量的访问,并将多个样式表的 CSS 组合在一起。与纯 CSS 导入不同,后者需要浏览器在呈现页面时发出多个 HTTP 请求,因此 Sass 导入在编译期间完全处理。

查找文件

不必明确写出要导入的文件的扩展名; @import "variables" 会自动加载 variables.scssvariables.sassvariables.css

⚠️注意

为确保样式表适用于每个操作系统,Sass 按 URL 而不是文件路径导入文件。这意味着即使在 Windows 上,也需要使用正斜杠而不是反斜杠。

加载路径

所有 Sass 实现都允许用户提供加载路径:Sass 在解析导入时将查看的文件系统上的路径。例如,如果您node_modules/susy/sass 作为加载路径传递,则可以使用 @import "susy" 加载 node_modules/susy/sass/susy.scss

但是,始终会首先相对于当前文件解析导入。仅当不存在与导入匹配的相对文件时,才会使用加载路径,确保在添加新库时不会意外地弄乱相对导入。

💡有趣的事实

与其他一些语言不同,Sass 不要求您使用 ./ 相对导入。相对入口始终可用。

片段

_ 开头的 sass 文件不会被编译,而是在导入时编译。

嵌套

可以嵌套在样式规则或简单的 CSS 规则 中,导入的 CSS 嵌套在该上下文中,使得嵌套导入可用于将一大块 CSS 定义到特定元素或媒体查询。请注意,嵌套导入中定义的顶级 mixins,函数和变量仍然是全局定义的。

  1. // _theme.scss
  2. pre, code {
  3. font-family: 'Source Code Pro', Helvetica, Arial;
  4. border-radius: 4px;
  5. }
  1. // style.scss
  2. .theme-sample {
  3. @import "theme";
  4. }

💡有趣的事实

嵌套导入对于确定第三方样式表的范围非常有用,但如果您是要导入的样式表的作者,通常最好在 mixin 中编写样式并在嵌套上下文中包含该 mixin。mixin 可以以更灵活的方式使用,并且在查看导入的样式表时如何使用它更清晰。

⚠️注意

嵌套导入中的 CSS 被评估为 mixin 这意味着任何父选择器都将引用样式表嵌套的选择器。

  1. // _theme.scss
  2. ul li {
  3. $padding: 16px;
  4. padding-left: $padding;
  5. [dir=rtl] & {
  6. padding: {
  7. left: 0;
  8. right: $padding;
  9. }
  10. }
  11. }
  1. // style.scss
  2. .theme-sample {
  3. @import "theme";
  4. }

导入 CSS

除了导入 .sass.scss 文件,Sass 还可以导入普通的旧 .css 文件。唯一的规则是导入不能明确包含 .css 扩展名,因为它用于表示纯CSS @import

  1. // code.css
  2. code {
  3. padding: .25em;
  4. line-height: 0;
  5. }
  1. // style.scss
  2. @import 'code';

Sass 导入的 CSS 文件不允许任何特殊的 Sass 功能。为了确保作者不会在 CSS 中不小心写 Sass ,所有不是有效 CSS 的 Sass 功能都会产生错误。

纯 CSS @import

纯 CSS @import 有以下情况:

  • 以 .css 后缀名导入的文件。
  • http://https:// 的文件。
  • url() 函数导入。
  • 具有媒体查询的文件。
  1. @import "theme.css";
  2. @import "http://fonts.googleapis.com/css?family=Droid+Sans";
  3. @import url(theme);
  4. @import "landscape" screen and (orientation: landscape);

插值

虽然 Sass 导入不能使用插值(以确保始终可以告诉 mixins,函数和变量来自哪里),但纯 CSS 导入可以。这使得可以动态地生成导入,例如基于 mixin 参数。

  1. @mixin google-font($family) {
  2. @import url("http://fonts.googleapis.com/css?family=#{$family}");
  3. }
  4. @include google-font("Droid Sans");

@mixin 和 @include

Mixins 允许您定义可在整个样式表中重复使用的样式。它们可以很容易地避免使用非语义类 .float-left,并在库中分发样式集合。

参数

Mixins 还可以接受参数,这样就可以在每次调用时自定义它们的行为。mixin 必须以 SassScript 表达式的形式包含相同数量的参数。这些表达式的值在 mixin 的主体中可用作相应的变量。

  1. @mixin rtl($property, $ltr-value, $rtl-value) {
  2. #{$property}: $ltr-value;
  3. [dir=rtl] & {
  4. #{$property}: $rtl-value;
  5. }
  6. }
  7. .sidebar {
  8. @include rtl(float, left, right);
  9. }

可选参数

  1. @mixin replace-text($image, $x: 50%, $y: 50%) {
  2. text-indent: -99999em;
  3. overflow: hidden;
  4. text-align: left;
  5. background: {
  6. image: $image;
  7. repeat: no-repeat;
  8. position: $x $y;
  9. }
  10. }
  11. .mail-icon {
  12. @include replace-text(url("/images/mail.svg"), 0);
  13. }

关键字参数

在声明 mixin 时的语法与可选参数没有什么不同,只是在使用时需要传入与形式参数相同的名称。

  1. @mixin square($size, $radius: 0) {
  2. width: $size;
  3. height: $size;
  4. @if $radius != 0 {
  5. border-radius: $radius;
  6. }
  7. }
  8. .avatar {
  9. @include square(100px, $radius: 4px);
  10. }

注意
因为任意参数都可以作为名称传递,所以在重命名 mixin 参数时,要将传入原参数名的行为打印警告,以通知他们使用新的参数名称。

任意数量的参数

  1. @mixin order($height, $selectors...) {
  2. @for $i from 0 to length($selectors) {
  3. #{nth($selectors, $i + 1)} {
  4. position: absolute;
  5. height: $height;
  6. margin-top: $i * $height;
  7. }
  8. }
  9. }
  10. @include order(150px, "input.name", "input.address", "input.zip");

传入的剩余参数将作为参数列表传给 $selectors

你可以这样实现 mixin 重命名

  1. @mixin btn($args...) {
  2. @warn "The btn() mixin is deprecated. Include button() instead.";
  3. @include button($args...);
  4. }

内容块

  1. @mixin hover {
  2. &:not([disabled]):hover {
  3. @content;
  4. }
  5. }
  6. .button {
  7. border: 1px solid black;
  8. @include hover {
  9. border-width: 2px;
  10. }
  11. }

⚠️注意

在内容块中使用变量必须提前定义。

@function

抽象公式和行为。

  1. @function pow($base, $exponent) {
  2. $result: 1;
  3. @for $_ from 1 through $exponent {
  4. $result: $result * $base;
  5. }
  6. @return $result;
  7. }
  8. .sidebar {
  9. float: left;
  10. margin-left: pow(4, 3) * 1px;
  11. }

@return

它只能在 @function 体内使用,每个 @function 必须以 @return 结束。

@extend

  1. .error:hover {
  2. background-color: #fee;
  3. }
  4. .error--serious {
  5. @extend .error;
  6. border-width: 3px;
  7. }

规则

@extend 可以拓展选择器的样式规则

  • 永远不会生成 #main#footer 这样的选择器。
  • 确保复杂选择器无论怎么嵌套都能工作。
  • 尽可能除去冗余选择器,同时确保选择器的准确性。
  • 合并相同规则的选择器。
  • 智能地处理组合器,通用选择器和包含选择器的伪类。
  1. .content nav.sidebar {
  2. @extend .info;
  3. }
  4. // 不会拓展,因为 p 和 nav 不能同时存在
  5. p.info {
  6. background-color: #dee9fc;
  7. }
  8. // 无法确定 .guide 和 .content 的包含关系,所以 SASS 将两个都生成了
  9. .guide .info {
  10. border: 1px solid rgba(#000, 0.8);
  11. border-radius: 2px;
  12. }
  13. // main.content 存在 main.content nav.sidebar 必然存在
  14. main.content .info {
  15. font-size: 0.8em;
  16. }

强制和可选扩展

@extend 必须匹配到选择器,否则会产生错误。如果想让拓展是可选的,在末尾加上 !optional

@media

不能在 @media 中使用 @extend

@error

在编写带有参数的 mixin 和函数时,需要确保参数具有所期望的类型和格式。如果不是,则通知用户并且您的 mixin / function 停止运行。

  1. @mixin reflexive-position($property, $value) {
  2. @if $property != left and $property != right {
  3. @error "Property #{$property} must be either left or right.";
  4. }
  5. $left-value: if($property == right, initial, $value);
  6. $right-value: if($property == right, $value, initial);
  7. left: $left-value;
  8. right: $right-value;
  9. [dir=rtl] & {
  10. left: $right-value;
  11. right: $left-value;
  12. }
  13. }
  14. .sidebar {
  15. @include reflexive-position(top, 12px);
  16. // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  17. // Error: Property top must be either left or right.
  18. }

@warn

在编写 mixin 和函数时,阻止用户传递某些参数或某些值。它们可能正在传递现已弃用的旧参数,或者它们可能以不太理想的方式调用 API。

  1. $known-prefixes: webkit, moz, ms, o;
  2. @mixin prefix($property, $value, $prefixes) {
  3. @each $prefix in $prefixes {
  4. @if not index($known-prefixes, $prefix) {
  5. @warn "Unknown prefix #{$prefix}.";
  6. }
  7. -#{$prefix}-#{$property}: $value;
  8. }
  9. #{$property}: $value;
  10. }
  11. .tilt {
  12. // Oops, we typo'd "webkit" as "wekbit"!
  13. @include prefix(transform, rotate(15deg), wekbit ms);
  14. }

@debug

开发样式表时查看变量或表达式的值, @debug 打印该表达式的值,以及文件名和行号。

  1. @mixin inset-divider-offset($offset, $padding) {
  2. $divider-offset: (2 * $padding) + $offset;
  3. @debug "divider offset: #{$divider-offset}";
  4. margin-left: $divider-offset;
  5. width: calc(100% - #{$divider-offset});
  6. }

@at-root

selector-unify() 函数一起使用表示使用根选择器作为 & 的值。

  1. @mixin unify-parent($child) {
  2. @at-root #{selector-unify(&, $child)} {
  3. @content;
  4. }
  5. }
  6. .wrapper .field {
  7. @include unify-parent("input") {
  8. /* ... */
  9. }
  10. @include unify-parent("select") {
  11. /* ... */
  12. }
  13. }

使用 with 或者 without 告诉 @at-root 排除哪些规则。

  1. @media print {
  2. .page {
  3. width: 8in;
  4. @at-root (without: media) {
  5. color: #111;
  6. }
  7. @at-root (with: rule) {
  8. font-size: 1.2em;
  9. }
  10. }
  11. }

除了 at-rules 的名称之外,还有两个可以在查询中使用的特殊值:

  • rule 指的是风格规则。例如,@at-root (with: rule) 排除所有 at-rules 但保留样式规则。
  • all 指的是所有的规则和风格规则都应该被排除在外。

流程控制

@if 和 @else

falsenull 在 Sass 中是假,空字符串、空列表和数字 0 在 Sass 中都是真。

@each

解构

  1. $icons:
  2. "eye" "\f112" 12px,
  3. "start" "\f12e" 16px,
  4. "stop" "\f12f" 10px;
  5. @each $name, $glyph, $size in $icons {
  6. .icon-#{$name}:before {
  7. display: inline-block;
  8. font-family: "Icon Font";
  9. content: $glyph;
  10. font-size: $size;
  11. }
  12. }

@for

使用 to 排除最后的数字,使用 through 包含最终数字。

  1. $base-color: #036;
  2. @for $i from 1 through 3 {
  3. ul:nth-child(3n + #{$i}) {
  4. background-color: lighten($base-color, $i * 5%);
  5. }
  6. }

参考

【1】Sass 官网文档