Sass 提供了嵌套的书写方式,用以简化选择器的书写,同时也带来了“作用域”。
嵌套
选择器嵌套
在 Sass 中,可以在父选择器中写子选择器,以嵌套的形式来表达关联的关系,这样做可以减少我们重复书写父选择器的工作量。
代码语言:javascript复制#content {
#article {
h1 {
color: red;
}
p {
color: grey;
}
}
}
编译后
代码语言:javascript复制#content #article h1 {
color: red;
}
#content #article p {
color: grey;
}
在编译时,Sass 会递归遍历所有嵌套关系,从最内层选择器开始,逐层在前面加上父选择器。
父选择器 &
在 CSS 中,基本选择器分为以下几种:
- ID 选择器,如 #id
- 类选择器,如 .class
- 标签选择器,如 div、p
- 属性选择器,如 [lang='en']
- 伪类选择器,如 a:hover、div:first-child
- 伪元素选择器,如 p::before、p::after
其中,伪类和伪元素选择器需要与别的选择器复合使用,以确定是哪些元素的伪类或伪元素。而其它选择器也可以复合使用,如 div#id、div.class、div[lang='en'] 等。
Sass 为了在嵌套中更好地表达这些复合关系,提供了父选择器 &。
代码语言:javascript复制div {
content: '#{&}'; // 将 & 当做变量使用
&#app { color: green; }
&.app { color: blue; }
&:hover { color: red; }
&:first-child { color: grey; }
&::before { content: ''; }
}
编译后
代码语言:javascript复制div { content: "div"; }
div#app { color: green; }
div.app { color: blue; }
div:hover { color: red; }
div:first-child { color: grey; }
div::before { content: ''; }
可以看到,如果把 & 当做变量使用,它被编译为了父选择器。 要注意的是,在复合选择器中,& 只能放在开头使用。
群组选择器
在 CSS 中,可以用逗号分隔多个选择器,形成一个群组。元素只要满足群组中任何一个选择器,都会使用群组对应的样式进行渲染,如
代码语言:javascript复制a, span, label {
color: grey;
}
在 Sass 中,我们可以使用嵌套的形式来简写群组。
代码语言:javascript复制.container {
h1, h2, h3 { margin-bottom: .8em; }
}
nav, aside {
a { color: blue; }
}
编译后
代码语言:javascript复制.container h1, .container h2, .container h3 {
margin-bottom: .8em;
}
nav a, aside a {
color: blue;
}
组合选择器 >、 、~
组合选择器:
- > 为子选择器,如 div > p,选中条件:
- 节点为 div 的邻层子节点
- 节点标签为 p
- 为相邻兄弟选择器,如 div p,选中条件:
- 节点为 div 后面的第一个节点
- 节点标签为 p
- ~ 为同层后续选择器,如 div ~ p,选中条件:
- 节点为 div 后面的同层节点
- 节点标签为 p
对于组合选择器,直接嵌套就可以了。
代码语言:javascript复制article {
~ article { border-top: 1px dashed #ccc }
> section { background: #eee }
dl > {
dt { color: #333 }
dd { color: #555 }
}
nav & { margin-top: 0 }
}
编译后
代码语言:javascript复制article ~ article { border-top: 1px dashed #ccc }
article > footer { background: #eee }
article dl > dt { color: #333 }
article dl > dd { color: #555 }
nav article { margin-top: 0 }
属性嵌套
除了可以嵌套书写选择器,还可以嵌套书写属性,如
代码语言:javascript复制nav {
border: {
style: solid;
width: 1px;
color: #ccc;
}
}
编译后
代码语言:javascript复制nav {
border-style: solid;
border-width: 1px;
border-color: #ccc;
}
作用域
Sass 引入了嵌套,出现了嵌套层级,自然也就有了“层级作用域”。
变量作用域
在 Sass 中,变量只能在它被声明的层级和子层级访问;如果一个变量在不同层级中被重复定义,在使用时会从下到上寻找最近的定义。这与 JS 中的函数作用域相似。
代码语言:javascript复制.inner {
$width: 10px;
width: $width;
p {
width: $width / 2;
}
}
编译后
代码语言:javascript复制.inner { width: 10px; }
.inner p { width: 5px; }
如果变量仅在子级被定义,而在父级被访问,编译时会报错。
代码语言:javascript复制Undefined variable: "$width".
@import
@import 是 CSS2 原生支持的指令,由于 CSS 只有在执行到这条指令时,才会去加载对应的文件,这样会导致页面闪烁和加载变慢,所以平时并不常用。
Sass 改进了这条指令,它会在编译时将导入的资源直接替换并插入指令所在的位置。
因此,如果 @import 导入的资源位置在嵌套层级中,那么:
- 资源中的变量只在当前层级中可用
- 资源中的选择器在编译时会带上父级前缀
// _source.scss
$width: 10px;
p {
color: red;
font-size: 14px;
}
代码语言:javascript复制// index.scss
@import '_source';
$width: 20px;
.outer {
width: $width;
.inner {
@import '_source';
width: $width;
}
}
编译后
代码语言:javascript复制p { color: red; font-size: 14px; }
.outer { width: 20px; }
.outer .inner { width: 10px; }
.outer .inner p { color: red; font-size: 14px; }
在使用 @import 导入文件时,可以不写 .scss 或 .sass 后缀。
如果资源是作为专被引用的公共资源,规范的命名方法是在名称前加下划线。
以下几种情况,Sass 会将 @import 编译为原生的 CSS 指令:
- 资源文件后缀为 .css
- 资源以 URL 地址的形式导入
- 资源以 CSS 的 url() 方法导入
@media
@media 是 CSS 原生支持的指令,用于查询设备媒体,以便做响应式布局。
Sass 对 @media 做了一些改进,允许我们在嵌套的过程中书写媒体查询和响应代码。在编译时, Sass 会把媒体查询编译到文件最外层,并为子选择器加上父选择器前缀。
代码语言:javascript复制$media-prop: min-width;
$media-middle-width: 1200px;
$media-large-width: 1980px;
.container {
.left {
font-size: 12px;
@media screen and ($media-prop: $media-middle-width) {
font-size: 14px;
}
}
.right {
font-size: 14px;
@media screen {
@media ($media-prop: $media-middle-width) {
font-size: 18px;
}
@media ($media-prop: $media-large-width) {
font-size: 22px;
}
}
}
}
编译后
代码语言:javascript复制.container .left {
font-size: 12px;
}
@media screen and (min-width: 1200px) {
.container .left {
font-size: 14px;
}
}
.container .right {
font-size: 14px;
}
@media screen and (min-width: 1200px) {
.container .right {
font-size: 18px;
}
}
@media screen and (min-width: 1980px) {
.container .right {
font-size: 22px;
}
}
使用 Sass 媒体查询的好处:
- 以前使用原生 CSS 做响应式布局时,我们需要先写好不同的媒体查询区块,整理出元素在不同设备的特殊样式,然后写入对应的区块。一个元素的样式分散在不同的媒体查询中,维护起来比较麻烦。
- 在 Sass 中,我们可以在写完一个元素的公共样式之后,直接在下面嵌套媒体查询,所有的响应代码和这个元素都写在同一块地方,维护起来非常方便。