什么是 SASS ?
SASS 文件有两种文件名后缀,分别是 .sass 和 .scss,.sass 是严格的嵌套缩进规则,而 .scss 的则是跟写 css 代码类似的大括号,分号这样的语法规则。所以个人比较喜欢 .scss 文件名后缀的。
SASS 是什么呢?它是 CSS 的扩展,是 CSS 的预处理。我们通过对 sass 文件进行编译,然后就得到对应的 css 文件。
一些扩展玩意
变量
在 Sass 中可以进行变量的定义,变量名以美元符号开头,形如:
$blue: #007bff !default;
$indigo: #6610f2 !default;
$purple: #6f42c1 !default;
$pink: #e83e8c !default;
$red: #dc3545 !default;
$orange: #fd7e14 !default;
$yellow: #ffc107 !default;
$green: #28a745 !default;
$teal: #20c997 !default;
$cyan: #17a2b8 !default;
这是 bootstrap 的一些颜色变量定义,其中的 !default 表示变量的默认值,即当变量没有赋值(++变量值为 null++)时,就会把该给定的值赋给变量。
变量的作用范围是在它定义的选择器嵌套层级的范围内有效(即类似块级作用域),在变量值后面加上 !global ,则变量的作用域提升为全局作用域。
变量要嵌套在字符串中,就必须要写在 #{} 之中。
// 这是一段添加浏览器厂商前缀的 mixin
@mixin prefix($declarations, $prefixes: ()) {
@each $property, $value in $declarations {
@each $prefix in $prefixes {
#{'-' + $prefix + '-' + $property}: $value;
}
#{$property}: $value;
}
}
嵌套规则
选择器嵌套,css 属性嵌套,例子如下(bootstrap 的小部分样式):
.alert-dismissible {
padding-right: ($close-font-size + $alert-padding-x * 2);
// Adjust close link position
.close {
position: absolute;
top: 0;
right: 0;
padding: $alert-padding-y $alert-padding-x;
color: inherit;
}
}
以上涉及到 Sass 变量的加减乘除运算,即在 Sass 中是可以使用一些运算的,包括数字运算,颜色运算,列表运算等,有兴趣的可以在参考资料下找到具体的解析。
这里 .close 类就是嵌套在 .alert-dismissible 类里层,相当于 css:
.alert-dismissible .close {
/* 属性 */
}
然后我们可以再看下下面的 Sass 代码,分别展示怎么引用父选择器和嵌套属性:
.form-check {
position: relative;
display: block;
margin-bottom: $form-check-margin-bottom;
// & 表示:父选择器
&.disabled {
.form-check-label {
color: $text-muted;
}
}
}
.font-example {
// 嵌套属性
font: {
family: sans-serif;
size: 14rem;
weight: bold;
}
}
@mixin 和 @extend
@mixin 主要是用来实现样式的重用,不用大段代码到处复制粘贴,而且跟 JS 的函数很像,也是可以传递参数的。当然 @mixin 不仅可以包含属性,也可以包含 css 规则,包括选择器和选择器中的属性。
// bootstrap 的清除浮动 mixin
@mixin clearfix() {
&::after {
display: block;
clear: both;
content: "";
}
}
// Sizing shortcuts
@mixin size($width, $height: $width) {
width: $width;
height: $height;
}
// bootstrap _alert.scss
@mixin alert-variant($background, $border, $color) {
color: $color;
// 这里展示了定义了 mixin 之后怎么去引用这个 mixin,也就是把 mixin 的代码拷贝过来
// @include mixin名字(参数)
@include gradient-bg($background);
border-color: $border;
hr {
border-top-color: darken($border, 5%);
}
.alert-link {
// darken 是颜色函数
color: darken($color, 10%);
}
}
@extend className; 也就是继承一个选择器的意思。但这里并不是像 @mixin 一样把代码引进来。
$guter: 5px;
// color
$blue: #007bff !default;
$yellow: #ffc107 !default;
$priamry: $blue !default;
$warning: $yellow !default;
.btn {
padding: $gutter;
display: inline-block;
text-align: center;
white-space: nowrap;
user-select: none;
}
.btn-primary {
@extend .btn;
background-color: $primary;
}
.table {
.btn-warning {
@extend .btn;
background-color: $warning;
}
}
然后让我们看下上面的 sass 编译出来的 css 是怎么样的?看看 @extend 的行为是不是我们了解的。
/* 注意看这里 */
.btn, .btn-primary, .table .btn-warning {
padding: 5px;
display: inline-block;
text-align: center;
white-space: nowrap;
user-select: none;
}
.btn-primary {
background-color: #007bff;
}
.table .btn-waning {
background-color: #ffc107;
}
高级用法
-
条件语句
$alarm-type: danger; p { @if $alarm-type == danger { color: red; } @else if $alarm-type == warning { color: orange; } @else { color: black; } }上述代码编译后的 css 内容:
p { color: red; }条件判断语句,当 @if 后面的条件判断为真时,选择器内容为条件判断紧接着的大括号内的内容;否则是之后 @else 的内容。 即 @else 可以设置条件判断为非真时的内容属性。
-
循环语句
// @for 形式1: @for $index from 1 through 3 { .item-#{$index} { width: 2em * $index; } } // @for 形式2: @for $index from 1 to 3 { .item-#{$index} { height: 2em * $index; } }@for 循环语句,跟 JavaScript 的 for 循环差不多,两种形式,不同点在于 through 和 to,一个是前后闭区间,另一个是前是闭区间,后是开区间。 上述代码编译后的 css 如下,就可以看出区别:
/* @for $index from 1 through 3 */ .item-1 { width: 2em; } .item-2 { width: 4em; } .item-3 { width: 6em; } /* @for $index from 1 to 3 */ .item-1 { height: 2em; } .item-2 { height: 4em; }// 还是用之前的例子,这里的 @each 循环形式 // @each $var in <list or map> @mixin prefix($declarations, $prefixes: ()) { @each $property, $value in $declarations { @each $prefix in $prefixes { #{'-' + $prefix + '-' + $property}: $value; } #{$property}: $value; } } .btn { @include prefix((display: flex), webkit moz ms); }value 分别对应 $declarations 的键值对;上述代码编译后的 css 内容:
.btn { -webkit-display: flex; -moz-display: flex; -ms-display: flex; display: flex; }$num: 4; @while $num > 0 { .item-#{$num} { width: 2em * $num; } $num: $num - 2; }@while 会重复输出嵌套样式,直到条件判断会 false,就会跳出循环;上述代码编译后的 css:
.item-4 { width: 8em; } .item-2 { width: 4em; } -
自定义函数
// 形式 // @function functionName($parameter) { // @return value; // } // 以下是 bootstrap 中的自定义函数 // Color contrast @function color-yiq($color) { $r: red($color); $g: green($color); $b: blue($color); $yiq: (($r * 299) + ($g * 587) + ($b * 114)) / 1000; @if ($yiq >= 150) { @return $yiq-text-dark; } @else { @return $yiq-text-light; } }其中的 red(
color) 和 blue($color) 就是函数的使用方式,它们也是 sass 内置的颜色函数。
模块型目录结构
|-- sass
|-- 0-plugins
| |-- plugins-dir.scss
|
|-- 1-base
| |-- _base-dir.scss
|
|-- 2-layouts
| |-- _layouts-dir.scss
|
|-- 3-mdoules
| |-- _modules-dir.scss
|
|-- _variables.scss
|-- _mixins.scss
|-- app.scss
app.scss 是主入口;
全局变量写在 _variables.scss;
4个文件夹下分别放置对应的入口 sass 文件;
具体解析请查看参考资料。
Questions
CSS 的 @import 和 Sass 的 @import 区别
一开始,我也是不清楚的,只知道都鼓励不要用 CSS 的 @import。为什么呢?因为只有执行到 CSS 文件中的 @import,浏览器才回去下载 @import 进来的 CSS 文件,这样就增加了下载时间、渲染响应时间,不利于页面的优化,也使用户体验不好。
Sass 的 @import 是会在编译生成 CSS 文件时就把相对应的文件 import 进去,即编译出来的 CSS 不需要再去请求下载 @import 的文件,因为此文件的内容已经导入到 编译好的 CSS 文件了。
一些 Sass 文件以下划线(_)开头是什么意思呢?
有时候你只是需要生成一个或几个 css 文件,而不需要对应的每个 sass 文件都编译生成对应的 css 文件,那么 sass 文件名以下划线开头(_),即告知,编译的时候该文件不会独立生成对应的 css 文件。