共计 11642 个字符,预计需要花费 30 分钟才能阅读完成。
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"); // true
h1 {
// $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"); // true
h1 {
// $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;
}