Sass 根本介绍

[toc]

如果对本文有任何问题,倡议,或者在前端技术体系方面有任何问题,能够增加我的微信: drylint , 我会尽可能为你解答,也会拉你进入前端技术进阶交换群,大家一起提高~

Sass 是 CSS 的超集,反对所有 css 语法,并在其根底上扩大。

Sass 反对像 css 一样的大括号语法,文件扩大名为 .scss ,以及另一种应用缩进的语法,文件扩大名为 .sass

教程次要采取齐全兼容 css 的 SCSS 语法。

正文(Comments)

反对两种正文,别离是:

  • 单行正文 // 正文文字
  • 多行正文 /* 正文文字 */

单行正文(Single-line comments)

编译的时候会间接被疏忽,不会编译到 CSS 中,所以也叫做“隐式正文”(silent comments)。

// 正文内容

多行正文(Multi-line comments)

编译时会将正文编译到 css 中,所以也叫做“显式正文”(loud comment)

// 这一行正文不会呈现在编译的 css 中/* 这一行会呈现在编译的 css 中,除非是在压缩模式下则不会 *//* 正文中还能够蕴含插值: * 1 + 1 = #{1 + 1} *//*! 这行正文即便在压缩模式下也会编译到 css 中 */p /* 多行正文能够写在任何   * 容许空白呈现的中央 */ .sans {  font-size: 16px;}

编译后的 css:

/* 这一行会呈现在编译的 css 中,除非是在压缩模式下则不会 *//* 正文中还能够蕴含插值: * 1 + 1 = 2 *//*! 这行正文即便在压缩模式下也会编译到 css 中 */p .sans {  font-size: 16px;}

SassDoc

文档正文,相似于 jsdoc 。应用三斜线 /// 申明。

/// Computes an exponent.////// @param {number} $base///   The number to multiply by itself./// @param {integer (unitless)} $exponent///   The number of `$base`s to multiply together./// @return {number} `$base` to the power of `$exponent`.@function pow($base, $exponent) {  $result: 1;  @for $_ from 1 through $exponent {    $result: $result * $base;  }  @return $result;}

非凡的函数(Special Functions)

  • url()
  • xxx

url()

url() 函数在CSS中很罕用,然而它的语法与其余函数不同,它能够承受带引号的 url ,也能够承受不带引号的 url。因为未加引号的 URL 不是无效的 SassScript 表达式,所以 Sass 须要非凡的逻辑来解析它。

如果 url() 的参数是一个无效的无引号的 url ,Sass 会原样解析它,当然,插值也是能够用的。

如果参数不是一个无效的无援用的 url ,例如,如果它蕴含变量或函数调用,它将被解析为一般的 CSS 函数调用。

