整理下sass的常用语法
1、变量
sass中可以使用变量,变量名以$
开头:
$c: #fff;
body {
color: $c;
}
/* 编译成css */
body {
color: #fff;
}
注意变量声明遵循实现了块级作用域,如果在选择器内声明的变量,只能在选择器内部使用:
// 正确案例
body {
width: 100%;
height: 100%;
$c: red;
#app {
color: $c;
}
}
/* 编译成css */
body {
width: 100%;
height: 100%;
}
body #app {
color: red;
}
// 错误案例
body {
width: 100%;
height: 100%;
$c: red;
}
.box {
color: $c;
}
// 错误 Error: Undefined variable: "$c"
如果要在选择器内声明全局变量,需要使用!global
body {
width: 100%;
height: 100%;
$c: red !global;
}
.box {
color: $c;
}
/* 编译成css */
body {
width: 100%;
height: 100%;
}
.box {
color: red;
}
变量除了在属性值内使用,也可用于属性名或者注释中,但是需要使用#{}
包裹:
$c: color;
#app {
background-#{color}: red;
}
/* 编译成css */
#app {
background-color: red;
}
$lang: css;
/* 编译成#{$lang} */
/* 编译成css */
2、嵌套语法
sass中可以将子标签嵌套在父标签中,避免了使用父子选择器
时重复书写父标签:
$c: #fff;
body {
color: $c;
#app {
width: 100%;
height: 100%;
}
}
/* 编译成css */
body {
color: #fff;
}
body #app {
width: 100%;
height: 100%;
}
如果要在嵌套语法中使用父级选择器,使用&
即可,它会被替换成父级选择器,常用于:hover
、::before
等:
a {
&:hover {
color: red;
}
}
/* 编译成css */
a:hover {
color: red;
}
3、继承
使用@extend
可以继承样式:
body {
.flex {
display: flex;
justify-content: space-around;
align-items: center;
flex-wrap: wrap;
}
.container {
@extend .flex;
width: 100%;
height: 100%;
color: #000;
}
}
/* 编译成css */
body .flex, body .container {
display: flex;
justify-content: space-around;
align-items: center;
flex-wrap: wrap;
}
body .container {
width: 100%;
height: 100%;
color: #000;
}
如果要继承多个样式,可以使用多次@extend
,也可以使用逗号分隔:
body {
#app {
width: 100%;
height: 100%;
}
.container {
color: pink;
}
.box {
@extend #app, .container;
}
}
/* 编译成css */
body #app, body .box {
width: 100%;
height: 100%;
}
body .container, body .box {
color: pink;
}
注意:使用媒体响应时,只能继承@media内的样式,不能继承外部样式,因为这样会编译出很多不必要的样式,因此sass编译时会报错
正确做法:
@media screen {
body {
width: 100%;
}
#app {
@extend body;
}
}
/* 编译成css */
@media screen {
body, #app {
width: 100%;
}
}
错误做法:
body {
width: 100%;
}
@media screen {
#app {
@extend body;
}
}
// 报错 You may not @extend an outer selector from within @media.
// You may only @extend selectors within the same directive.
有时候我们只是想提取一个公共样式,但是并不想它作为选择器出现在编译后的css中。这时可以使用占位符,占位符用%
开头:
// 案例1
%center {
width: 200px;
height: 200px;
margin: 0 auto;
}
#app {
@extend %center;
color: #000;
}
/* 编译成css */
#app {
width: 200px;
height: 200px;
margin: 0 auto;
}
#app {
color: #000;
}
// 案例2
body %center {
width: 200px;
height: 200px;
margin: 0 auto;
}
#app {
@extend %center;
color: #000;
}
/* 编译成css */
body #app {
width: 200px;
height: 200px;
margin: 0 auto;
}
#app {
color: #000;
}
4、注释
sass提供了三种注释,分别是//
、/**/
、/*!*/
,第一种注释在编译后会被去掉,后两种不会,且第三种在压缩后仍会保留,通常用于表示版权信息。
/* 编译成css */
// 我会被去掉
/*! 压缩后我也在 */
body {
width: 100%;
height: 100%;
}
/* 编译成css */
/*! 压缩后我也在 */
body {
width: 100%;
height: 100%;
}
5、根选择器@at-root
实际不应该叫根选择器(css中有个叫根选择器的::root
),而是将被@at-root
包裹的样式放在最顶层。
body {
width: 100%;
height: 100%;
#app {
color: red;
}
@at-root {
.container {
background-color: #fff;
}
}
}
/* 编译成css */
body {
width: 100%;
height: 100%;
}
body #app {
color: red;
}
.container {
background-color: #fff;
}
使用@at-root
的好处是无论嵌套多深,都可以直接在@at-root
中书写顶层样式。
6、运算
sass中可以使用运算,配合变量可以大幅度避免需要手动计算的情况:
$w: 100px;
$h: 300px;
$bw: 1px;
body {
width: $w + 100px;
height: $h - 100px;
border-bottom-width: $bw * 1;
border-top-width: $bw / 1;
}
/* 编译成css */
body {
width: 200px;
height: 200px;
border-bottom-width: 1px;
border-top-width: 1px;
}
注意以下情况/
会被解释成除法:
- 如果值,或值的一部分,是变量或者函数的返回值
- 如果值被圆括号包裹
- 如果值是算数表达式的一部分
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;
width: 1;
height: 250px;
margin-left: 9px;
}
如果要确保/
被解释为除法,使用括号包裹即可。如果不想让/
被解释成除法,可以使用#{}
包裹:
p {
$font-size: 12px;
$line-height: 30px;
font: #{$font-size}/#{$line-height};
}
/* 编译成css */
p {
font: 12px/30px;
}
使用+
可以拼接字符串,字符串是否带引号以左边为准:
p:before {
content: "Foo " + Bar;
font-family: sans- + "serif";
}
/* 编译成css */
p:before {
content: "Foo Bar";
font-family: sans-serif;
}
如果字符串带引号,则可以使用#{}
插入动态的值:
p:before {
content: "I ate #{5 + 10} pies!";
}
/* 编译成css */
p:before {
content: "I ate 15 pies!";
}
和JavaScript
一样,使用圆括号可以改变运算顺序:
p {
height: 1em + 2em * 3;
width: (1em + 2em) * 3;
}
/* 编译成css */
p {
height: 7em;
width: 9em;
}
除了四则运算以外,还可以使用关系判断语句:>
、<
、>=
、<=
、==
、!=
。其中前四个只能用于数值,后两个可用于任意类型。它们都返回布尔值,常用于判断语句。
sass中的数据类型如下:
- 数字,
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)
7、导入(import)
sass提供了导入功能,使用@import
即可:
@import "common.scss";
需要注意的是,如果没有提供后缀名,sass会尝试按照后缀名scss
和sass
查找文件。以下情况sass不会进行解析,而是原样导入:
- 指定了文件扩展名为
css
- 文件路径以
http://
开头 - 使用的是css的导入语法
@import url(路径)
@import
包含媒体查询
@import "normalize.css";
@import "http://foo.com/bar";
@import url(common.css);
@import "foo" screen;
/* 编译成css */
@import "normalize.css";
@import "http://foo.com/bar";
@import url(common.css);
@import "foo" screen;
8、控制语句
在sass中提供了一些条件判断语句和循环语句:@if
、@else-if
、@else
、@for
、@each
、@while
$type: monster;
p {
@if $type == ocean {
color: blue;
} @else if $type == matador {
color: red;
} @else if $type == monster {
color: green;
} @else {
color: black;
}
}
/* 编译成css */
p {
color: green;
}
@for
的使用有两种格式,一种是@for 变量名 from 开始 through 结束
、@for 变量名 from 开始 to 结束
,它们的区别在于第一种范围是包含开始和结束,而第二种不包括结束。用数学中的开区间和闭区间来表示就是[开始, 结束]
和[开始, 结束)
的区别:
@for $i from 1 through 3 {
.item-#{$i} { width: 2em * $i; }
}
@for $i from 1 to 3 {
.item-#{$i} { height: 2em * $i; }
}
/* 编译成css */
.item-1 {
width: 2em;
}
.item-2 {
width: 4em;
}
.item-3 {
width: 6em;
}
.item-1 {
height: 2em;
}
.item-2 {
height: 4em;
}
@for
只能表示数值范围,如果要循环非数值,需要使用@each
,它可以遍历list
:
@each $var in top, bottom, left, right {
body {
border-#{$var}-width: 1px;
}
}
/* 编译成css */
body {
border-top-width: 1px;
}
body {
border-bottom-width: 1px;
}
body {
border-left-width: 1px;
}
body {
border-right-width: 1px;
}
注意list
既可以用,
分隔,也可以使用空格
分隔,将其理解为数组即可。因此也存在二维的list
@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;
}
}
/* 编译成css */
.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;
}
上面的用法有点类似JavaScript
中同时使用循环和解构:
const list = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
for (const [a, b, c] of list) {
console.log(a, b, c)
}
// 输出
// 1, 2, 3
// 4, 5, 6
// 7, 8, 9
除了可以遍历list
,each
还可以遍历map
:
@each $header, $size in (h1: 2em, h2: 1.5em, h3: 1.2em) {
#{$header} {
font-size: $size;
}
}
/* 编译成css */
h1 {
font-size: 2em;
}
h2 {
font-size: 1.5em;
}
h3 {
font-size: 1.2em;
}
sass里面的 map
类似于JavaScript
中的对象:
const map = { a: 1, b: 2, c: 3 }
for (const [key, value] of Object.entries(map)) {
console.log(key, value)
}
// 输出
// a 1
// b 2
// c 3
最后是while
循环,和JavaScript
类似:
$i: 6;
@while $i > 0 {
.item-#{$i} { width: 2em * $i; }
$i: $i - 2;
}
/* 编译成css */
.item-6 {
width: 12em;
}
.item-4 {
width: 8em;
}
.item-2 {
width: 4em;
}
9、混入(mixin)
mixin通常用于抽离公共样式到独立的文件中,类似于JavaScript
中常见的将工具方法抽离到utils
文件夹中一样,用法类似于函数声明,只是使用时需要借助@include
:
@mixin clearfix {
display: inline-block;
&:after {
content: ".";
display: block;
height: 0;
clear: both;
visibility: hidden;
}
* html & { height: 1px }
}
.box {
@include clearfix;
}
/* 编译成css */
.box {
display: inline-block;
}
.box:after {
content: ".";
display: block;
height: 0;
clear: both;
visibility: hidden;
}
* html .box {
height: 1px;
}
也可以给mixin
传参:
@mixin set-border($w, $c) {
border: solid $w $c;
}
.box {
@include set-border(1px, pink);
}
/* 编译成css */
.box {
border: solid 1px pink;
}
也可以给mixin设置默认值:
@mixin set-border($dir: top, $w: 1px, $c: pink) {
border-#{$dir}: solid $w $c;
}
.box1 {
@include set-border(); // 不传参数时括号也可省略
}
.box2 {
@include set-border(bottom, 2px, purple);
}
/* 编译成css */
.box1 {
border-top: solid 1px pink;
}
.box2 {
border-bottom: solid 2px purple;
}
当不确定参数数量时,可以使用...
:
@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);
}
/* 编译成css */
.shadows {
-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
也可以接受一个列表list
,配合...
,可以一次传入多个参数:
@mixin colors($text, $background, $border) {
color: $text;
background-color: $background;
border-color: $border;
}
$values: #ff0000, #00ff00, #0000ff;
.primary {
@include colors($values...);
}
/* 编译成css */
.primary {
color: #ff0000;
background-color: #00ff00;
border-color: #0000ff;
}
有时候也需要从外部传入一段代码到mixin
,传入的样式代码可以通过@content
得到,这种用法类似于vue
中的默认插槽:
@mixin apply-to-ie6-only {
* html {
@content;
}
}
@include apply-to-ie6-only {
#logo {
background-image: url(/logo.gif);
}
}
/* 编译成css */
* html #logo {
background-image: url(/logo.gif);
}
10、自定义函数
虽然mixin
已经足够强大,但有时我们不需要指定属性名而只是单纯的想要返回属性值,此时可以通过自定义函数,它和mixin
类似,不同点在于它必须有返回值,使用@return
返回。自定义函数使用@function
声明:
$grid-width: 40px;
$gutter-width: 10px;
@function grid-width($n) {
@return $n * $grid-width + ($n - 1) * $gutter-width;
}
#sidebar {
width: grid-width(5);
}
/* 编译成css */
#sidebar {
width: 240px;
}