CSS预处理器 —— Sass学习笔记4
注释
- 单行注释: // 不会被编译后的css文件中
- 多行注释:/* */ 会被完整输出到编译后的 CSS 文件中
-
将
!
作为多行注释的第一个字符:表示在压缩输出模式下保留这条注释并输出到 CSS 文件中,通常用于添加版权信息 - 多行注释中也可以写入
#{}
插值语句 (interpolation) ,用于输出变量值
-
将
嵌套规则
后代选择器
-
父选择器标识符 &
- & 的值:如果不存在父选择器,那么&的值就是空值null;若是存在,那么&的值就是一个用逗号分隔的数组列表(数组的知识可见变量类型——数组Lists一章 )
群组选择器
子组合选择器 >
同层组合选择器 + 和 ~
#main {
color: #0ff0;
// 父选择器标识符 -- 在编译时, &会被替换成父选择器 #main
&:hover{ // 用法1: 表示给#main元素添加hover样式
color: #fff;
}
.ie &{ // 用法2:在父选择器标识符&之前添加选择器,表示在.ie下的#main样式
color: #00f;
}
&-bar { // 用法3:用作占位符,编译时会用父选择器的名称替换&,表示#main-bar
border: 1px solid;
}
// 后代选择器 -- 在编译时,会在.redbox前面加上父选择器名,也就是 #main .redbox
.redbox {
color: #000;
}
// 群组选择器 -- 编译时,会将#main和h1,h2,h3分别组合,然后将三者重新组合成一个群组选择器,也就是 #main h1, #main h2, #main h3{a{margin-bottom: .8em;}}
h1, h2, h3 {
// 后代选择器
a {margin-bottom: .8em}
}
// 直接子元素 >,编译时会在前面加上父选择器名,编译为: #main > section
> section { background: #eee }
// 同层组合选择器+ 编译为 nav + #main
// 父选择器标识符&会被替换成父选择器名,表示 nav元素紧跟其后的#main元素
nav + & { margin-top: 0 }
// 同层全体组合选择器~ 编译为:#main ~ artical
// 表示#main元素后面所有同一层级的article元素,不管它们中间是否隔着别的元素
~ article { border-top: 1px dashed #ccc }
}
编译结果
#main { color: #0ff0;}
// 父选择器标识符编译出来的结果
#main:hover { color: #fff; }
.ie #main { color: #00f; }
#main-bar { border: 1px solid; }
// 后代选择器编译出来的结果
#main .redbox { color: #000; }
// 群组选择器编译出来的结果
#main h1 a, #main h2 a, #main h3 a { margin-bottom: .8em; }
#main > section { background: #eee; } // 子组合选择器编译结果
nav + #main { margin-top: 0; } // 同层组合选择器编译结果
#main ~ article { border-top: 1px dashed #ccc; } // 同层全体组合选择器编译结果
@mixin does-parent-exist {
@if & { // 如果父选择器存在,那么就给父元素添加hover样式
&:hover {
/* 查看一下&的值: #{&} */
color: red;
}
} @else {
a {
color: red;
}
}
}
div p{ @include does-parent-exist(); }
// div p:hover { /*parent: div p:hover*/ color: red; }
属性嵌套
嵌套属性的规则:把属性名从中划线
-
的地方断开,在根属性后边添加一个冒号:
,紧跟一个{ }
块,把子属性部分写在这个{ }
块中编译规则:如果选择器嵌套一样,
sass
会把你的子属性一一解开,把根属性和子属性部分通过中划线 - 连接起来
#main{
// 属性嵌套在编译时,会将根属性与子属性通过中划线【-】连接起来
background:{
color: #f00;
image: url('1.jpg');
repeat: no-repeat;
position: 50% 50%;
}
// 命名空间也可以包含自己的属性值
font: 12px/24px {
weight: 600;
family: 'Microsoft Yahei';
}
// 指明例外规则
border: 1px solid #ddd{
left: 0;
right: 0;
}
}
编译结果
#main {
background-color: #f00;
background-image: url("1.jpg");
background-repeat: no-repeat;
background-position: 50% 50%;
font: 12px/24px;
font-weight: 600;
font-family: 'Microsoft Yahei';
border: 1px solid #ddd;
border-left: 0;
border-right: 0;
}
变量 $
$变量名: 变量值; // 变量值:css中所有合法的属性值都可以,还可以是属性名。。 // 全局变量
body{
$变量名: 变量值; // 规则块内 -- 局部变量
css属性: $变量名; // 变量引用。编译成css时,该$变量名会被其所指代的变量值替换
}
1. 变量作用域
1. 全局作用域:不在嵌套规则内定义的变量则可在任何地方使用(嵌套规则外 -- 全局变量)
2. 块级作用域:嵌套规则内定义的变量只能在嵌套规则内使用(嵌套规则内 -- 局部变量)
3. 将局部变量转换为全局变量可以添加 `!global` 声明(嵌套规则内 -- 全局变量 -- $变量名: 变量值 !global;)
2. 变量声明
- sass变量名以美元符号$开头,大小写敏感
- 可以用中划线和下划线两种形式命名,中划线方式更普遍
- 两种用法互相兼容,也就是说,用中划线声明的变量可以用下划线的方式引用,反之亦然
- 变量声明后还未生效,只有当变量被引用后才生效
3. 变量赋值
变量的赋值与css的赋值是一样的
- 任何可以用作
css
属性值的赋值都可以用作sass
的变量值 - 在声明变量时,变量值也可以引用其他变量
- 可以在变量值后面使用
!global
声明,将局部变量 变成 全局变量 - 可以在变量第一次赋值时在后面使用
!default
指定变量默认值- 只在第一次赋值时有用。也就是说,如果变量已经被赋值,就不会再被重新赋值,但是如果变量还没有被赋值,则会被赋予新的值。
- 变量是 null 空值时将视为未被
!default
赋值。
4. 变量引用
- 凡是
css
属性的标准值可存在的地方,变量就可以使用。css
生成时,变量会被它们的值所替代。 - 变量可以修改,但一经修改,所有引用此变量的地方(同一作用域)生成的值都会随之改变
- 变量有一种特殊的引用方法:插值语句 #{变量}
插值语句 #{}
插值 (interpolation) —— 将一个占位符,替换成一个值。
- 通过
#{}
插值语句可以在选择器或属性名中使用变量 —— 其实就是字符串连接的语法糖而已。 -
#{}
插值语句也可以在属性值中插入 SassScript —— 可以避免 Sass 运行运算表达式,直接编译 CSS。
$name: foo;
$attr: border;
p.#{$name} { // 在选择器中使用变量
#{$attr}-color: blue; // 在属性名中使用变量
}
// p.foo { border-color: blue; }
p {
$font-size: 12px;
$line-height: 30px;
font: #{$font-size}/#{$line-height}; // 避免将/用作除法运算符
}
// p { font: 12px/30px; }
1. 用于css函数
-
Sass会把CSS函数(包括伪类)认为是字符串,所以想要在最后获得它们的值,要求你转义所有同它们一起使用的变量。否则结果会与你的预期大不相同
- 比如:
calc()
、url()
,linear-gradient()
,radial-gradient()
,cubic-bezier()
- 比如:
$sidebar-width: 250px;
$max: 3;
// for语句循环
@for $i from 1 through $max {
.el:nth-of-type(#{$i}) { // 与css伪类一起使用,需要转义
width: calc(100% - #{$sidebar-width}); // 与css函数calc一起使用,需要转义
}
}
// 编译结果
.el:nth-of-type(1) { width: calc(100% - 250px * 1); }
.el:nth-of-type(2) { width: calc(100% - 250px * 2); }
.el:nth-of-type(3) { width: calc(100% - 250px * 3); }
2. 用于css指令
- 与css指令一起使用,比如
@support
,@page
,最重要的是@media
- 如果
@media
后面紧跟 变量,那么就必须使用插值才可以 - 如果
@media
后面紧跟(()
),就不再需要插值变量了,因为Sass会求出所有在这些括号里面的值
- 如果
$screen: screen;
@media #{$screen} { // @media字符串后面紧跟着变量,那么就必须使用插值进行转义
// ...
}
$value: 1336px;
@media (max-width: $value) { // @media字符串后面紧跟着(),那么()中的变量就无需插值,sass会先求出括号中的值
// ...
}
变量类型
SassScript 支持 6 种主要的数据类型(变量的6中主要数据类型):
-
数字,
1, 2, 13, 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, 相当于 JavaScript 的 object,
(key1: value1, key2: value2)
SassScript 也支持其他 CSS 属性值,比如 Unicode 字符集,或 !important
声明。然而Sass 不会特殊对待这些属性值,一律视为无引号字符串
可以使用 type-of()
检查变量或者一段表达式的类型
1. 字符串类型
- 有引号字符串 (quoted strings) :如
"Lucida Grande"
'Microsoft Yahei'
; - 无引号字符串 (unquoted strings),如
sans-serif
、bold
- 一般情况下,变量字符串在编译时类型不会有变化,
sass
中有引号,编译的css
中也就有引号,sass
中无引号,编译的css
中也就没有引号。但是有一种例外情况,就是在使用插值语句#{}时,有引号字符串会被编译成无引号字符串。
$font-family: 'Microsoft Yahei', sans-serif; // 一个有引号字符串,一个无引号字符串
body {
font: 14px/24px $font-family;
font-family: #{$font-family}; // 使用插值语句
}
// 编译后. 可发现在编译css文件时不会改变字符串的类型
body {
font: 14px/24px "Microsoft Yahei", sans-serif; // 在编译 CSS 文件时不会改变字符串类型
font-family: Microsoft Yahei, sans-serif; // 有引号字符串被编译为无引号字符串
}
2. 数组 Lists
sass
中的数组(或者叫列表)指的是 通过 空格 或者 逗号 分隔的一系列的值。事实上,独立的值也被视为数组 —— 只包含一个值的数组。数组中也可以包含子数组。如用逗号分隔:1px 2px, 5px 6px
,还有用空格分隔 (1px 2px) (5px 6px)
数组的规则:
- 除非列表太长不能写在80字符宽度的单行中,否则应该始终单行显示。 —— 最好单号显示
- 除非适用于CSS,否则应该始终使用逗号作为分隔符。 —— 建议使用逗号分隔
- 除非为空或者嵌套在另一个数组中,否则始终不要使用括号。
- 始终不要添加尾部的逗号 —— 基于逗号分隔的数组允许保留结尾的逗号,但建议不要保留
注意:
- 列表第一项的索引是1,而不是0,这一点和javascript数组不同
$list: (); // 空数组。若被引用,编译会报错 —— 空数组不可以直接编译成 CSS
$list-space: "item-1" "item-2" "item-3"; // 使用空格进行分隔
$list-space: "item-1","item-2","item-3"; // 使用逗号进行分隔
// 数组嵌套推荐使用小括号
$list: (
("item-1.1", "item-1.2", "item-1.3"),
("item-2.1", "item-2.2", "item-2.3"),
("item-3.1", "item-3.2", "item-3.3")
);
// nth获取元素中指定的某个值
$list:"antzone",2,"softwhy.com";
.div {
content: nth($list,1); // content: length($list) 求数组的长度
}
操作数组的函数:
- length($list):返回一个列表的长度值。
- index(value):返回一个值在列表中的位置值
- nth(index):返回一个列表中指定的某个标签值。
- append(val, [$separator]):将某个值放在列表的最后。
- join(list2, [$separator]):将两个列给连接在一起,变成一个列表。
- zip($lists…):将几个列表结合成一个多维的列表。。
3. Maps
Maps可视为键值对的集合,键被用于定位值。和Lists不同,Maps必须被圆括号包围,键值对被逗号分割。
Maps可用于任何Lists可用的地方,在List函数中 Map会被自动转换为List , 如 (key1: value1, key2: value2)会被List函数转换为 key1 value1, key2 value2 ,反之则不能。
操作Maps的函数:
- map-has-key(key) 判断某个key是否存在于map中
- map-get(key) 获取map中键key对应的值
- map-merge(map2) 将两个maps合并成一个新的maps,不影响原来的maps对象
- map-keys(map)
- map-remove(key) 从map中删除一个key,返回一个新的map
- keywords($args) 返回一个函数的阐述,这个参数可以动态设置key和value
- @each value in $map 循环maps
示例:搭配函数使用
// 声明一个Maps变量:Maps必须被圆括号包围,键值对被逗号分割
$layer: (
offcanvas: 1,
lightbox: 500,
dropdown: 10,
tooltip: 15
);
// 定义函数,参数$name对应$layer中的key
@function layer($name) {
@if map-has-key($layer, $name) { // 判断传入的参数是否存在于$layer
@return map-get($layer, $name); // 根据$name获取$layer中对应的值
}
@warn "The key #{$name} is not in the map '$layer'";
@return null;
};
// 使用
.m-lightbox {
z-index: layer(lightbox); // 调用方法,并传入对应的值
}
// 编译后
.m-lightbox { z-index: 500; }
搭配列表一起使用
// 定义maps变量,每个key的值都是一个列表,表示(背景颜色, 字体颜色)
$buttons: (
error: (#d82d2d, #666),
success: (#52bf4a, #fff),
warning: (#c23435, #fff)
);
// 使用
.m-button {
display: inling-block;
padding: .5em;
// 遍历maps遍历
@each $name, $colors in $buttons {
$bgcolor: nth($colors, 1); // 通过nth获取数组中的第一项
$fontcolor: nth($colors, 2);// 通过nth获取数组中的第二项
// 父选择器标识符&的第三种用法:用在选择器中作为占位符
&--#{$name} {
background-color: $bgcolor;
color: $fontcolor;
}
}
}
// 编译后
.m-button { display: inling-block; padding: .5em;}
.m-button--error { background-color: #d82d2d; color: #666; }
.m-button--success { background-color: #52bf4a; color: #fff; }
.m-button--warning { background-color: #c23435; color: #fff; }
运算
所有数据类型均支持相等运算
==
或!=
,此外,每种数据类型也有其各自支持的运算方式
1. 数字运算
SassScript 支持数字的运算有:
-
数字的加减乘除、取整等运算 (
+, -, *, /, %
),如果必要会在不同单位间转换值。 - 关系运算
<, >, <=, >=
- 可用于所有数据类型的相等运算 **
==, !=
**
1.1 除法运算
在 SassScript 中, /
有两个作用:分隔数字、除法运算符
以下三种情况 /
将被视为除法运算符号:
- 如果值,或值的一部分,是变量或者函数的返回值
- 如果值被圆括号包裹
- 如果值是算数表达式的一部分
如果需要使用变量,同时又要确保 /
不做除法运算而是完整地编译到 CSS 文件中,只需要用 #{}
插值语句将变量包裹。
p {
$width: 1000px;
width: $width/2; // 值的一部分是变量 —— 除法运算符
width: round(1.5)/2; // 值是算术表达式的一部分 —— 除法运算符
height: (500px/2); // 值被圆括号包裹 —— 除法运算符
margin-left: 5px + 8px/2px; // 加减乘除运算
// 要使用变量,又要确保 `/` 不做除法运算 而是 完整地编译到 CSS 文件中 —— 使用插值语句
$font-size: 12px;
$line-height: 30px;
font: #{$font-size}/#{$line-height}; // font: 12px/30px;
}
1.2 内置函数
-
percentage($number)
将一个不带单位的数值转成百分比 -
round($number)
将$number
四舍五入为整数,$number
可带单位 -
ceil($number)
大于$number
,向上取整 -
floor($number)
与ceil()
相反,去除$number
小数,向下取整 -
abs($number)
,返回$number
的绝对值 -
min($numbers…)
,返回$number...
的最小值 -
max($numbers…)
,返回$number...
的最大值 -
random([$limit])
,返回一个随机数
2. 颜色值运算
颜色的值(RGB)是分段计算进行的,也就是分别计算红色,绿色,以及蓝色的值
- 颜色与颜色进行算术运算; color: #010203 + #040506; // color: #050709;
- 颜色与数字进行算术运算;color: #010203 * 2; // color: #020406;
- 若颜色值中包含 alpha channel(rgba 或 hsla 两种颜色值),则必须拥有相等的 alpha 值才能进行运算
- 也就是说:rgba + rgba ; hsla + hsla ... 这两者的透明度 a 必须相同才可以进行运算。因为术运算不会作用于 alpha 值
- 颜色值的 alpha channel 可以通过 opacify 或 transparentize 两个函数进行调整
- IE 滤镜要求所有的颜色值包含 alpha 层,而且格式必须固定
#AABBCCDD
,使用ie_hex_str
函数可以很容易地将颜色转化为 IE 滤镜要求的格式
p {
color: #010203 + #040506; // 编译为 color: #050709;
// 计算 01 + 04 = 05、02 + 05 = 07、03 + 06 = 09
color: #010203 * 2; // 编译为 color: #020406;
// 计算 01 * 2 = 02、02 * 2 = 04、03 * 2 = 06
color: rgba(255, 0, 0, 0.75) + rgba(0, 255, 0, 0.75); // 两者的alpha必须相同,都为0.75
// 编译为:color: rgba(255, 255, 0, 0.75);
}
$red: rgba(255, 0, 0, 0.5);
$green: #00ff00;
p {
color: opacify($red, 0.3); // 使用 opacity 函数 -- color: rgba(255, 0, 0, 0.8);
background-color: transparentize($red, 0.25); // 使用 transparentize 函数
// 编译结果: background-color: rgba(255, 0, 0, 0.25);
}
div { // 使用ie-hex-str函数将颜色转化未符合 IE 滤镜要求的格式 #RRGGBBAA
filter: progid:DXImageTransform.Microsoft.gradient(enabled='false', startColorstr='#{ie-hex-str($green)}', endColorstr='#{ie-hex-str($red)}');
}
// 编译结果
div {
filter: progid:DXImageTransform.Microsoft.gradient(enabled='false', startColorstr=#FF00FF00, endColorstr=#80FF0000);
}
2.1 内置函数
对于颜色的操作,scss提供了大量内置函数,非常方便。
- rgba() 能省掉手工转换 hex 到 rgb 格式的工作
- opacify () 增加透明度
- transparentize () 减少透明度值
- lighten / darken 是基于 HSL 明度变换,这个比较适合 button 按钮的 normal 态和 hover 态变换,
- saturate / desaturate 是基于 HSL 饱和度 变换,
- tint / shade 色彩算法,通过增加 白色(tint) 和 黑色(shade) 的占比来生成系列色
- complement 补色
- 在色彩理论中,如果一种颜色与另一种颜色混合后,呈现中性的灰黑色,那么这两种颜色就互为补色
3. 字符串运算
-
使用
+
可用于连接字符串。- 有引号字符串+无引号字符串=有引号字符串; 'a' + b = 'ab'
- 无引号字符串+有引号字符串=无引号字符串;a + 'b' = ab
- 运算表达式与其他值连用时,用空格做连接符。 margin: 3px + 4px auto;
- 在有引号的文本字符串中使用
#{}
插值语句可以添加动态的值。 contnet: 'welcome, #{username}' - 空的值被视作插入了空字符串。 $value: null; content: 'I ate #{value} pies';
3.1 内置函数
-
unquote($string)
删除$string
前后的引号。 -
quote($string)
给$string
前后添加引号 -
str-length($string)
返回$string
的长度 -
str-insert($string, $insert, $index)
在指定位置插入字符 -
str-index($string, $substring)
返回指定字符在字符串的位置 -
to-upper-case($string)
将$string
小写字母转成大写字母 -
to-lower-case($string)
将$string
大写字母转成小写字母
4. 布尔运算
SassScript 支持布尔型的 and
、 or
以及 not
运算。
5. 数组运算
数组不支持任何运算方式,只能使用 list functions 控制(见变量类型——数组一章)。
5.1 内置函数
- length($list):返回一个列表的长度值。
- index(value):返回一个值在列表中的位置值
- nth(index):返回一个列表中指定的某个标签值。
- append(val, [$separator]):将某个值放在列表的最后。
- join(list2, [$separator]):将两个列给连接在一起,变成一个列表。
- zip($lists…):将几个列表结合成一个多维的列表。。
Sass高级 —— 规则和指令
@-Rules 与指令
1. @import
Sass 拓展了 @import
的功能,允许其导入 SCSS 或 Sass 文件。
1. 例外情况
通常,@import
寻找 Sass 文件并将其导入,但在以下情况下,@import
仅作为普通的 CSS 语句,不会导入任何 Sass 文件。
- 文件拓展名是
.css
; - 文件名以
http://
开头; - 文件名是
url()
; -
@import
包含 media queries。
2. 基础知识
Sass 拓展了 @import
的功能:
- 若不存在上面的4种情况,文件的拓展名是
.scss
或.sass
,则导入成功- 就算没有指定拓展名,Sass 也会试着寻找文件名相同,拓展名为
.scss
或.sass
的文件并将其导入
- 就算没有指定拓展名,Sass 也会试着寻找文件名相同,拓展名为
- Sass 允许同时导入多个文件,使用逗号
,
进行分隔 - 导入文件也可以使用
#{ }
插值语句,但只能作用于 CSS 的url()
导入方式,而不是通过变量动态导入 Sass 文件 - 被导入的文件将合并编译到同一个 CSS 文件中
- 被导入的文件中所包含的变量或者混合指令 (mixin) 都可以在导入的文件中使用 —— 变量和mixin可通用
- Sass 在当前地址寻找 Sass 文件
- 如果需要设定其他地址,可以用
:load_paths
选项,或者在命令行中输入--load-path
命令
- 如果需要设定其他地址,可以用
/** 4种情况 @import仅作为普通的 CSS 语句 */
@import "foo.css"; // 文件拓展名是 .css
@import "foo" screen; // @import 包含 media queries
@import "http://foo.com/bar"; // 文件名以 http:// 开头
@import url(foo); // 文件名是 url()
/** 正确示例 */
@import "foo.scss"; // 1- 文件的拓展名是 .scss 或 .sass
@import "foo"; // 2- 没有扩展名,Sass会试着找 foo.scss 或者 foo.sass 进行导入
@import "rounded-corners", "text-shadow"; // 同时导入多个文件,使用逗号进行分隔
/** 3- 使用插值语句 -- 只能作用域 CSS 的 url() 导入方式*/
$family: unquote("Droid+Sans"); // 字符串内置函数unquote(str)去除引号
@import url("http://fonts.googleapis.com/css?family=\#{$family}"); // CSS url()方式导入
// 编译结果: @import url("http://fonts.googleapis.com/css?family=Droid+Sans");
3. 局部 (Partials)
如果需要导入 SCSS 或者 Sass 文件,但又不希望将其编译为 CSS,只需要在文件名前添加下划线,这样会告诉 Sass 不要编译这些文件,但导入语句中却不需要添加下划线。
—— 需要导入 + 不希望被编译 ---- 将文件命名时,前面加上下划线。
—— 如:文件名为 _colors.scss; 导入 @import colors.scss; 其实导入的就是 _colors.scss文件
—— 注意:不可存在同名文件,即不能再有 colors.scss 文件 ---- 因为导入语句中不需要添加下划线
注意,不可以同时存在添加下划线与未添加下划线的同名文件,添加下划线的文件将会被忽略。
4. 嵌套 @import
大多数情况下,一般在文件的最外层(不在嵌套规则内)使用 @import
,其实,也可以将 @import
嵌套进 CSS 样式或者 @media
中,与平时的用法效果相同,只是这样导入的样式只能出现在嵌套的层中。
可以理解成作用域:
- 在文件最外层使用 @import ---- 导入的样式、变量、mixin等全局可用 ---- 全局
- 在嵌套规则内,或者@media中 ---- 导入的样式只能出现在嵌套的层中 ---- 局部
注意: 不可以在混合指令 (mixin) 或控制指令 (control directives) 中嵌套 @import
2. @media
CSS中的 @media
规则指定一组规则的目标媒体类型(以逗号分隔)
Sass 中 @media
指令与 CSS 中用法一样,只是增加了一点额外的功能:允许其在 CSS 规则中嵌套。
- 如果
@media
嵌套在 CSS 规则内,编译时,@media
将被编译到文件的最外层,包含嵌套的父选择器。 -
@media
的queries
允许互相嵌套使用,编译时,Sass
自动添加and
-
@media
甚至可以使用 SassScript(比如变量,函数,以及运算符)代替条件的名称或者值
$media: screen;
$feature: -webkit-min-device-pixel-ratio;
$value: 1.5;
.navbar {
width: 300px;
// 1- @media嵌套在 CSS 规则内
@media #{$media} { // 3-使用 SassScript 如果@media后面直接跟变量,就需要用插值语句;
.sidebar {
// 2- 嵌套使用
@media ($feature: $value) {// 3-使用 SassScript 如果跟着圆括号,则不需要用插值语句
width: 500px;
}
}
}
}
// 编译结果
.navbar { width: 300px; }
// 嵌套在 CSS 规则内的@media,编译时,将被编译到文件的最外层,包含嵌套的父选择器
@media screen and (-webkit-min-device-pixel-ratio: 1.5) {
.navbar .sidebar { width: 500px; }
}
3. @extend
情形:一个元素使用的样式与另一个元素完全相同,但又添加了额外的样式。
通常做法:在 HTML 中给元素定义两个 class,一个通用样式,一个特殊样式。
不便之处:必须时刻记住特殊样式需要参考通用样式
解决之法:使用 @extend
,告诉 Sass 将一个选择器下的所有样式(包括其他使用到该选择器的样式)继承给另一个选择器。
- 【如何工作】@extend继承它后面选择器的样式,但并不是简单的将样式插入到被继承选择器所在的位置,而是智能的进行了合并,比如避免无谓的重复,不能匹配任何元素的选择器也会删除
- 比如
a:hover{...} .error{ @extend a:hover; }
将a的所有样式继承给.error - 编译时,使用.error替换a:hover,然后合并到一起,也就是 a:hover, .error{....}
- 比如
- 【@extend-Only 选择器】通过
%占位符名称
标记的样式不会被编译,通过 @extend - 【延伸复杂的选择器】Sass 允许延伸任何定义给 单个元素 的选择器,不止是简单的Class 选择器,比如
.special.cool
,a:hover
或者a.user[href^="http://"]
等 - 【多重延伸】同一个选择器可以一次继承多个选择器,它所包含的属性将继承给所有被延伸的选择器
- 比如
.warn{...} .error{ ... } .success{ @extend .warn; @extend .error; }
也可以写成 .success{ @extend .warn , .error; }
- 比如
- 【继续链】当一个选择器延伸给第二个后,可以继续将第二个选择器延伸给第三个。。。
- 比如
.warn{...} .error{ @extend .warn; } .success{ @extend .error; }
那么success也会继承.warn
- 比如
// .error以及其他使用到.error 的样式
.error {
border: 1px solid #f00;
}
.error.intrusion { // 其他使用到 .error 的样式也会同样继承给 .seriousError
background-image: url("./image/hacked.png");
}
// a:hover以及其他使用到a:hover的样式
a:hover {
text-decoration: underline;
}
.comment a.user:hover { // 合并规则:合并选择器列
font-weight: bold;
}
// @extend-Only 选择器 -- 该选择器不能被编译
.success %place-s{
font-size: 14px;
}
// @extend的使用
.seriousError { // 【多重延伸】 也可以写成 @extend .error, a:hover;
@extend .error; // 【延伸】使用 @extend 继承.error的所有样式
@extend a:hover; // 【延伸复杂的选择器】使用 @extend 继承a:hover 的所有样式
border-width: 3px; // 单独给 .seriousError 设定特殊样式
}
.criticalError {
@extend .seriousError; // 【继续延伸】将.seriousError的所有样式延伸给.criticalError
color: #fff; // 单独给 .criticalError 设定特殊样式
}
.font{
@extend %place-s;
}
编译为
.error, .seriousError, .criticalError {
border: 1px solid #f00;
}
.error.intrusion, .seriousError.intrusion, .criticalError.intrusion {
background-image: url("./image/hacked.png");
}
a:hover, .seriousError, .criticalError{
text-decoration: underline;
}
.comment a.user:hover, .comment .user.seriousError, .comment .user.criticalError {
font-weight: bold;
}
.success .font{
font-size: 14px;
}
.seriousError, .criticalError {
border-width: 3px;
}
.criticalError {
color: #fff;
}
-
【选择器列】暂时不可以将选择器列延伸给其他元素,但是,却可以将其他元素延伸给选择器列
- 比如 不可以
@extend .foo .bar
或@extend .foo + .bar
;但是可以:.foo .bar{ @extend a; }
- 比如 不可以
-
【合并选择器列】有时会遇到复杂的情况,比如选择器列中的某个元素需要延伸给另一个选择器列,这种情况下,两个选择器列需要合并。当两个列 (sequence) 合并时:
- 没有包含相同的选择器,将生成两个新选择器:第一列出现在第二列之前,或者第二列出现在第一列之前
- 包含了相同的选择器,相同部分将会合并在一起,其他部分交替输出。
- 注意:按照全排列的方式,生成可能选择器组合的数目也许很庞大,scss只会生成最可能的选择器组合
#admin .tabbar a {
font-weight: bold;
}
// 1-【合并选择器列】没有包含相同的选择器
#demo .overview .fakelink {
@extend a; // 延伸选择器列 #admin .tabbar a 中的单个元素a
}
/** 编译结果 */
#admin .tabbar a,
#admin .tabbar #demo .overview .fakelink, // 生成新的选择器1:第一列在第二列之前
#demo .overview #admin .tabbar .fakelink { // 生成新的选择器2:第二列在第一列之前
font-weight: bold;
}
// 2-【合并选择器列】包含相同的选择器-#admin
#admin .overview .fakelink {
@extend a; // 延伸选择器列 #admin .tabbar a 中的单个元素a
}
/** 分析
* 由于它们具有共同的祖辈#admin选择器,所以将其放在所有选择器的开头毫无疑问。
* 将.fakelink选择器插入到被继承的a选择器位置。
* 但是我们无法判断.tabbar和.overview谁包含谁,所以两者就相互包含一下
*/
/** 编译结果 */
#admin .tabbar a,
#admin .tabbar .overview .fakelink,
#admin .overview .tabbar .fakelink {
font-weight: bold;
}
- 【
!optional
声明】如果要求@extend
不生成新选择器,可以通过!optional
声明达到这个目的
p{
color:red;
// @extend .notice; // 由于并不存在一个名为notice的样式类,所以会报错
@extend .notice !optional; // 由于是可选的,即便notice样式类不存在也不会报错
}
// 编译结果
p{ color: red; }
- 【在指令中延伸】在指令中使用
@extend
时 有一些限制- 比如在
@media
(或者其他 CSS 指令)中使用@extend
,必须延伸给相同指令层中的选择器
- 比如在
.warn{ color: yellow; }
@media print {
.error { color: #fdd; }
.seriousError {
@extend .error; // OK
@extend .warn; // ERROR .warn在"@media print"指令外层
border-width: 3px;
}
}
4. @at-root
- @at-root指令可以使一个或多个规则被限定输出在文档的根层级上,而不是被嵌套在其父选择器下
- 默认情况下,@at-root只会跳出选择器嵌套,而不能跳出指令,比如@media或@support指令
- 如果要跳出指令,可以搭配 without 和 with
- without 的作用是指定跳出哪些指令
- with 的作用是指定不跳出哪些指令,其他的指令都跳出
- @at-root (without/with: all); 表示所有
- @at-root (without/with: rule); 表示常规css
- @at-root (without/with: media); 表示 @media 指令
- @at-root (without/with: support); 表示 @support 指令
.parent{
color:red;
@at-root .child { // 使用@at-root 将.child规则输出到文档的根层级上
color: #fff;
}
// 多个规则
@at-root {
.child-1 { color: yellow; }
.child-2 { color: red; }
}
}
// 编译结果
.parent { color: red; }
.child { color: #fff; }
.child-1 { color: yellow; }
.child-2 { color: red; }
// 默认情况下@at-root并不会使指定的规则或则选择器跳出指令
@media print {
@at-root{
.foo { color: green; }
}
}
// 编译结果 @media print { .foo { color: green; } }
// 搭配without
@media print {
.parent{
color:red;
@at-root (without: media) { // 指定只跳出media,但并不会跳出.parent
.child { color: #0ff; }
}
}
}
// 编译结果 @media print { .parent { color: red; } } .parent .child { color: #0ff; }
// 搭配 without:all
@media print {
.parent{
color:red;
@at-root (without: all) { // all标识要跳出所有
.child { color: #0ff; }
}
}
}
// 编译结果 @media print { .parent { color: red; } } .child { color: #0ff; }
// 搭配 with
@media print {
@supports ( transform-origin: 5% 5% ) {
@at-root (with: supports){ // 除了supports,其他指令都跳出
.foo { color: green; }
}
}
}
// 编译结果 @supports (transform-origin: 5% 5%) { .foo { color: green; } }
5. @debug
@debug
伪指令检测错误,并将SassScript表达式值显示到标准错误输出流
$font-sizes: 10px + 20px
.container{
@debug $font-sizes;
}
6. @warn
Sass @warn指令在出现问题并希望向用户提供警告性建议时使用。它将SassScript表达式的值显示到标准错误输出流。
$main-color: #bdc3c7;
@warn "Darker: " darken($main-color, 30%);
控制指令
SassScript 提供了一些基础的控制指令,比如在满足一定条件时引用样式,或者设定范围重复输出格式。控制指令是一种高级功能,日常编写过程中并不常用到,主要与混合指令 (mixin) 配合使用,尤其是用在 Compass 等样式库中。
if(exp, value1, value2)
语法:
if( expression, value1, value2 )
说明:内置函数,基于条件expression,如果表达式结果为真,则返回 value1;为假则返回 value2。函数的结果可以参考可能未被定义的变量或具有进一步的计算。
h2{
color: if( 1 + 1 == 2 , green , red);
}
// 编译结果
h2 { color: green; }
@if exp {}
当
@if
的表达式返回值不是false
或者null
时,条件成立,输出{}
内的代码@if
声明后面可以跟多个@else if
声明,或者一个@else
声明。如果@if
声明失败,Sass 将逐条执行@else if
声明,如果全部失败,最后执行@else
声明
$type: monster;
p {
@if 1 + 1 == 2 { border: 1px solid; } // 表达式的值是 true -- 真
@if 5 < 3 { border: 2px dotted; } // 表达式的值是 false -- 假
@if null { border: 3px double; } // 表达式的值是 null -- 假
@if $type == ocean {
color: blue;
} @else if $type == matador {
color: red;
} @else if $type == monster {
color: green;
} @else {
color: black;
}
}
@for
@for
指令可以在限制的范围内重复输出格式,每次按要求(变量的值)对输出结果做出变动。
两种格式:
@for $var from <start> through <end>
@for $var from <start> to <end>
区别在于
through
与to
的含义:
- 当使用
through
时,条件范围包含<start>
与<end>
的值; start <= $val <= end ----- [start, end]- 使用
to
时条件范围只包含<start>
的值不包含<end>
的值; start <= $val < end ----- [start, end)
$var
可以是任何变量,比如$i
;<start>
和<end>
必须是整数值
@for $index from 1 through 3 {
.item-#{$index} { width: 2em * $index; }
}
// 编译结果
.item-1 { width: 2em; } .item-2 { width: 4em; } .item-3 { width: 6em; }
@each
语法:
@each $var in <list or map>
说明:
$var
可以是任何变量名,比如$length
,$name
;
<list or map>
是一连串的值,也就是值列表(数组、Maps ...)
@each
将变量 $var
作用于值列表中的每一个项目,然后输出结果,例如:
// 声明变量 $animal 循环列表: puma, sea-slug, egret, salamander
@each $animal in puma, egret, sea-slug, salamander {
.#{$animal}-icon {
background-image: url('/images/#{$animal}.png');
}
}
// 编译结果
.puma-icon { background-image: url('/images/puma.png'); }
.egret-icon { background-image: url('/images/egret.png'); }
.sea-slug-icon { background-image: url('/images/sea-slug.png'); }
.salamander-icon { background-image: url('/images/salamander.png'); }
1. @each 多个分配
语法:
@each $var1, $var2, $var3 ... in <list>
说明:<list> 表示列表的列表,每个变量将保存子列表的元素
$mul-list: (puma, black, default), (slug, blue, pointer), (egret, white, move);
@each $animal, $color, $cursor in $mul-list {
.#{$animal}-icon {
background: url('/images/#{$animal}.png');
border-color: 2px solid $color;
cursor: $cursor;
}
}
// 编译结果
.puma-icon { background: url('/images/puma.png'); border-color: black; cursor: default; }
.slug-icon { background: url('/images/slug.png'); border-color: blue; cursor: pointer; }
.egret-icon { background: url('/images/egret.png'); border-color: white; cursor: move; }
2. @each 多个分配与映射
语法:
@each $var1, $var2 in <map>
说明:<map> 表示键值对的列表
$mul-map: (h1: red, h2: green, h3: blue);
@each $header, $color in $mul-map {
#{$header} {
color: $color;
}
}
// 编译结果
h1 { color: red; } h2 { color: green; } h3 { color: blue; }
@while
@while
指令重复输出格式直到表达式返回结果为 false
。这样可以实现比 @for
更复杂的循环,只是很少会用到。
语法: while(condition) { // CSS codes... }
说明:要注意,计数器变量需要在每次迭代时递增/递减。
$i: 30;
@while $i > 0 {
.paddding-#{$i} { padding-left: 1px * $i; }
$i: $i - 10; // 计数器变量在每次迭代时递减
}
// 编译结果
.paddding-30 { padding-left: 30px; }
.paddding-20 { padding-left: 20px; }
.paddding-10 { padding-left: 10px; }
混合指令
Mixins允许创建一组可以在整个样式表中重复使用的样式,而不需要重新创建非语义类。混合指令可以包含所有的 CSS 规则,绝大部分 Sass 规则,甚至通过参数功能引入变量,输出多样化的样式。
在CSS中,mixin可以存储多个值或参数和调用函数; 它有助于避免编写重复的代码。混合名称可以交替使用下划线和连字符。
1 定义 @mixin
混合指令的用法是在 @mixin
后添加名称与样式
语法: @mixin 混合指令名称 { // css code, sass code ... }
附:为便于书写,
@mixin
可以用=
表示;即: =混合指令名称 { // css code, sass code ... }
- 混合样式中也可以包含其他混合样式
- 混合样式中应该只定义后代选择器,这样可以安全的导入到文件的任何位置。
// 定义混合指令 clearfix
@mixin clearfix {
display: inline-block;
&:after { // 使用父选择器标识符
content: ".";
height: 0;
clear: both;
visibility: hidden;
}
* html & { height: 1px }
}
2 引用 @include
@include 指令用于在文档中引用混合样式mixin。格式是在其后添加混合名称,并传递需要的参数(可选)。由mixin定义的样式可以包含在当前规则中。
语法: @include 混合指令名称( 参数[可选] )
附:为便于书写,
@include
可以用+
表示;即: +混合指令名称( 参数[可选] )
可在规则块中引用mixin;也可在最外层引用混合样式,不会直接定义属性,也不可以使用父选择器
-
混合样式中也可以包含其他混合样式
@mixin highlighted-background { background-color: #fc0; } @mixin does-parent-exist { @if & { // 如果父选择器存在,那么就给父元素添加hover样式 &:hover { /* 查看一下&的值: #{&} */ color: red; } } @else { a { @include highlighted-background; // 混合样式中也可以包含其他混合样式 color: red; } } } div p{ @include does-parent-exist(); } // 在嵌套规则块中引用mixin @include does-parent-exist(); // 直接在代码最外层引用mixin // 编译结果 div p:hover { /* 查看一下&的值: div p:hover */ color: red; } a { background-color: #fc0; color: red; }
3 参数 (Arguments)
参数用于给混合指令中的样式设定变量,并且赋值使用。在定义混合指令的时候,按照变量的格式,通过逗号分隔,将参数写进圆括号里。引用指令时,按照参数的顺序,再将所赋的值对应写进括号:
定义: @mixin 混合指令名称( param2, ... ) { // css code, sass code... }
引用: @include 混合指令名称( val2, ... )
两种参数类型:关键字参数,可变参数
-
【关键字参数】引用mixin时使用
@include mixin-name($param1: $val1, $param2: $val2, ... )
- 关键词参数可以打乱顺序使用,如果使用默认值也可以省缺
- 参数名被视为变量名,下划线、短横线可以互换使用
-
【可变参数变量】
- 用于声明mixin
@mixin mixin-name( $args...)
- 用于引用mixin
@include mixin-name( $vals...)
- 用于声明mixin
// 定义了两个参数$color和$width, $width的缺省值为 1in
@mixin sexy-border($color, $width: 1in) {
border: {
color: $color;
width: $width;
style: dashed;
}
}
h1 { @include sexy-border($color: blue, $width: 2in); } // 【关键字参数】
p { @include sexy-border(blue); } // 只传入一个参数$color, 使用$width的默认值
// 【可变参数变量】 用于引用mixin
$values: #ff0000, 2in;
h2{ @include sexy-border($values...); }
// 编译结果
h1 { border-color: blue; border-width: 2in; border-style: dashed; }
p { border-color: blue; border-width: 1in; border-style: dashed; }
h2 { border-color: blue; border-width: 2in; border-style: dashed; }
可变参数变量:用于声明mixin
// 用于声明mixin
@mixin box-shadow($shadows...) { // 参数变量 用于定义mixin
-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 wrapped-stylish-mixin($args...) {
font-weight: bold;
@include stylish-mixin($args...);
}
@mixin stylish-mixin($args...){
/* #{$args} */
color: nth($args, 1);
width: nth($args, 2);
}
.stylish {
@include wrapped-stylish-mixin(#00ff00, $width: 100px);
}
// .stylish { font-weight: bold; /* #00ff00, 100px */ color: #00ff00; width: 100px; }
4 导入代码块
在引用混合样式的时候,可以先将一段代码导入到混合指令中,然后再输出混合样式,额外导入的部分将出现在 @content
标志的地方。
- 若传入的代码块中有用到变量,该变量一定是引用时能够访问到的,而不能是mixin内部的
- 也就是说,在引用时 —— 先计算再传递给mixin
- 当
@content
在指令中出现过多次或者出现在循环中时,额外的代码将被导入到每一个地方。
$color-1: white;
$color: red;
@mixin colors($color: blue) {
background-color: $color;
@content;
border-color: $color;
}
.colors {
@include colors { color: $color-1; } //传递的内容块在引用时就计算,所以引用的变量不能时mixin内的
}
// 编译结果
.colors { background-color: blue; color: white; border-color: blue; }
函数指令
@function 自定义函数名(param2 ...){
@return 返回值
}调用:
自定义函数名(val1, val2 ...);
或者自定义函数名($param1: val1, $param2: val2 ...);
Sass 支持自定义函数,并能在任何属性值或 Sass script 中使用
- 【命名约定】为了避免命名冲突,函数名称可以带前缀,以便可以轻松区分;函数和其他Sass标识符可以交替使用下划线(_)和连字符( - )
- 就像mixin一样,函数也可以访问全局定义的变量,也可以接受参数,也支持变量参数。
- 应该使用 @return 来调用函数的返回值。
- 可以使用关键字参数调用SASS定义的函数
fn-name( $param1: val1, $param2: val2 ... )
$grid-width: 40px;
$gutter-width: 10px;
@function grid-width($n) {
@return $n * $grid-width + ($n - 1) * $gutter-width;
}
#sidebar { width: grid-width(5); } // 使用关键字参数调用 width: grid-width($n: 5);