$roboto-font-path: "../fonts/roboto";@font-face {  // This is parsed as a normal function call that takes a quoted string.  src: url("#{$roboto-font-path}/Roboto-Thin.woff2") format("woff2");}@font-face {  // This is parsed as a normal function call that takes an arithmetic  // expression.  src: url($roboto-font-path + "/Roboto-Light.woff2") format("woff2");}@font-face {  // This is parsed as an interpolated special function.  src: url(#{$roboto-font-path}/Roboto-Regular.woff2) format("woff2");}

编译后的 css :

@font-face {  src: url("../fonts/roboto/Roboto-Thin.woff2") format("woff2");}@font-face {  src: url("../fonts/roboto/Roboto-Light.woff2") format("woff2");}@font-face {  src: url(../fonts/roboto/Roboto-Regular.woff2) format("woff2");}

calc()element()

calc()element() 函数是在 CSS 标准中定义的。因为 calc() 的数学表达式与 Sass 的算法抵触,而 element() 的id能够被解析为色彩,所以它们须要非凡的解析。

Sass 容许任何文本呈现在这些函数调用中,包含嵌套的圆括号。

除了能够应用插值来注入动静值会被编译解决。其余任何货色都不会被解释为 SassScript 表达式进行计算,而是原样输入。

progid:...()expression() 弃用

expression() 和以 progid: 结尾的函数是应用非标准语法的 Internet Explorer 遗留个性。只管最近的浏览器曾经不再反对它们,然而 Sass 持续解析它们以实现向后兼容。

min()max()

CSS在 CSS Values and Units Level 4 中减少了对 min()max() 函数的反对,Safari 很快就采纳了它们来反对 iPhoneX 。

然而 Sass 在很久以前就曾经有了本人的 min()max() 函数,为了向后兼容所有现有的样式表。这就须要额定的句法技巧来实现。

如果一个 min()max() 函数调用是无效的纯 CSS ,它将被编译为一般的 CSS 的 min()max() 函数调用。

"纯CSS "包含嵌套调用 calc()env()var()min() ,或 max() ,以及插值。

然而,只有调用的时候蕴含了 SassScript 个性(如变量或函数调用),它就会被认为是对 Sass 自带的 min()max() 函数的调用。

变量

在 Sass 中,申明变量必须以 $ 结尾。

$red: #f00;div {  color: $red;}

编译后的 css :

div {  color: #f00;}

Sass 变量和 css 变量的区别:

  • Sass 变量会被编译成实在的值而后输入为 css ,也就是仅仅存在于开发阶段。
  • CSS 变量对于不同的元素能够有不同的值,然而 Sass 变量一次只有一个值。
  • Sass 变量是不可逆的,这意味着如果您应用了一个变量,而后在前面更改了它的值,那么之前的应用将仍然放弃不变。CSS 变量是申明性的,这意味着如果在前面更改了值,它将影响后面的应用和当前的应用。

留神:和所有的 Sass 标识符一样,Sass 变量将连字符 - 和下划线 _ 视为雷同的字符。这意味着 $font-size$font_size 都指向同一个变量。这是 Sass 晚期的历史遗留,过后它只容许在标识符名称中应用下划线。起初, Sass 减少了对连字符的反对,以匹配 CSS 的语法,sass 将这两个字符视为等效解决,以便于使迁徙更加容易。

默认值

比方开发一个库,用户能够抉择是否传递自定义的值,如果没有传递则应用默认值。

为了实现这一点,Sass 提供了 !default 标记。只有当变量没有定义或者它的值为 null 时,才会给该变量赋值。否则,将应用默认的值。

配置模块变量

!default 定义的变量,能够在应用 @use 规定加载模块时配置。

在模块中申明变量,并定义默认值:

// _library.scss$black: #000 !default;$border-radius: 0.25rem !default;$box-shadow: 0 0.5rem 1rem rgba($black, 0.15) !default;code {  border-radius: $border-radius;  box-shadow: $box-shadow;}

在援用模块时,抉择要自定义值的变量,疏忽的变量则应用默认值:

// index.scss@use 'library' with (  $black: #222,  $border-radius: 0.1rem);

内置变量

内置模块定义的变量是无奈被批改的。

比方,上面代码视图批改内置变量,但不会胜利:

@use "sass:math" as math;// This assignment will fail.math.$pi: 0;

作用域

在 css 文件顶层申明的变量是全局变量,申明后能够在模块中的任何中央被拜访。

在块({})中申明的变量是局部变量,只能在申明它们的块内拜访。

// 全局变量$red: #f00;div {  // 局部变量  $black: #000;  color: $red;}p {  // 在这里援用局部变量编译时会报错  color: $black;}

当局部变量和全局变量重名时,不会笼罩全局变量,而是同时存在,在哪个作用域拜访的就是哪个变量。

$red: #f00;div {  $red: #f55;  color: $red;}p {  color: $red;}

编译后的 css :

div {  color: #f55;}p {  color: #f00;}

如果想用一个局部变量去笼罩全局变量,也就是在块中批改全局变量的值,能够应用 !global 来实现:

$red: #f00;div {  // !global 将批改全局变量的值,而不是在块中新建一个部分作用域  $red: #f55 !global;  color: $red;}p {  color: $red;}
div {  color: #f55;}p {  color: #f55;}

留神:如果应用 !global 的变量不是一个全局变量,则编译时会报错。

在流程管制语句(@if/@each/@for/@while 等)中申明的变量有一个本人的非凡作用域,它不会创立新变量去笼罩同级作用域中的同名变量,而是简略地进行原变量的赋值批改操作。

$dark-theme: true;$red: #e55;$black: #333;@if $dark-theme {  $red: #f00;  $black: #000;}.button {  background-color: $red;  color: $black;}

编译后的 css :

.button {  background-color: #f00;  color: #000;}

在流程管制语句中,赋值给曾经存在的变量则是批改操作,如果是不存在的变量则会创立一个新的变量,但这个新的变量也只能在这个流程管制语句的作用域中应用。

检测变量是否存在

Sass 外围库提供了两个用于解决变量的高级函数。meta.variable-exists() 函数返回给定名称的变量是否在以后作用域中存在, meta.global-variable-exists() 函数做同样的事件,但仅用于全局作用域。

@debug meta.variable-exists("var1"); // false$var1: value;@debug meta.variable-exists("var1"); // trueh1 {  // $var2 is local.  $var2: value;  @debug meta.variable-exists("var2"); // true}
@debug meta.global-variable-exists("var1"); // false$var1: value;@debug meta.global-variable-exists("var1"); // trueh1 {  // $var2 is local.  $var2: value;  @debug meta.global-variable-exists("var2"); // false}

用户有时可能会心愿应用插值来定义基于另一个变量的变量名。Sass 不容许这样做,因为它使得咱们很难一眼就晓得哪些变量在哪里定义。然而,您能够做的是定义一个从名称到值的 map,而后您能够应用变量拜访该映射。

@use "sass:map";$theme-colors: (  "success": #28a745,  "info": #17a2b8,  "warning": #ffc107,);.alert {  // Instead of $theme-color-#{warning}  background-color: map.get($theme-colors, "warning");}

编译后的 css :

.alert {  background-color: #ffc107;}

插值(Interpolation)

插值简直能够在 Sass 样式表的任何中央应用,以将 SassScript 表达式的后果嵌入到 CSS 块中。

#{} 中搁置一个表达式即可,比方能够用在:

  • 选择器
  • 属性名
  • 自定义属性值
  • CSS 的 @ 语句中
  • @extends
  • CSS @imports
  • 字符串
  • 非凡函数
  • CSS 函数名
  • 保留正文(Loud comments ) /* ... */

上面展现局部用法,在选择器,属性,继承,正文语句中应用插值:

$selector: "hello";$color: "color";/* selector: #{$selector} */.#{$selector} {  background-#{$color}: #f00;}.#{$selector}-2 {  @extend .#{$selector};  border-#{$color}: #f00;}
/* selector: hello */.hello,.hello-2 {  background-color: #f00;}.hello-2 {  border-color: #f00;}

在 SassScript 中,能够应用插值表达式将 SassScript 注入到未加引号的字符串中。这在动静生成名称(例如动画)或应用斜杠分隔值时特地有用。

留神: SassScript 中的插值永远返回一个未加引号的字符串,在下面的例子中曾经看到了。

插值对于将值注入到字符串中很有用,但除此之外,在 SassScript 表达式中很少须要插值。

比方,应用变量齐全不须要这样写: color: #{$red} ,而是能够间接应用变量: color: $red

留神:不应该应用插值插入数字。因为插值总是返回未加引号的字符串,返回值并不能进一步用于计算,这也同时防止了违反 Sass 内置的的平安爱护规定,以确保可能正确应用单位。

Sass 有弱小的单位运算,你能够应用它来代替。例如,与其写 #{$width}px ,不如写 $width * 1px,或者更好的是,以px结尾申明$width变量。这样,$width 曾经有单位,你将失去一个很好的谬误音讯,而不是编译伪造的CSS。

还有,尽管能够应用插值将带引号的字符串转换为不带引号的字符串,但应用 string.unquote() 函数会更分明。所以应该用 string.unquote($string) 来代替 #{$string}

@语句(At-Rules)

Sass 在 CSS 之上增加了新的 @ 语句 :

  • @mixin@include 用于复用大的块级款式
  • @function 申明自定义函数,用于 SassScript 表达式中
  • @extend 用于在一个选择器中继承另一个选择器的款式
  • @at-root 将代码块外部的款式编译到 css 最外层(相当于顶级作用域)
  • @error 成心使编译失败而中断,并抛出错误信息
  • @warn 抛出一条错误信息但不使编译程序失败而中断
  • @debug 抛出一条用于 debug 调试的音讯
  • @if, @each, @for, @while 流程管制语句

@mixin and @include

@mixin 用于定义要复用的款式块,@include 用于调用这些款式块。

因历史遗留起因,mixin 的名字和 Sass 标识符一样,连字符(hyphens) - 和下划线(underscores)_ 被视为完全相同。

定义 mixin 的语法:

// 不须要传参数时,复用固定的款式代码@mixin <name> {  // ...}// 或// 须要应用时传递参数,动静复用款式代码@mixin name(arg1, arg2, ..., argN) {  // ...}

应用 mixin 的语法:

@include <name>;// 或@include <name>(arg1, arg2, ...)

应用示例:

// a.scss@mixin input {  padding: 10px;  color: #333;}@mixin button ($color, $fontSize) {  color: $color;  font-size: $fontSize;}
@use "a";.input {  @include a.input;}.button {  @include a.button(#333, 20px);}

编译后的 css :

.input {  padding: 10px;  color: #333;}.button {  color: #333;  font-size: 20px;}

通常状况下,如果一个 mixin 定义时有多少个参数,那么在调用时必须传递雷同数量的参数,除非是定义 mixin 时应用了参数默认值。

mixin 参数默认值

定义一个参数默认值就像定义一个变量一样,参数名后加一个冒号,而后就能够写默认值了。

@mixin button ($color, $fontSize: 16px) {  color: $color;  font-size: $fontSize;}.button {  @include button(#f00);}

编译后的 css :

.button {  color: #f00;  font-size: 16px;}

默认参数值能够是任意 Sass 表达式,甚至是它后面的参数。

@mixin font ($size, $weight: if($size >= 24px, 600, 400)) {  font-size: $size;  font-weight: $weight;}.div1 {  @include font(16px);}.div2 {  @include font(24px);}

编译后的 css :

.div1 {  font-size: 16px;  font-weight: 400;}.div2 {  font-size: 24px;  font-weight: 600;}

关键词传参

默认状况下,调用 mixin 时传递的参数程序必须和定义时的参数一一对应。

如果传递参数时指定参数关键词,则能够不依照定义的程序来传参。

@mixin font ($weight, $size) {  font-size: $size;  font-weight: $weight;}.div1 {  @include font($size: 16px, $weight: 500);}

编译后的 css :

.div1 {  font-size: 16px;  font-weight: 500;}

留神,如果要传递不带关键词的参数,则它必须呈现在关键词参数之前。

任意数量的参数

如果 mixin 的最初一个参数名以 ... 结尾,那么这个参数就能够接管传递过去的任意数量的参数,这个参数的值则会是一个列表。

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

编译后的 css :

input.name {  position: absolute;  height: 150px;  margin-top: 0;}input.address {  position: absolute;  height: 150px;  margin-top: 150px;}input.zip {  position: absolute;  height: 150px;  margin-top: 300px;}

带有关键字的任意参数

如果调用 mixin 带了关键字,那么任意参数须要应用 meta.keywords() 来解决,解决后将返回一个 map 类型的数据。

如果没有将任意参数传递给 meta.keywords() 函数,那么这个任意参数列表就不容许接管带有关键词的参数,编译程序会报错。

@use "sass:meta";@mixin syntax-colors($args...) {  @debug meta.keywords($args);  // (string: #080, comment: #800, variable: #60b)  @each $name, $color in meta.keywords($args) {    pre span.stx-#{$name} {      color: $color;    }  }}@include syntax-colors(  $string: #080,  $comment: #800,  $variable: #60b,)
pre span.stx-string {  color: #080;}pre span.stx-comment {  color: #800;}pre span.stx-variable {  color: #60b;}

传递任意参数

接管的任意参数能够是一个列表(list),那么,也能够把一个列表作为任意参数传递,同样只须要在前面加上 ... 即可。

$font: 16px, 600, #f00;@include font($font...);

同样,也能够把一个 map 作为任意参数传递:

@mixin font ($size, $weight) {  font-size: $size;  font-weight: $weight;}$font: (  weight: 600,  size: 16px,);.div1 {  @include font($font...);}

编译后的 css :

.div1 {  font-size: 16px;  font-weight: 600;}

@content 款式块

除了承受参数之外,mixin 还能够承受整个款式块,称为内容块。

在 mixin 中,在款式块中写一个 @content 来申明这个地位承受一个内容块,传递一个款式块给 mixin,这个款式块的内容将会用来替换 @content

@mixin font ($size, $weight) {  font-size: $size;  font-weight: $weight;  @content;}$font: (  weight: 600,  size: 16px,);.div1 {  @include font($font...) {    font-family: sans-serif;  }}

编译后的 css :

.div1 {  font-size: 16px;  font-weight: 600;  font-family: sans-serif;}

能够书写多个 @content; ,这样将会编译生成多个接管到的款式块。

传递的款式块是有作用域限度的,只能拜访款式块所处的地位的变量,而不能去拜访 mixin 定义的作用域的变量。

如果要让款式块应用 mixin 定义的作用域的变量,则须要通过 @content() 传递给款式块。

应用 `@content 时传参

传参应用 @content(arg1, arg2, ...) ,接管应用 @include <name> using ($arg1, $arg2, ...)

@mixin font ($size, $weight) {  font-size: $size;  font-weight: $weight;  @content(#f00, $size * 2);}$font: (  weight: 600,  size: 16px,);.div1 {  @include font($font...) using ($color, $margin) {    font-family: sans-serif;    color: $color;    margin: $margin;  }}

编译后的 css :

.div1 {  font-size: 16px;  font-weight: 600;  font-family: sans-serif;  color: #f00;  margin: 32px;}

@content() 同样能够传递 listmap 类型的参数,用法和后面一样。

缩进语法的 mixin

缩进语法的 Sass 能够应用 = 来定义一个mixin,而后应用 + 来应用一个 mixin,但很不直观,不倡议应用。

@at-root

通常用于嵌套的选择器中,在选择器前写下 @at-root 语句,用于将该选择器编译到样式表的最外层,而不是嵌套所在的地位。

.div1 {  color: #f00;  .div2 {    color: #0f0;    // 将 .div3 编译到最外层    @at-root .div3 {      color: #00f;    }  }}

编译后的 css :

.div1 {  color: #f00;}.div1 .div2 {  color: #0f0;}.div3 {  color: #00f;}

联合 mixin 来应用:

@use "sass:selector";@mixin unify-parent($child) {  @at-root #{selector.unify(&, $child)} {    font-size: 16px;    @content;  }}.wrapper .field {  @include unify-parent("input") {    color: #f00;  }  @include unify-parent("select") {    color: #0f0;  }}

编译后的 css :

.wrapper input.field {  font-size: 16px;  color: #f00;}.wrapper select.field {  font-size: 16px;  color: #0f0;}

@at-root 还有另一种写法 @at-root { ... }

.div1 {  font-size: 16px;  @at-root {    .div2 {      color: #f00;    }    .div3 {      color: #0f0;    }  }}

编译后的 css :

.div1 {  font-size: 16px;}.div2 {  color: #f00;}.div3 {  color: #0f0;}

解决款式之外的货色

默认状况下, @at-root 只会解决一般款式规定, 其余像是 @media@supports 等将会被丢掉。

应用 @at-root (with: <rules...>) { ... }@at-root (without: <rules...>) 来通知 Sass 在编译的时候是否包含一些指定的规定。

除了非法的 @语句的名称,如 @media 中的 media,还有两个非凡的值能够在查问中应用:

  • rule 指的是款式规定。例如,@at-root (with: rule) 不保留 @ 语句,但保留款式规定。
  • all 指所有 @语句 和 style 规定。
@media screen and (min-width: 900px) {  .page {    width: 100px;    @at-root (with: media) {      /* @at-root (with: media) */      .div1 {        font-size: 16px;      }    }    @at-root (without: media) {      .div2 {        /* @at-root (without: media) */        color: #111;      }    }    @at-root (with: rule) {      .div3 {        /* @at-root (with: rule) */        color: #111;      }    }    @at-root (without: rule) {      .div4 {        /* @at-root (without: rule) */        color: #111;      }    }    @at-root (with: all) {      .div5 {        /* @at-root (with: all) */        color: #111;      }    }    @at-root (without: all) {      .div6 {        /* @at-root (without: all) */        color: #111;      }    }  }}

编译后的 css :

@media screen and (min-width: 900px) {  .page {    width: 100px;  }  /* @at-root (with: media) */  .div1 {    font-size: 16px;  }}.page .div2 {  /* @at-root (without: media) */  color: #111;}.page .div3 {  /* @at-root (with: rule) */  color: #111;}@media screen and (min-width: 900px) {  .div4 {    /* @at-root (without: rule) */    color: #111;  }}@media screen and (min-width: 900px) {  .page .div5 {    /* @at-root (with: all) */    color: #111;  }}.div6 {  /* @at-root (without: all) */  color: #111;}