Sass 指令大致有以下 11 种
- @use:从其他样式表加载 mixins、函数、变量,并将不同的 css 样式表组合起来
- @forward:将模块成员暴露出去
- @import:导入 CSS、Sass文件
- @mixin、@include:样式快的复用
- @function:自定义可以在 SassScript 表达式中使用的函数
- @extend:选择器相互继承样式
- @at-root:可以用来放弃当前的嵌套层级,让其内部的 css 样式规则到根部
- @error:使Sass 将会停止编译并打印错误
- @warn:继续编译并打印警告
- @debug:可以用来在开发样式表时查看变量或表达式的值,它会打印出该表达式的值,以及文件名和行号
- @if、@each、@while:流控制。控制是否使用样式,以及使用样式的次数
如果 Sass 文件只打算作为模块加载,而不是自己编译,文件名以 _ 开头即可,这些被称为局部文件(partials),它们告诉 Sass 工具不要尝试自己编译这些文件。但是在导入这些模块时可以不用书写 _ 符号。
@use
使用 @use "<url>" 可以加载模块,以这种方式加载的任何样式时,只会在编译的 css 输出中包含一次。
@use 的前面只能出现 @forward 或 变量声明,其他的所有代码只能出现在 @use 之后。
// src/_corners.scss
$radius: 3px;
$-radius: 3px;
@mixin rounded {
border-radius: $radius;
}
修改命名空间
@use "<url>" as <namespace> 可以修改默认情况下的 namespace,甚至可以通过 @use "<url>" as * 去除命名空间(不建议,容易发生名称冲突)。
//style1.scss
@use "src/corners" as C;
.button {
@include C.rounded;
padding: 5px + C.$radius;
}
/************************************************************************/
//style2.scss
@use "src/corners" as *;
.button {
@include rounded;
padding: 5px + $radius;
}
加载成员
在使用 @use <url> 加载文件之后,可以分别通过 <namespace>.<variable> 、 <namespace>.<function>() 、@include <namespace>.<mixin>() 使用文件中的变量、函数、mixin。默认情况下,namespace 是 URL 最后的一个组成成分。
// style2.scss
@use "src/corners";
.button {
@include corners.rounded;
padding: 5px + corners.$radius;
}
私有成员
如果不想将模块中的成员暴露给其他文件访问,将模块成员以 - 或 _ 开头即可。
// style3.scss
@use "src/corners";
.button {
@include corners.rounded;
// 报错:模块的私有成员无法在模块外部使用
padding: 5px + corners.$-radius;
}
变量可配置
加载变量有默认值的模块时,可以通过 @use <url> with (<variable>: <value>,<variable>: <value>) 的方式修改变量的默认值。值得注意的是:模块在加载之后,也可以修改变量的值。
//_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;
}
// style.scss
@use 'library' with (
$black: #222,
$border-radius: 0.1rem
);
// _library.scss
$color: red;
// _override.scss
@use 'library';
library.$color: blue;
// style.scss
@use 'library';
@use 'override';
@debug library.$color; //=> blue
寻找模块
使用 @use 时,可以省略文件后缀名。
例如通过 @use "module" 使用模块时,不需要写扩展名,程序会自动查找:
- 查找
./module.scss,没有则进行下一步 - 查找
./module.sass,没有则进行下一步 - 查找
./module.css,没有则进行下一步 - 查找
node_modules/module/sass/module.scssindex文件:
如果在文件夹中有 _index.scss 或者 _index.sass ,则在加载该文件夹本身的URL时会自动加载索引文件。
@forward
使用 @forward "<url>" 可以把模块的成员暴露出去。
- 通过 @forward 加载的模块成员,不能在当前文件内访问,假如需要访问,使用 @use
- 当需要在一个文件中同时使用 @use 和 @forward 时,建议先写 @forward 再写 @use
添加前缀
通过 @forward "module" as xxx-* 可以给同一个模块中的成员统一添加前缀:
// src/_list.scss
@mixin reset {
margin: 0;
padding: 0;
list-style: none;
}
// bootstrap.scss
@forward "src/list" as list-*;
// styles.scss
@use "bootstrap";
li {
@include bootstrap.list-reset;
}
控制变量可见性
通过 @forward "<url>" hide <members...> 和 @forward "<url>" show <members...> 可以控制哪些变量隐藏(可见)。
// src/_list.scss
$horizontal-list-gap: 2em;
@mixin list-reset {
margin: 0;
padding: 0;
list-style: none;
}
@mixin list-horizontal {
@include list-reset;
li {
display: inline-block;
margin: {
left: -2px;
right: $horizontal-list-gap;
}
}
}
// bootstrap.scss
@forward "src/list" hide list-reset, $horizontal-list-gap;
配置变量
在转发模块时,可以对成员进行配置,修改默认值,或者指定一个确定的值均可。
// _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;
}
// _opinionated.scss
@forward 'library' with (
$black: #222 !default,
$border-radius: 0.1rem !default
);
// style.scss
@use 'opinionated' with ($black: #333);
@import
导入 Sass 或 CSS,使得文件中的 mixin、function、变量可访问,并且把样式联合起来。
与 CSS import 的区别
- css 中的
@import可以是一个线上 url 地址,浏览器会在运行时下载这个文件,而 sass 中的@import只能在编译打包阶段运行,所以在 sass 中只能导入一个本地存在的 sass/scss/css 文件; - scss 中允许写一个
@import导入多个文件,文件以逗号,分隔开即可,css 中必须每个文件写一个@import
在 sass 中导入 css 文件
-
编译时导入
不要显示地写出扩展名
.css,只写文件名即可/* a.css */ .a { color: #f00; } // index.scss @import "a.css"; .index { // 报错:The target selector was not found. // 目标选择器未找到 @extend .a; font-size: 16px; } -
运行时导入:
表示让编译器原封不动地输出
@import语句,而不是编译后替换掉它-
以
.css结尾 -
以
http://或https://开头 -
路径包含在
url()之中 -
语句中有媒体查询
@import "xxx.css"; @import "http://xxx.css"; @import url(xxx); @import "landscape" screen and (orientation: landscape);
-
@import 中使用插值:sass 中的 @import 语句是不支持使用插值的,因为这可能会让人不知道变量、函数、mixin 是从哪里来的。但是,对于纯css @import 语句却是可以使用插值的,可以用来动态生成纯 css 的 @import 语句。
@mixin get-font($family) {
@import url("http://xxx.com/#{$family}.css");
}
@include get-font("font-name");
@mixin and @include
@mixin 可以定义可重复使用的样式, @include 使用 @mixin 定义的样式。
@mixin 写法:@mixin <name> {...} 或者 @mixin <name> (<arguments>) {...} (带参数);
@include 写法:@include <name> 或者 @include <name> (<arguments>) (带参数),甚至可以是 @include <name> {...}
Mixin 名称和所有 Sass 标识符一样,将连字符和下划线视为相同。这意味着reset-list 和 reset_list都指的是同一个 mixin。
传参方式
一般情况下,@include 调用 @mixin 时,传递的参数个数必须保持一致。
-
默认值传值
通过定义默认值的形式,使该参数成为可选参数,如果未传递该参数,则将使用默认值
@mixin replace-text($image, $x: 50%, $y: 50%) { text-indent: -99999em; overflow: hidden; text-align: left; background: { image: $image; repeat: no-repeat; position: $x $y; } } .mail-icon { @include replace-text(url("/images/mail.svg"), 0); } -
名称传参
当传递参数的时候,除了可以根据位置传参,还可以根据名称传参。这对于具有多个可选参数的 mixin 或 布尔 参数特别有用,因为这些参数在没有名称的情况下意义不明显。
@mixin square($size, $radius: 0) { width: $size; height: $size; @if $radius != 0 { border-radius: $radius; } } .avatar { @include square(100px, $radius: 4px); } -
参数列表
如果
@mixin声明中的最后一个参数以...结尾,则该 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");任意数量参数时,也可以使用具名参数。通过
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, )同理,传递任意数量参数时,也可以使用
...传递参数列表。甚至可以利用这一特点为 mixin 定义别名。$form-selectors: "input.name", "input.address", "input.zip" !default; @include order(150px, $form-selectors...); @mixin btn($args...) { @warn "The btn() mixin is deprecated. Include button() instead."; @include button($args...); }
内容块
除了接收参数外,mixin 还可以接收整个样式块,称为内容块。内容块用 {} 传入,在 mixin 中代替 @content 内容。
@mixin hover {
&:not([disabled]):hover {
@content;
}
}
.button {
border: 1px solid black;
@include hover {
border-width: 2px;
}
}
内容块可以通过 @content(<arguments>) 接收参数,并通过 @include <name> using (<arguments>) 传递参数
@mixin media($types...) {
@each $type in $types {
@media #{$type} {
@content($type);
}
}
}
@include media(screen, print) using ($type) {
h1 {
font-size: 40px;
@if $type == print {
font-family: Calluna;
}
}
}
/************************************************************************/
// 编译后的 css
@media screen {
h1 {
font-size: 40px;
}
}
@media print {
h1 {
font-size: 40px;
font-family: Calluna;
}
}
@function and @return
使用 @function <name>(arguments...) {...} 语法可以在 scss 中定义函数。
一般情况下使用函数时,传递的参数个数必须与定义函数的参数个数一致。接收参数时,可以分为以下两种情况:
- 可选参数:通过定义参数默认值,使该参数称为可选参数(
变量名: SassScript 表达式),如果可选参数没有传值将使用默认值 - 具名参数:使用名称传递参数
- 参数列表:
@function声明中最后一个参数以...结尾,则改函数的所有额外参数都作为列表传递给该参数
在传递参数时,可以传递一个参数列表 ... 作为函数调用的最后一个参数,它将被视为额外的位置参数。
$widths: 50px, 30px, 100px;
.micro {
width: min($widths...);
}
/************************************************************************/
// 编译后的 css
.micro {
width: 30px;
}
@return 只能出现在 @function 的函数体中,并且 @function 必须以 @return 结尾。
@extend
@extend <selctor> 可以让一个选择器继承另一个选择器的样式,这种继承会保证两个选择器就像完全一样,如:
.error:hover {
background-color: #fee;
}
.error--serious {
@extend .error;
border-width: 3px;
}
/************************************************************************/
// 编译后的 css
.error:hover, .error--serious:hover {
background-color: #fee;
}
.error--serious {
border-width: 3px;
}
.content nav.sidebar {
@extend .info;
}
// This won't be extended, because `p` is incompatible with `nav`.
p.info {
background-color: #dee9fc;
}
// There's no way to know whether `<div class="guide">` will be inside or
// outside `<div class="content">`, so Sass generates both to be safe.
.guide .info {
border: 1px solid rgba(#000, 0.8);
border-radius: 2px;
}
// Sass knows that every element matching "main.content" also matches ".content"
// and avoids generating unnecessary interleaved selectors.
main.content .info {
font-size: 0.8em;
}
/************************************************************************/
// 编译后的 css
p.info {
background-color: #dee9fc;
}
.guide .info, .guide .content nav.sidebar, .content .guide nav.sidebar {
border: 1px solid rgba(0, 0, 0, 0.8);
border-radius: 2px;
}
main.content .info, main.content nav.sidebar {
font-size: 0.8em;
}
占位符选择器
以 % 开始的选择器称为占位符选择器,它可以用 @extend 扩展。没有使用 @extend 对占位符选择器进行扩展时,它不会被编译到 css 输出当中;当使用 @extend 进行扩展时,会被编译到扩展它们的选择器中。
当 @extend 无法找到匹配的选择器时, sass 将会报错。如果只是想在 @extend 扩展选择器不存在的情况下不执行任何操作,只需在末尾添加 !optional 即可。
@error
在编写带有参数的mixin和函数时,通常希望这些参数符合要求(强制性)。此时就可以用到 @error <expression> 达到该目的。当执行 @error 语句时,Sass 将会停止编译并打印错误。
@mixin reflexive-position($property, $value) {
@if $property != left and $property != right {
@error "Property #{$property} must be either left or right.";
}
$left-value: if($property == right, initial, $value);
$right-value: if($property == right, $value, initial);
left: $left-value;
right: $right-value;
[dir=rtl] & {
left: $right-value;
right: $left-value;
}
}
.sidebar {
@include reflexive-position(top, 12px);
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// Error: Property top must be either left or right.
}
@warn
在编写带有参数的mixin和函数时,通常希望这些参数符合要求(建议性)。此时就可以用到 @warn <expression> 达到该目的。当执行 @warn 语句时,Sass 会继续编译并打印警告。
$known-prefixes: webkit, moz, ms, o;
@mixin prefix($property, $value, $prefixes) {
@each $prefix in $prefixes {
@if not index($known-prefixes, $prefix) {
@warn "Unknown prefix #{$prefix}.";
}
-#{$prefix}-#{$property}: $value;
}
#{$property}: $value;
}
.tilt {
// Oops, we typo'd "webkit" as "wekbit"!
@include prefix(transform, rotate(15deg), wekbit ms);
}
@debug
@debug <expression> 可以用来在开发样式表时查看变量或表达式的值,它会打印出该表达式的值,以及文件名和行号。
@at-root
@at-root 可以用来放弃当前的嵌套层级,让其内部的 css 样式规则到根部。例如:
.parent{
color:red;
@at-root .child {
width:200px;
height:50px;
}
}
/************************************************************************/
// 编译后的 css
.parent {
color: red;
}
.child {
width: 200px;
height: 50px;
}
@at-root 默认情况下不会跳出 @media 或 @supports 等指令。例如:
@media print {
@at-root {
.foo {
color: green;
}
}
}
/************************************************************************/
// 编译后的 css
@media print {
.foo {
color: green;
}
}
如果想跳出指令,需要增加 without 语法。例如:
@media print {
.page {
width: 800px;
a {
color: red;
@at-root(without: media) {
span { color: #00f }
}
}
}
}
/************************************************************************/
// 编译后的 css
@media print {
.page {
width: 800px;
}
.page a {
color: red;
}
}
.page a span {
color: #00f;
}
可以看出 @at-root(without: media) 可以跳出 @media ,但是没有跳出父级选择器,如果我们想跳出 @media 和 父级嵌套,可以一次添加两个指令。
@media print {
.page {
width: 800px;
a {
color: red;
// media rule 可以省略为 all
@at-root (without: media rule) {
span {
color: #00f;
}
}
}
}
}
/************************************************************************/
// 编译后的 css
@media print {
.page {
width: 800px;
}
.page a {
color: red;
}
}
span {
color: #00f;
}
with 和 without 语法的关键词有以下可选值:
- all:表示所有
- rule:表示常规css
- media:表示media
- support:表示support
由此可以看出,默认的 @at-root 就是 @at-root(without:rule)
流程控制
@if 、 @else if 、 @else
@if <expression> {...} 、@else if <expression> {...} 、 @else {...} 。
注意 @if <expression> {...} 与 if(expression, value1, value2) 的区别
- @if <expression> {...}:根据
expression的真假决定大括号中的语句是否执行 - if(expression, value1, value2):根据
expression的真假决定取值,真值取value1, 假值取value2
sass 中为假值只有 false 和 null,其他的如:空字符串、0 都为真值。
@each
遍历 List 写法: @each <variable> in <expression> {...}
$sizes: 40px, 50px, 80px;
@each $size in $sizes {
.icon-#{$size} {
font-size: $size;
height: $size;
width: $size;
}
}
遍历 Map 写法: @each <key>,<value> in <expression> {...}
$icons: ("eye": "\f112", "start": "\f12e", "stop": "\f12f");
@each $name, $glyph in $icons {
.icon-#{$name}:before {
display: inline-block;
font-family: "Icon Font";
content: $glyph;
}
}
解构写法: @each <variable1,variable2,variable3...> in <expression> {...} :每个变量的值为相应位置的值,如果相应位置没有值,则变量的值为 null。
$icons:
"eye" "\f112" 12px,
"start" "\f12e" 16px,
"stop" "\f12f" 10px;
@each $name, $glyph, $size in $icons {
.icon-#{$name}:before {
display: inline-block;
font-family: "Icon Font";
content: $glyph;
font-size: $size;
}
}
@for
包含终止值:@for <variable> from <expression> through <expression> {...}
不包含终止值:@for <variable> from <expression> to <expression> {...}
$width: 5px;
@for $i from 1 to 3 {
.box#{$i} {
width: $width * $i;
}
}
@for $i from 1 through 3 {
.box#{$i} {
width: $width * $i;
}
}
@while
@while <expression> {...}
$whileVar: 1;
@while $whileVar < 3 {
.box#{$whileVar} {
width: $width * $whileVar;
}
$whileVar: $whileVar + 1;
}