本篇主要内容是sass的语法基础,样式规则以及一些重大的改变
1. 语法
1.1. Overview
其实是css语法的一个扩展,所有任何css的语法都可以在sass里写
1.2. 样式表的基本结构
1.2.1. 语句Statements
1.2.1.1. 通用语句
- 变量声明,
$var1: value1
- 流程控制,
@if @each @for
等等
- 调试和错误警告信息,
@debug @error @warn
1.2.1.2. CSS语句
- 样式规则
- css的at-rules,
@media @font-face
- mixin的使用,
@include
@at-root
1.2.1.3. 顶级语句
和样式本身无关
- 模块的加载
@use @forward
- 导入
@import
- mixin的声明
@mixin
- 函数定义
@function
1.2.1.4. 其它语句
- 属性声明, 基本的属性语法
width: 100%;
- 继承
@extend
1.2.2. 表达式Expressions
表达式位于属性声明的右侧,或者变量声明的右侧,表达式可以产生值
1.2.2.1. 字面量
一些静态的值类型
- Numbers, 有单位和无单位的数值,
12
or 100px
.
- Strings, 有引号和无引号的字符串
"Helvetica Neue"
or bold
.
- Colors, 颜色值或者枚举值
#c6538c
or blue
.
- boolean
true
or false
.
- 单一的空值
null
.
- Lists of values, 列表类型数值
1.5em 1em 0 2em
, Helvetica, Arial, sans-serif
, or [col1-start]
.
- Maps 键值对类型数值
("background": red, "foreground": pink)
.
1.2.2.2. 操作符
==
and !=
判断真假
+
, -
, *
, /
, and %
数学计算
<
, <=
, >
, and >=
比较运算
and
, or
, and not
真假运算
+
, -
, and /
字符串拼接
(
and )
提升操作符的优先级.
1.2.2.3. 其它表达式
- Variables, 一个变量值引用
$var
.
- Function calls, 函数调用 比如
nth($list, 1)
or var(--main-bg-color)
- Special functions, 特殊函数,比如
calc(1px + 100%)
or url(http://myapp.com/assets/logo.png)
, that have their own unique parsing rules.
- The parent selector, 父选择器
&
.
- The value
!important
, which is parsed as an unquoted string.
1.3. 注释
1.3.1. SCSS里的注释
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
// This comment won't be included in the CSS.
/* But this comment will, except in compressed mode. */
/* It can also contain interpolation:
* 1 + 1 = #{1 + 1} */
/*! This comment will be included even in compressed mode. */
p /* Multi-line comments can be written anywhere
* whitespace is allowed. */ .sans {
font: Helvetica, // So can single-line commments.
sans-serif;
}
|
1.3.2. SASS里注释
1
2
3
4
5
6
7
8
9
10
11
12
|
// This comment won't be included in the CSS.
This is also commented out.
/* But this comment will, except in compressed mode.
/* It can also contain interpolation:
1 + 1 = #{1 + 1}
/*! This comment will be included even in compressed mode.
p .sans
font: Helvetica, /* Inline comments must be closed. */ sans-serif
|
1.3.3. 文档型注释
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
/// Computes an exponent.
///
/// @param {number} $base
/// The number to multiply by itself.
/// @param {integer (unitless)} $exponent
/// The number of `$base`s to multiply together.
/// @return {number} `$base` to the power of `$exponent`.
@function pow($base, $exponent) {
$result: 1;
@for $_ from 1 through $exponent {
$result: $result * $base;
}
@return $result;
}
|
参考:Sass: Comments (sass-lang.com)
1.4. 特殊方法
大部分css里的函数在sass脚本里都能正常工作,以下的几个函数比较特殊,在sass里有不同的意义
说白了下面这些函数在使用的过程中可以利用sass的表达式或者插值之类特性
1.4.1. url()
不带引号的,在sass里会被理解为表达式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
$roboto-font-path: "../fonts/roboto";
@font-face {
// This is parsed as a normal function call that takes a quoted string.
src: url("#{$roboto-font-path}/Roboto-Thin.woff2") format("woff2");
font-family: "Roboto";
font-weight: 100;
}
@font-face {
// This is parsed as a normal function call that takes an arithmetic
// expression.
src: url($roboto-font-path + "/Roboto-Light.woff2") format("woff2");
font-family: "Roboto";
font-weight: 300;
}
@font-face {
// This is parsed as an interpolated special function.
src: url(#{$roboto-font-path}/Roboto-Regular.woff2) format("woff2");
font-family: "Roboto";
font-weight: 400;
}
|
1.4.2. calc()
, clamp()
, element()
, progid:...()
, and expression()
这些函数里可以使用插值,除了这种情况,sass不解析他们
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
@use "sass:math";
.logo {
$width: 800px;
width: $width;
position: absolute;
left: calc(50% - #{math.div($width, 2)});
top: 0;
}
// 输出
@use "sass:math";
.logo {
width: 800px;
position: absolute;
left: calc(50% - 400px);
top: 0;
}
|
1.4.3. min()
和max()
这两个函数,如果里面有插值, 则为css语法,如果有表达式则被解释为sass语法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
$padding: 12px;
.post {
// Since these max() calls don't use any Sass features other than
// interpolation, they're compiled to CSS max() calls.
padding-left: max(#{$padding}, env(safe-area-inset-left));
padding-right: max(#{$padding}, env(safe-area-inset-right));
}
.sidebar {
// Since these refer to a Sass variable without interpolation, they call
// Sass's built-in max() function.
padding-left: max($padding, 20px);
padding-right: max($padding, 20px);
}
|
1.4.4. 参考
2. 样式规则
2.1. Overview
样式规则是css中基础中的基础,通过在选择器上的属性定义来达到外观布局等等效果
2.1.1. 嵌套
嵌套使得我们的样式文件结构更清晰,并且避免了无意的对其它外层元素的影响
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
nav {
ul {
margin: 0;
padding: 0;
list-style: none;
}
li { display: inline-block; }
a {
display: block;
padding: 6px 12px;
text-decoration: none;
}
}
// 输出
nav ul {
margin: 0;
padding: 0;
list-style: none;
}
nav li {
display: inline-block;
}
nav a {
display: block;
padding: 6px 12px;
text-decoration: none;
}
|
2.1.1.1. 选择器列表
sass能够很智能的进行组合
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
.alert, .warning {
ul, p {
margin-right: 0;
margin-left: 0;
padding-bottom: 0;
}
}
// 输出
.alert ul, .alert p, .warning ul, .warning p {
margin-right: 0;
margin-left: 0;
padding-bottom: 0;
}
|
2.1.1.2. 组合选择器
您也可以嵌套使用组合器的选择器。 您可以将组合器放在外部选择器的末尾,内部选择器的开头,甚至可以单独放在两者之间。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
ul > {
li {
list-style-type: none;
}
}
h2 {
+ p {
border-top: 1px solid gray;
}
}
p {
~ {
span {
opacity: 0.8;
}
}
}
//输出
ul > li {
list-style-type: none;
}
h2 + p {
border-top: 1px solid gray;
}
p ~ span {
opacity: 0.8;
}
|
2.1.1.3. 更高级的嵌套
参考下面的父选择器章节
注意: 后代选择器,空格分开的选择器组合,如果使用&
父选择器, 编译结果父选择器是最后一个,看下面的示例
1
2
3
4
5
6
7
8
9
10
|
.cls1 .cls2 {
&.cls3 {
font-size: 18px;
}
}
// 输出
.cls1 .cls2.cls3 {
font-size: 18px;
}
|
2.1.2. 插值
选择器在sass里也是可以用插值的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
@mixin define-emoji($name, $glyph) {
span.emoji-#{$name} {
font-family: IconFont;
font-variant: normal;
font-weight: normal;
content: $glyph;
}
}
@include define-emoji("women-holding-hands", "👭");
// 输出
@charset "UTF-8";
span.emoji-women-holding-hands {
font-family: IconFont;
font-variant: normal;
font-weight: normal;
content: "👭";
}
|
sass是先解析插值再解析选择器,所以可以放心的在选择器上使用差值
2.2. 属性声明
2.2.1. 插值
属性的声明也是可以自由的使用插值的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
@mixin prefix($property, $value, $prefixes) {
@each $prefix in $prefixes {
-#{$prefix}-#{$property}: $value;
}
#{$property}: $value;
}
.gray {
@include prefix(filter, grayscale(50%), moz webkit);
}
// 输出
.gray {
-moz-filter: grayscale(50%);
-webkit-filter: grayscale(50%);
filter: grayscale(50%);
}
|
2.2.2. 嵌套(声明)
属性的声明也是可以嵌套的,因为如 font-
, border-
, padding-
等等很多都是前缀相同的,利用sass可以少打好多字
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
.enlarge {
font-size: 14px;
transition: {
property: font-size;
duration: 4s;
delay: 2s;
}
&:hover { font-size: 36px; }
}
// 输出
.enlarge {
font-size: 14px;
transition-property: font-size;
transition-duration: 4s;
transition-delay: 2s;
}
.enlarge:hover {
font-size: 36px;
}
|
甚至有些,前缀本身可以有值的,可以这样写
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
.info-page {
margin: auto {
bottom: 10px;
top: 2px;
}
}
// 输出
.info-page {
margin: auto;
margin-bottom: 10px;
margin-top: 2px;
}
|
2.2.3. 隐藏声明
如果sass发现有的表达式的值为null
或者为没有引号的空字符串, 那sass解析时会忽略这个属性的定义
1
2
3
4
5
6
|
$rounded-corners: false;
.button {
border: 1px solid black;
border-radius: if($rounded-corners, 5px, null); // 这个会被忽略
}
|
2.2.4. 自定义属性
css允许自定义属性,一般是指变量声明, 并且这些属性的主要意义是提供给js访问, 所有标记都会原封不动的解释为css语言,除非里面使用了插值
自定义属性除非有插值,否则都被认为是css语法,sass不做任何处理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
$primary: #81899b;
$accent: #302e24;
$warn: #dfa612;
:root {
--primary: #{$primary};
--accent: #{$accent};
--warn: #{$warn};
// Even though this looks like a Sass variable, it's valid CSS so it's not
// evaluated.
--consumed-by-js: $primary;
}
// 输出
:root {
--primary: #81899b;
--accent: #302e24;
--warn: #dfa612;
--consumed-by-js: $primary;
}
|
注意:
插值会删除字符串的引号,如果需要使用meta.inspect()
来保留引号
1
2
3
4
5
6
7
8
9
|
@use "sass:meta";
$font-family-sans-serif: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto;
$font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas;
:root {
--font-family-sans-serif: #{meta.inspect($font-family-sans-serif)};
--font-family-monospace: #{meta.inspect($font-family-monospace)};
}
|
2.3. 父选择器
在sass里&
是一个特殊的占位符,表示父选择器,在内嵌样式中非常常见和重要,它和别的组合起来可以实现父选择器的伪类,组合等等
简单的使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
.alert {
// The parent selector can be used to add pseudo-classes to the outer
// selector.
&:hover {
font-weight: bold;
}
// It can also be used to style the outer selector in a certain context, such
// as a body set to use a right-to-left language.
[dir=rtl] & {
margin-left: 0;
margin-right: 10px;
}
// You can even use it as an argument to pseudo-class selectors.
:not(&) {
opacity: 0.8;
}
}
// 输出
.alert:hover {
font-weight: bold;
}
[dir=rtl] .alert {
margin-left: 0;
margin-right: 10px;
}
:not(.alert) {
opacity: 0.8;
}
|
父选择器暂时只能出现在开头
父选择器作为表达式用来得到父选择器的字面值,无论是组合关系列表等等
1
2
3
4
5
6
7
8
9
10
11
12
13
|
.main aside:hover,
.sidebar p {
parent-selector: &;
// => ((unquote(".main") unquote("aside:hover")),
// (unquote(".sidebar") unquote("p")))
}
// 输出
.main aside:hover,
.sidebar p {
parent-selector: .main aside:hover, .sidebar p;
}
|
父选择器在出现在逻辑判断中
比如下面,使得mixin可以有选择的混合
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
@mixin app-background($color) {
#{if(&, '&.app-background', '.app-background')} {
background-color: $color;
color: rgba(#fff, 0.75);
}
}
@include app-background(#036);
.sidebar {
@include app-background(#c6538c);
}
// 输出
.app-background {
background-color: #036;
color: rgba(255, 255, 255, 0.75);
}
.sidebar.app-background {
background-color: #c6538c;
color: rgba(255, 255, 255, 0.75);
}
|
更高级的内嵌用法
利用函数selector.unify
组合父与子选择器,在用@at-root
样式提取到外层
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
@use "sass:selector";
@mixin unify-parent($child) {
@at-root #{selector.unify(&, $child)} {
@content;
}
}
.wrapper .field {
@include unify-parent("input") {
/* ... */
}
@include unify-parent("select") {
/* ... */
}
}
// 输出
.wrapper input.field {
/* ... */
}
.wrapper select.field {
/* ... */
}
|
可以看到,这样做解决了一个问题, 将父选择器放到了组合选后面, 因为目前&
只能用在表达式或者属性字面的开头,这样变相实现了父选择器的位置变换
这里@at-root
的作用是明确,不要放到父选择器的下面了
如果去掉@at-root
,结果如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
@use "sass:selector";
@mixin unify-parent($child) {
#{selector.unify(&, $child)} {
@content;
}
}
.wrapper .field {
@include unify-parent("input") {
/* ... */
}
@include unify-parent("select") {
/* ... */
}
}
// 输出
.wrapper .field .wrapper input.field {
/* ... */
}
.wrapper .field .wrapper select.field {
/* ... */
}
|
2.4. 占位符选择器
占位符定义的样式,在sass编译会被删除,哪怕是组合选择器里有占位符选择器,编译后也不存在, 下面例子,两种都被删除掉了
1
2
3
4
5
6
7
8
9
10
11
12
13
|
.alert:hover, %strong-alert {
font-weight: bold;
}
%strong-alert:hover {
color: red;
}
// 编译后
.alert:hover {
font-weight: bold;
}
|
一般结合@extend
来使用占位符选择器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
%toolbelt {
box-sizing: border-box;
border-top: 1px rgba(#000, .12) solid;
padding: 16px 0;
width: 100%;
&:hover { border: 2px rgba(#000, .5) solid; }
}
.action-buttons {
@extend %toolbelt;
color: #4285f4;
}
.reset-buttons {
@extend %toolbelt;
color: #cddc39;
}
// 输出
.action-buttons, .reset-buttons {
box-sizing: border-box;
border-top: 1px rgba(0, 0, 0, 0.12) solid;
padding: 16px 0;
width: 100%;
}
.action-buttons:hover, .reset-buttons:hover {
border: 2px rgba(0, 0, 0, 0.5) solid;
}
.action-buttons {
color: #4285f4;
}
.reset-buttons {
color: #cddc39;
}
|
3. 重大改变(未完)
3.1. Overview
3.2. Slash和Division
3.3. 颜色单位
3.4. 扩展复合选择器
3.5. CSS变量语法
CSS本身支持--
开头的变量定义,通过var()
方法进行调用, 但是在SASS中注意尽量使用差值来给属性赋值,由于历史原因,如果不使用差值会被解析成CSS语法,
值没有被替换.
1
2
3
4
5
6
7
8
9
|
$accent-color: #fbbc04;
:root {
// WRONG, will not work in recent Sass versions.
--accent-color-wrong: $accent-color;
// RIGHT, will work in all Sass versions.
--accent-color-right: #{$accent-color};
}
|
生成如下
1
2
3
4
|
:root {
--accent-color-wrong: $accent-color;
--accent-color-right: #fbbc04;
}
|