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()
同样能够传递 list
或 map
类型的参数,用法和后面一样。
缩进语法的 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;}