我以为已经会了,之前在公司写项目基本都是用sass
写样式,十分顺手。直到有段时间,我准备参考Element Plus
来设计自己组件库的工程结构,看到Element Plus
那些优雅的sass
用法时,我开始为我的浅薄和无知感到羞愧。这便开始系统学习sass
,期间多次想写点学习分享,却都因各种事情而无疾而终。时至今日,终于忙里偷闲有点时间,正好与君共勉。
一、简介
作为一款极其成熟的css
预处理器,sass
具有不少特色功能,帮助我们写出更为优雅、简洁的样式代码。它在css
之前引入了样式变量,还支持嵌套、函数、混合、指令控制等功能,极大地拓展了样式玩法。
sass
有两种语法格式:SCSS
和Sass
。
其中SCSS
是目前使用较多的一种格式,它仅在CSS3
的语法基础上进行拓展,加入了Sass
的特有功能,支持绝大多数的CSS hacks
写法以及浏览器前缀写法(vendor-specific syntax
),它的文件以.scss
作为拓展名。
而Sass
是最早的语法格式,用缩进代替花括号,用换行代替分号,格式尤为简洁,书写也更加方便。这种格式也支持Sass
的所有功能,不过在个别地方与SCSS
采用了不同的表达方式,它的文件拓展名为.sass
。
任何一种格式都可以 导入(@import) 到另一种格式的文件中使用,也可以通过sass-convert
命令行工具转化为另一种格式。
# Sass转为SCSS
sass-convert style.sass style.scss
# SCSS转为Sass
sass-convert style.scss style.sass
关于Sass
的安装使用就不在此介绍了,毕竟现在绝大多数项目都是通过webpack
等构建工具来进行打包构建,期间辅以相应的loader
等工具来辅助编译。应该极少项目需要在命令行使用sass
命令来编译样式文件了吧。
不过 编码格式 还是值得一提的。和CSS
一样,可以使用@hcarset
来声明特定的编码格式:在样式文件的起始位置(第一个字符处)插入@charset "encoding-name"
,Sass
就会按照给出的编码格式来编译文件。当然,使用的编码格式必须可以转化为Unicode
字符集。Sass
以UTF-8
编码输出CSS
文件,如果编译后的文件中出现非ASCII
字符,则会在输出文件中添加@charset
声明。
二、基础功能拓展
1. 嵌套规则 Nested Rules
Sass
支持将一套CSS
样式嵌入到另一套CSS
样式中,内层的样式将以外层的选择器为父选择器。
#main p {
color: #00ff00;
width: 97%;
.redbox {
background-color: #ff0000;
color: #000000;}
}
这会被Sass
编译为如下CSS
:
#main p {
color: #00ff00;
width: 97%;
}
#main p .redbox {
background-color: #ff0000;
color: #000000;
}
嵌套功能很大程度上减少了代码量,我们不必再重复地去写繁琐的父选择器,且方便管理。
2. 父选择器 &
(Referencing Parent Selectors: &
)
在嵌套中,如果需要引用父选择器,例如给某个元素设置:hover
样式时,或者当body
元素有某个classname
时,可以用&
来引用父选择器,即其外层选择器。
a {
font-weight: bold;
text-decoration: none;
// & 引用父元素&:hover { text-decoration: underline; }
// body.firefox 可以直接引用
body.firefox & { font-weight: normal; }
}
将被Sass
编译为如下CSS
:
a {
font-weight: bold;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
body.firefox a {
font-weight: normal;
}
&
必须作为选择器的第一个字符,不过它后面可以跟随后缀来生成复合的选择器:
#main {
color: black;
// #main-sidebar 字符串拼接,这就有点好玩了&-sidebar { border: 1px solid; }
}
这会被编译为:
#main {
color: black;
}
#main-sidebar {
border: 1px solid;
}
3. 属性嵌套 Nested Properties
有的CSS
遵循相同的命名空间(namespace
),如 font-family, font-size, font-weight
都以 font
作为属性的命名空间。这时候,为了书写简单、管理方便,Sass
允许将属性嵌套在命名空间里:
.funky {
// 注意命名空间这里要加冒号
font: {
family: fantasy;
size: 30em;
weight: bold;}
}
编译为如下CSS
:
.funky {
font-family: fantasy;
font-size: 30em;
font-weight: bold;
}
其中,命名空间也可以包含自己的属性值:
.funky {
// font-size/line-height
font: 20px/24px {
family: fantasy;
weight: bold;}
}
编译为:
.funky {
/* font-size/line-height */
font: 20px/24px;
font-family: fantasy;
font-weight: bold;
}
4. 占位符选择器 %foo
(Placeholder Selectors
: %foo
)
占位符选择器与id
选择器和class
选择器类似,只是符号为%
,必须通过@extend
指令调用,否则不会参与到Sass
的编译中。
5. 注释 Comments
Sass
支持单行注释//
和多行注释/* */
。多行注释会被完整地输出到编译后的CSS
文件中。将 !
作为多行注释的第一个字符表示在压缩输出模式下保留这条注释并输出到 CSS
文件中,通常用于添加版权信息。插值语句(interpolation
) 可以在多行注释中输出变量值。(使用#{$val}
进行插值。)
// Sass
$version: "1.2.3";
/* This CSS is generated by My Snazzy Framework version #{$version}. */
// 编译为CSS:
/* This CSS is generated by My Snazzy Framework version 1.2.3. */
三、进阶功能拓展
1. SassScript
Sass
提供了名为SassScript
的强大功能,可以作用于任何属性,允许属性使用变量、算数运算等额外功能。
1.1 Interactive Shell
Interactive Shell
可以在命令行中测试SassScript
的功能。在命令行中输入sass -i
,然后输入想要测试的SassScript
查看输出结果。
sass -i
>> "Hello, Sassy World!"
"Hello, Sassy World!"
>> 1px + 1px + 1px
3px
>> #777 + #777
#eeeeee
>> #777 + #888
white
1.2 变量 $
Variables: $
使用变量非常简单:
// 声明变量
$width: 5em;
#main {// 使用变量
width: $width;
}
变量具有块级作用域,嵌套规则内的变量属于局部变量,只能在嵌套规则内使用。而全局变量则可以在任何地方使用。添加!global
声明可以把局部变量转换为全局变量。
// Sass
#main {// !global声明,转换为全局变量
$width: 5em !global;
width: $width;
}
#sidebar {
// 使用全局变量
width: $width;
}
// 编译为CSS:
#main {
width: 5em;
}
#sidebar {
width: 5em;
}
1.3 数据类型 Data Types
SassScript
支持7
种主要的数据类型:
- 数字,可以带单位,
1, 2, 3, 6, 10px
等; - 字符串(有引号和无引号都支持),
"foo", "bar", baz
; - 颜色,
blue, #04a3f9, rgba(255,0,0,0.5)
等; - 布尔值,
true, false
; - 空值,
null
; - 数组(
list
),用空格或逗号作为分隔符,1.5em 1em 0 2em, Helvetica, Arial, sans-serif
; maps
,相当于JS
里的Object
,(key1: value1, key2: value2)
。
此外,SassScript
也支持其它CSS
属性值,如Unicode
字符集,或!important
声明,不过这些不会被特殊对待,而是一律视为无引号字符串。
1.3.1 字符串
SassScript
支持 有引号字符串(quoted strings
) 和 无引号字符串(unquoted strings
) 。这两种字符串在编译时不会相互转换,除了一种情况:在使用#{}
(interpolation
)时,有引号字符串会被编译为无引号字符串,这样便于在mixin
中引用选择器名。
// Sass
@mixin firefox-message($selector) {
body.firefox #{$selector}:before {
content: "Hi, Firefox users!";}
}
@include firefox-message(".header");
// 编译为CSS
body.firefox .header:before {
content: "Hi, Firefox users!";
}
1.3.2 数组( lists
)
数组指Sass
如何处理CSS
中margin: 10px 15px 0 0
或font-face: Helvetica, Arial, sans-serif
这样通过空格或逗号分隔的一系列的值。事实上,独立的值也被视为只包含一个值的数组。
数组本身没有太多功能,不过Sass list functions
给数组带来了很多新功能:nth
函数可以直接访问数组中的某一项;join
函数可以将多个数组连接在一起;append
函数可以往数组中添加新值;@each
函数可以遍历数组中的每一项。
数组中可以包含子数组:如 1px 2px, 5px 6px
是包含 1px 2px
与 5px 6px
两个数组的数组。如果内外两层数组使用相同的分隔方式,则需要使用圆括号包裹内层,如(1px 2px) (5px 6px)
。圆括号在编译时不会被保留,因此,无论哪种写法,1px 2px, 5px 6px
或者(1px 2px) (5px 6px)
,最后的编译结果都是一样的,但是它们在Sass
文件中含义不同,前者表示包含四个值的数组,后者表示包含两个子数组的数组,可以说,圆括号更强调 “分组” 的概念。
()
用于表示空数组,也可以表示空的map
。空数组不会被直接编译成CSS
,如果数组中有空数组或空值,在编译时会被清除。如 1px 2px () 3px
或 1px 2px null 3px
。基于逗号分隔的数组允许保留结尾的逗号,这样做的意义是强调数组的结构关系,尤其是需要声明只包含单个值的数组时。例如 (1,)
表示只包含 1
的数组。
1.3.3 maps
map
是键值对的集合,key
和value
都可以是任意的SassScript
对象。它和list
都是用函数来操作的。例如,map-get
函数可以用于查找键值,map-merge
可用于添加新的键值对,@each
指令可为每个键值对添加样式。map
可以用在任意可以使用list
的地方,反之则不能。当map
用于list
的函数时,会被看做key1 value1, key2 value2
形式的数组。
1.3.4 颜色
任何CSS
颜色表达式都会返回一个SassScript
的颜色值。这包含了大量的命名颜色(往往和无引号字符串unquoted strings
难以分辨)。
1.4 运算 Operations
所有数据类型都支持相等运算==
或!=
,此外,每种数据类型也有自己的运算方式。
1.4.1 数字运算 Number Operations
SassScript
支持加减乘除以及取整?运算(+, -, *, /, %
),必要时会在各个单位之间转换值。关系运算符(>, <, >=, <=
)也可以用于数字运算。
// Sass
p {
width: 1in + 8pt;
}
// 编译为:
p {
width: 1.111in;
}
- 除法运算
/
除法运算有必要单独提一下。因为/
符号在CSS
中通常起到分隔数字的作用。在SassScript
中,/
不仅用于分隔数字,还可以用于除法运算。在以下三种情况下,/
会被视为除法运算:
- 当值或值的一部分是变量或者是函数的返回值;
- 当值被圆括号包裹;
- 当值是算术表达式的一部分。
// Sass
p {
font: 10px/8px; // 普通的CSS
$width: 1000px;
width: $width/2; // 使用了变量,是除法运算
width: round(1.5)/2; // 函数返回值,是除法运算
height: (500px/2); // 使用圆括号,是除法运算
margin-left: 5px + 8px/2px; // 算数运算表达式的一部分,是除法运算
}
// 编译为CSS
p {
font: 10px/8px;
width: 500px;
height: 250px;
margin-left: 9px;
}
如果需要使用变量,又不希望/
被当作除法运算符,那么可以用#{}
将变量包裹起来:
// Sass
p {$font-size: 12px;$line-height: 30px;font: #{$font-size}/#{$line-height};
}
// 编译为CSS
p {font: 12px/30px;
}
1.4.2 颜色值运算 Color Operations
颜色值的运算是分段进行计算的,即分别计算R, G, B
的值。
p {
color: #010203 + #040506;
}
分段计算 01 + 04 = 05
02 + 05 = 07
03 + 06 = 09
,然后编译为:
p {
color: #050709;
}
可以使用color functions
,这比颜色计算要方便一些。
颜色值也可以结合数字运算:
p {
color: #010203 * 2;
}
// 计算 01 * 2 = 02 02 * 2 = 04 03 * 2 = 06,然后编译为:
p {
color: #020406;
}
需要注意,如果颜色值包含alpha channel
,则参与计算的颜色值必须拥有相同的alpha
值才能进行运算,因为算数运算不会作用于alpha
值。
p {
// 需要保证有相同的alpha值color: rgba(255, 0, 0, 0.75) + rgba(0, 255, 0, 0.75);
}
而颜色值中的alpha
值,可以通过函数opacity
或者transparentize
进行调整。
// Sass
$translucent-red: rgba(255, 0, 0, 0.5);
p {
color: opacify($translucent-red, 0.3);
background-color: transparentize($translucent-red, 0.25);
}
// 被编译为:
p {
color: rgba(255, 0, 0, 0.8);
background-color: rgba(255, 0, 0, 0.25);
}
1.4.3 字符串运算 String Operations
使用+
连接字符串;+
左边的值主导最终编译结果是有引号还是无引号。
运算表达式与其他值连用时,用空格做连接符:
p {
margin: 3px + 4px auto;
}
// 编译为:
p {
margin: 7px auto;
}
可以使用#{}
插入动态的值:
$value: null;
p:before {content: "I ate #{$value} pies!";
}
// 编译为CSS:
p:before {content: "I ate pies!";
}
1.4.4 布尔运算 Boolean Operations
布尔型的运算支持and
, or
, not
。
1.4.5 数组运算
数组不支持直接运算,只能使用list functions
来操作。
1.5 圆括号 (Parentheses)
有括号的先算括号。
1.6 函数 Functions
SassScript
内置了许多函数,有些甚至可以使用普通的CSS
语句调用:
p {
color: hsl(0, 100%, 50%);
}
// 编译为:
p {
color: #ff0000;
}
- 关键词参数
Keyword Arguments
Sass
函数允许使用关键词参数,上面的例子可以写为:
p {
color: hsl($hue: 0, $saturation: 100%, $lightness: 50%);
}
Sass
内置的函数非常多,就不在此展开了。
1.7 插值语句 Interpolation #{}
通过#{}
可以在选择器或属性名中使用变量:
$name: foo;
$attr: border;
p.#{$name} {#{$attr}-color: blue;
}
// 编译为:
p.foo {border-color: blue;
}
1.8 SassScript
中的 &
&
表示父选择器。如下,&
的值为((".foo.bar" ".baz.bang"), ".bip.qux")
。
.foo.bar .baz.bang, .bip.qux {$selector: &;
}
如果没有父选择器,则&
的值为null
。这可以应用在mixin
中来检测是否有父选择器:
@mixin does-parent-exist {
@if & {
// 有父选择器
&:hover {
color: red;
}} @else {
// 没有父选择器
a {
color: red;
}}
}
1.9 变量默认值 (Variable Defaults
):!default
在变量结尾添加!default
可以用来给一个未添加!default
声明赋值的变量赋值。只有当变量尚未被赋值或被赋空值null
时,!default
的赋值才会有效。
$content: "First content";
// 变量已被赋值,无效
$content: "Second content?" !default;
$new_content: "First time reference" !default;
#main {
content: $content;
new-content: $new_content;
}
// 编译为:
#main {
content: "First content";
new-content: "First time reference";
}
2. @-Rules
与指令(Directives
)
Sass
支持所有的CSS3 @-Rules
,以及Sass
特有的指令(directives
)。
2.1 @import
Sass
拓展了@import
的功能,使其可以导入.scss
和.sass
文件。被导入的文件将被合并编译到同一个CSS
文件中去。此外,被导入的文件中包含的变量或者mixin
都可以在导入的文件中使用。
一般来说,@import
会寻找Sass
文件并将其导入,但是以下几种情况例外,只会当作普通CSS
语法:
- 文件拓展名是
.css
; - 文件名以
http://
开头; - 文件名是
url()
; @import
包含media queries
。
允许一次导入多个文件,当没有写拓展名时,则会尝试查找.scss
或.sass
的同名文件。
@import "rounded-corners", "text-shadow";
导入文件也可以使用插值语句#{}
,但是只能作用于CSS
的url()
导入方式。
$family: unquote("Droid+Sans");
@import url("http://fonts.googleapis.com/css?family=#{$family}");
// 编译为:
@import url("http://fonts.googleapis.com/css?family=Droid+Sans");
@imports
还有两个特别的用法:分音 和 嵌套。
- 分音 (
Partials
)
有时候想要导入Sass
文件,又不希望将其编译为CSS
,就可以在文件名前添加下划线,这样会告诉Sass
不要对其进行编译。注意,导入语句中不需要添加下划线。例如,将文件命名为_colors.scss
,则以下代码导入的是_colors.scss
文件,且其不会被编译为CSS
。
@import "colors";
需要注意,如过存在同名的包含前置下划线和不包含前置下划线的文件,则添加下划线的文件会被忽略。
- 嵌套
@import
多数场景下,我们都是在文件最顶层使用@imports
。事实上,也可以把@imports
嵌套进CSS
样式或者@media
中。与在顶层中使用的区别,在于这样导入的样式只能出现在嵌套的层中,可以理解为 “局部作用域”。
// example.scss
.example {
color: red;
}
// main.scss
#main {
@import "example";
}
最终会被编译为:
#main .example {
color: red;
}
但是要注意,被这种嵌套形式的@import
来导入的文件中,不应有@mixin
、@charset
等顶层指令。
2.2 @media
Sass
中的@media
与CSS
中一样,并且增加了新的功能:
- 允许其在
CSS
规则中嵌套。当@media
被嵌套进CSS
规则中,编译的时候,会被编译到文件的最外层,并在内部包含之前嵌套时的父选择器,这点非常方便。
// Sass
.sidebar {
width: 300px;
@media screen and (orientation: landscape) {
width: 500px;}
}
// 编译为
.sidebar {
width: 300px;
}
@media screen and (orientation: landscape) {
.sidebar {
width: 500px; }
}
@media
允许嵌套queries
,这在编译时会被自动添加and
。
@media screen {
.sidebar {
@media (orientation: landscape) {
width: 500px;
}}
}
// 编译为
@media screen and (orientation: landscape) {
.sidebar {
width: 500px; }
}
- 可以使用
SassScript
(变量、函数等)来替代条件的名称或者值。
$media: screen;
$feature: -webkit-min-device-pixel-ratio;
$value: 1.5;
@media #{$media} and ($feature: $value) {
.sidebar {
width: 500px;}
}
// 编译为
@media screen and (-webkit-min-device-pixel-ratio: 1.5) {
.sidebar {
width: 500px; }
}
2.3 @extend
- 通过
@extend
可以使一个选择 继承 另一个选择器的样式。
.error {
border: 1px #f00;
background-color: #fdd;
}
.error.intrusion {
background-image: url("/image/hacked.png");
}
.seriousError {
// 继承,此时所有使用到 .error 的样式都会被继承过来
@extend .error;
border-width: 3px;
}
// 编译为
.error, .seriousError {
border: 1px #f00;
background-color: #fdd; }
.error.intrusion, .seriousError.intrusion {
background-image: url("/image/hacked.png");
}
.seriousError {
border-width: 3px;
}
Placeholder Selectors
占位符选择器
有时候,需要定义一套用于继承的样式,而不单独给某个元素使用,我们希望它不会被Sass
单独编译输出。这种场景更多出现在制作Sass
样式库时。占位符选择器由此诞生。它的使用和id
选择器或class
选择器几乎一致,选择器符号为%
。当单独使用占位符选择器时,会被Sass
忽略,不会被编译到输出文件中。
// 不会被编译到输出文件中
#context a%extreme {
color: blue;
font-weight: bold;
font-size: 2em;
}
它需要通过@extend
来使用:
.notice {
@extend %extreme;
}
// 被编译为
#context a.notice {
color: blue;
font-weight: bold;
font-size: 2em;
}
!optional
声明
使用!optional
声明,可以让@extend
不生成新的选择器。
// 不可以,因为没有 .notice
a.important {
@extend .notice
}
// 可以
a.important {
@extend .notice !optional;
}
- 在指令中使用
@extend
为了避免生成大量无用的代码,在指令中进行延伸(@extend
),限制只能延伸给相同指令层级内的选择器。
@media print {
.error {
border: 1px #f00;
background-color: #fdd;}
.seriousError {
// 可以
// .error 同在一个 @meida层级中
@extend .error;
border-width: 3px;}
}
// 以下为反面栗子
.error {
border: 1px #f00;
background-color: #fdd;
}
@media print {
.seriousError {
// 不可以, .error 不在当前的@meida指令层级中
@extend .error;
border-width: 3px;}
}
2.4 @at-root
使用@at-root
指令可以把作用的选择器提升到最外层。
.parent {...
@at-root .child { ... }
}
// 编译为
.parent { ... }
.child { ... }
- 它可以是一个包含多个选择器的块级结构。
.parent {...
@at-root {
.child1 { ... }
.child2 { ... }}
.step-child { ... }
}
// 编译为
.parent { ... }
.child1 { ... }
.child2 { ... }
.parent .step-child { ... }
- 通过
with:xxx yyy ...
或without:xxx yyy ...
来保证外层指令是否对提升到最外层的选择器有效:
// without:
@media print {
.page {
width: 8in;
// without: media 让选择器不受外层的@media影响
@at-root (without: media) {
color: red;
}}
}
// 编译为
@media print {
.page {
width: 8in;}
}
.page {
color: red;
}
3. 控制指令 Control Derectives
控制指令用于在一定条件下引用样式。
3.1 if()
内置的 if
函数可用于任意的SassScript
脚本上下文。
3.2 @if
@if
指令的表达式返回值不是false
或者null
时,条件成立。后面可以接@else if
和@else
。
$type: monster;
p {
@if $type == ocean {
color: blue;} @else if $type == matador {
color: red;} @else if $type == monster {
color: green;} @else {
color: black;}
}
// 编译为
p {
color: green;
}
3.3 @for
这个指令包含两种格式:@for $var from <start> through <end>
,或者 @for $var from <start> to <end>
。两者都包含起始点<start>
,区别在于to
不包含<end>
,而through
包含<end>
。此外,$var
可以是任何变量,但是<start>
和<end>
必须是整数。
@for $i from 1 to 3 {
.item-#{$i} { width: 2em * $i; }
}
// 编译为
.item-1 {
width: 2em;
}
.item-2 {
width: 4em;
}
3.4 @each
@each
指令的格式:@each $var in <list>
@each $animal in puma, sea-slug, egret, salamander {.#{$animal}-icon {
background-image: url('/images/#{$animal}.png');}
}
// 编译为
.puma-icon {
background-image: url('/images/puma.png'); }
.sea-slug-icon {
background-image: url('/images/sea-slug.png'); }
.egret-icon {
background-image: url('/images/egret.png'); }
.salamander-icon {
background-image: url('/images/salamander.png'); }
- 可以同时应用多个变量,在编写形式相似而值不同的样式时很方便:
@each $animal, $color, $cursor in (puma, black, default),
(sea-slug, blue, pointer),
(egret, white, move) {.#{$animal}-icon {
background-image: url('/images/#{$animal}.png');
border: 2px solid $color;
cursor: $cursor;}
}
// 编译为
.puma-icon {
background-image: url('/images/puma.png');
border: 2px solid black;
cursor: default; }
.sea-slug-icon {
background-image: url('/images/sea-slug.png');
border: 2px solid blue;
cursor: pointer; }
.egret-icon {
background-image: url('/images/egret.png');
border: 2px solid white;
cursor: move; }
- 由于
maps
会被当成数组lists
处理,因此@each
也可以用于map
:
@each $header, $size in (h1: 2em, h2: 1.5em, h3: 1.2em) {#{$header} {
font-size: $size;}
}
// 编译为
h1 {
font-size: 2em; }
h2 {
font-size: 1.5em; }
h3 {
font-size: 1.2em; }
3.5 @while
while
循环,都懂。
$i: 6;
@while $i > 0 {
.item-#{$i} { width: 2em * $i; }
// 更改条件变量
$i: $i - 2;
}
//编译为
.item-6 {
width: 12em; }
.item-4 {
width: 8em; }
.item-2 {
width: 4em; }
4. 混合指令 (Mixin Directives
)
mixin
用于定义可重复使用的样式。
4.1 定义混合指令 @minin
(Defining a Mixin: @mixin
)
在@mixin
后添加名称与样式,即可定义混合指令,注意需要包含选择器和属性,也可以使用&
来引用父选择器。
// 定义名为 clearfix 的混合指令
@mixin clearfix {
display: inline-block;
// & 指代父选择器。注意,这个混合指令里虽然它没有父选择器,
// 但是混合指令使用的地方,可以产生父选择器&:after {
content: ".";
display: block;
height: 0;
clear: both;
visibility: hidden;}
// 这里的 & 同理* html & { height: 1px }
}
4.2 引用混合指令 @include
(Including a Mixin: @include
)
- 使用
@include MixinName
来引用混合指令:
.page-title {
// 引用混合指令,将 clearfix 中的规则混入到 .page-title 中
@include clearfix;
padding: 4px;
margin-top: 10px;
}
- 也可以在最外层直接引用混入,不会定义属性,也没有父选择器可引用:
@mixin silly-links {
a {
color: blue;
background-color: red;}
}
@include silly-links;
//编译为
a {
color: blue;
background-color: red; }
我们编写的混合指令中,最好只定义后代选择器,这样才能安全地引入到文件的任何位置。
- 混合指令中可以引用其它混合指令:
@mixin compound {
@include highlighted-background;
@include header-text;
}
@mixin highlighted-background { background-color: #fc0; }
@mixin header-text { font-size: 20px; }
4.3 参数 (Arguments
)
参数可以给混合指令的样式设置变量并赋值使用。在引用和定义混合指令时,参数的顺序应该一一对应,而且,参数可以赋默认值。
// $width有默认值
@mixin sexy-border($color, $width: 1in) {
// 注意这里得 border,是CSS命名空间
border: {
color: $color;
width: $width;
style: dashed;}
}
p { @include sexy-border(blue); }
h1 { @include sexy-border(blue, 2in); }
// 编译为
p {
border-color: blue;
border-width: 1in;
border-style: dashed; }
h1 {
border-color: blue;
border-width: 2in;
border-style: dashed; }
此外,参数还有两个比较重要的点:
- 关键词参数 (
Keyword Arguments
):在引用Mixin
传参时,通过指定参数关键词(参数名)来精确传值。
p { @include sexy-border($color: blue); }
h1 { @include sexy-border($color: blue, $width: 2in); }
尽管书写稍显麻烦,但是阅读方便,且能精准赋值。
- 参数变量 (
Variable Arguments
) :不确定混合指令需要多少个参数时,可以在参数最后方使用参数变量...
来声明,Sass
会把这些参数视为值列表来处理。
@mixin box-shadow($shadows...) {
-moz-box-shadow: $shadows;
-webkit-box-shadow: $shadows;
box-shadow: $shadows;
}
.shadows {
@include box-shadow(0px 4px 5px #666, 2px 6px 10px #999);
}
// 编译为
.shadowed {
-moz-box-shadow: 0px 4px 5px #666, 2px 6px 10px #999;
-webkit-box-shadow: 0px 4px 5px #666, 2px 6px 10px #999;
box-shadow: 0px 4px 5px #666, 2px 6px 10px #999;
}
也可以在引用的时候使用参数变量:
@mixin colors($text, $background, $border) {
color: $text;
background-color: $background;
border-color: $border;
}
$values: #ff0000, #00ff00, #0000ff;
.primary {
@include colors($values...);
}
// 编译为
.primary {
color: #ff0000;
background-color: #00ff00;
border-color: #0000ff;
}
4.4 往混合指令中导入内容 @content
(Passing Content Blocks to a Mixin
)
引用Mixin
的时候,尤其是在文件最外层引用的时候,可以通过@content
占位,然后把接在@include
后的内容导入到@content
的位置,和模板、插槽等相似。
@mixin apply-to-ie6-only {* html {
@content;}
}
@include apply-to-ie6-only {
#logo {
background-image: url(/logo.gif);}
}
// 编译为
* html #logo {
background-image: url(/logo.gif);
}
由于Mixin
在Sass
样式库中使用频繁。为简化使用,可以用=
表示@mixin
,用+
表示@include
。
// Sass (这里就是Sass格式的语法了,而非SCSS格式)
=apply-to-ie6-only* html
@content
+apply-to-ie6-only
#logo
background-image: url(/logo.gif)
- 块级内容和变量作用域:通过
@content
导入的块级内容,它所在的作用域和定义它的位置的上下文相关联,而和混合指令内部的作用域没有关系。
$color: white;
@mixin colors($color: blue) {
background-color: $color;
// @content 的内容的作用域在定义它的地方
@content;
border-color: $color;
}
.colors {
@include colors { // 这里的color,虽然会被插入到@content的位置// 但是它的作用域是在定义它的地方,
// 而定义它的地方,$color是全局变量,值为whitecolor: $color; }
}
// 编译为
.colors {
background-color: blue;
color: white;
border-color: blue;
}
注意,不是每次定义的地方都是全局作用域,也有可能其定义的位置是嵌套在某个选择器里的,那时作用域为该选择器的局部作用域。
5. 函数指令 (Function Directives
)
Sass
允许自定义函数,函数可以在任何属性值或SassScript
中使用。自定义函数命名可以加上前缀,避免命名冲突。
$grid-width: 40px;
$gutter-width: 10px;
@function grid-width($n) {
@return $n * $grid-width + ($n - 1) * $gutter-width;
}
#sidebar { width: grid-width(5); }
// 编译为
#sidebar {
width: 240px;
}
6. 输出格式
6.1 :nested
嵌套(:nested
)是sass
的默认输出格式,清晰地反映CSS
与HTML
之间的关系。选择器与属性单独占一行,缩进量与sass
文件中的保持一致,依靠缩进来反映嵌套层级。
// 编译后输出的CSS文件
#main {
color: #fff;
background-color: #000; }
#main p {
width: 10em; }
6.2 :expanded
展开(:expanded
)格式和手写时的格式一样,选择器不做缩进。
#main {
color: #fff;
background-color: #000;
}
#main p {
width: 10em;
}
6.3 :compact
紧凑格式(Compact
)占用更少的空间,每条CSS
规则只占用一行,嵌套过的选择器不留空行,没嵌套过的选择器之间留空行处理。
#main { color: #fff; background-color: #000; }
#main p { width: 10em; }
.huge { font-size: 10em; font-weight: bold; text-decoration: underline; }
6.4 :compressed
压缩格式(Compressed
)不留空行、空格、注释等,输出的体积最小。
#main{color:#fff;background-color:#000}#main p{width:10em}.huge{font-size:10em;font-weight:bold;text-decoration:underline}
最后
为大家准备了一个前端资料包。包含54本,2.57G的前端相关电子书,《前端面试宝典(附答案和解析)》,难点、重点知识视频教程(全套)。
有需要的小伙伴,可以点击下方卡片领取,无偿分享