Sass 是一种 CSS 的预编译语言,对css进行了扩展,提供了一系列内置的机制,方便以编程的方式编写css,大大提升了css的复用性和灵活性.
本章介绍基础部分,包括安装,变量,差值
1. 什么是sass
Sass 是一种 CSS 的预编译语言。它提供了 变量(variables)、嵌套(nested rules)、 混合(mixins)、 函数(functions)等功能,并且完全兼容 CSS 语法。Sass 能够帮助复杂的样式表更有条理, 并且易于在项目内部或跨项目共享设计。
Features:
- 变量
- 模块化(导入)
- 嵌套
- 操作符
- 函数
- 混合
- 流程控制
- 额外的@(At-Rules)
1.1. Features 1 - Variables
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
|
// ------ Colors ------ //
$white: #ffffff;
$black: #000000;
$gray-100: #f8f9fa;
$gray-200: #e9ecef;
$gray-300: #dee2e6;
$gray-400: #ced4da;
$gray-500: #adb5bd;
$gray-600: #6c757d;
$gray-700: #495057;
$gray-800: #343a40;
$gray-900: #212529;
$blue-100: #caf0f8;
$blue-200: #ade8f4;
$blue-300: #90e0ef;
$blue-400: #48cae4;
$blue-500: #00b4d8;
$blue-600: #0096c7;
$blue-700: #0077b6;
$blue-800: #023e8a;
$blue-900: #03045e;
$green-100: #99e2b4;
$green-200: #88d4ab;
$green-300: #78c6a3;
$green-400: #67b99a;
$green-500: #56ab91;
$green-600: #469d89;
$green-700: #358f80;
$green-800: #248277;
$green-900: #14746f;
$primary: $blue-900;
|
1.2. Features 2 - Nesting
1
2
3
4
5
6
7
8
9
10
11
|
a.common-link {
color: $link-color;
display: inline-block;
padding: 0 0.25rem;
&:hover,
&:focus {
color: $primary;
text-decoration: underline;
}
}
|
1.3. Features 3 - Partials
像其它语言一样可以模块化
1
2
3
4
5
6
7
8
9
10
11
12
|
@import "vendor/utils";
@import "vendor/animation";
@import "common/variables";
@import "common/global";
@import "components/code";
@import "components/markdown";
@import "partial/header";
@import "pages/index"
|
1.4. Features 4 - Extend
同时sass
提供了扩展的特性
1
2
3
4
5
6
7
8
9
10
11
12
|
.btn {
padding: 6px 12px;
line-height: 140%;
text-align: middle;
// ...
}
.bt-reverse {
@extend .btn;
backgroud-color: #FCF4DC;
color: #C61C6F;
}
|
1.5. Features 5 - Operators
操作符
==
和 !=
+ - * /
和 %
> >= < <=
and or not
1
2
|
@debug 1 + 2 * 3 == 1 + (2 * 3); // true
@debug true or false and false == true or (false and false); // true
|
1.6. Features 6 - Mixins
混合是sass的一个特别重要的特性,不同于extend
, 它不需要给任何选择器定义样式, 只是一个名称指代, 并且方便发布到库中在其它项目使用,
mixins
类似方法,使用的时候可以传递变量.@mixins
不是给页面使用的,是给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
|
@mixin clearfix() {
&:before,
&:after {
content: " ";
display: table;
}
&:after {
clear: both;
}
}
.nav-end {
@include clearfix;
}
@mixin rouded($radius: 10px) {
-webkit-border-radius: $radius;
border-radius: $radius;
backgroud-clip: padding-box;
}
ul {
padding: 0;
margin: 0;
list-style: none;
li img {
display: block;
@include rounded(20px);
}
}
|
2. SASS的实现
SASS官方的实现是LibSass
,还有node sass
, ruby sass
和Dart Sass
, 除了Dart Sass
其余的基本已经只处在维护状态, 官方推荐全部转移到Dart Sass
,
其实对于编写Sass样式的用户来说不用太关心实现, 因为这些都会有相应的构建工具或者框架来处理, 比如hugo
, 比如snowpack
, postcss
等等,都会自动配置好
注意: node-sass
是node里的一个sass实现,就是官方说的已经Deprecated,目前推荐使用的是sass/dart-sass: The reference implementation of Sass, written in Dart. (github.com),它的npm包: sass - npm (npmjs.com)
Sass是一门语言, 就像Lua
, Bash
等等一样, 重要的特性就那么多, 所以更新的也很少很少, 总而言之使用Dart Sass
的实现是目前的第一选择.
3. 安装(Dart Sass)
参考:
安装方式有很多种, 这里是用的Dart Sass
的实现
3.1. 独立安装
去Dart-Sass Releases下载指定平台的包, 解压缩,添加到PATH
里
3.2. OS X HomeBrew
1
|
brew install sass/sass/sass
|
3.3. Chocolatey or Scoop(Windows)
1
2
3
|
choco install sass
# or
scoop install sass
|
3.4. NPM
node用户直接npm i -g sass
即可
3.5. 真实的开发环境
然而在实际生产中,我们不可能就简单的使用sass的cli来进行编译,我们的开发模式和流程以及功能需求可能是下面的情况
- 需要结合html和js一起开发
- 需要压缩文件
- 需要合并文件
- 需要整合别的插件
- 需要实时预览,代码修改后即刻出效果
- 新的css语法
- 语法检查
- 自动对浏览器进行转换,添加前缀等等
- 更加方便的语法,比如将属性等等进行了包装和缩减
所以我们通常的前端开发环境是一个带有脚手架的集成环境,包括构建工具,语法检查工具,格式化工具,语法转换,压缩等等
现在无论是集成框架如vue
, react
, 还是像parceljs
, vite
, snowpack
, rome
这样的集成工具链, 还是自搭建的集成环境工具链,在处理样式这方面,最流行的做法是这样的:
一个打包工具,如webpack
, rollup
加上 postcss
(类似js里的babel,做语法转换的)来进行编译,压缩,打包的一体化操作, 再加上一些语法插件
我目前自己配置的开发环境中,工具链如下:
rollup
(打包工具)
rollup-plugin-scss
(sass文件处理插件)
postcss
(sass语法转换器)
autoprefixer
(postcss插件-处理浏览器兼容性的样式属性前缀问题)
postcss-import
(可以在sass里直接import node_modules里的包)
tailwindcss
(tailwind包)
rollup的配置如下:
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
38
39
40
41
42
43
44
45
46
47
48
|
// rollup.config.js
import resolve from "@rollup/plugin-node-resolve";
import commonjs from "@rollup/plugin-commonjs";
import scss from "rollup-plugin-scss";
import autoprefixer from "autoprefixer";
import postcss from "postcss";
import atImport from "postcss-import";
import tailwindcss from "tailwindcss";
const isProduction =
process.env.NODE_ENV === "production" || process.env.BUILD === "production";
export default (async () => ({
input: "src/js/main.js",
output: {
file: "public/js/bundle.js",
format: "iife",
sourcemap: true,
globals: {
jquery: "$",
},
},
external: ["jquery"],
plugins: [
resolve(), // Tells Rollup how to find date-fns in node_modules
commonjs(), // Convert CommonJS modules to ES Modules.
isProduction && (await import("rollup-plugin-terser")).terser(),
scss({
output: "public/css/bundle.css",
sass: require("sass"),
processor: (css) =>
postcss([
autoprefixer({ overrideBrowserslist: "Edge 18" }),
tailwindcss(),
])
.use(atImport())
.process(css, { from: undefined })
.then((result) => result.css),
// Add file/folder to be monitored in watch mode so that changes to these files will trigger rebuilds.
// Do not choose a directory where rollup output or dest is pointed to as this will cause an infinite loop
watch: "src/sass",
// watch: ["src/styles/components", "src/multiple/folders"],
}),
],
}))();
|
4. SASS和SCSS
sass和scss其实是一样的css预处理语言,SCSS 是 Sass 3 引入新的语法,其后缀名是分别为 .sass和.scss两种。
SASS版本3.0之前的后缀名为.sass,而版本3.0之后的后缀名.scss。
两者是有不同的,继sass之后scss的编写规范基本和css一致,sass时代是有严格的缩进规范并且没有{}
和;
。
而scss则和css的规范是一致的。
目前来说, 一半说sass就是指scss了, 基本全部都使用的是scss标准
SCSS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
@mixin button-base() {
@include typography(button);
@include ripple-surface;
@include ripple-radius-bounded;
display: inline-flex;
position: relative;
height: $button-height;
border: none;
vertical-align: middle;
&:hover { cursor: pointer; }
&:disabled {
color: $mdc-button-disabled-ink-color;
cursor: default;
pointer-events: none;
}
}
|
SASS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
@mixin button-base()
@include typography(button)
@include ripple-surface
@include ripple-radius-bounded
display: inline-flex
position: relative
height: $button-height
border: none
vertical-align: middle
&:hover
cursor: pointer
&:disabled
color: $mdc-button-disabled-ink-color
cursor: default
pointer-events: none
|
5. 注释
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
// 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;
}
|
6. 变量 Variables
1
2
3
4
5
6
|
$base-color: #c6538c;
$border-dark: rgba($base-color, 0.88);
.alert {
border: 1px solid $border-dark;
}
|
编译成
1
2
3
|
.alert {
border: 1px solid rgba(198, 83, 140, 0.88);
}
|
6.1. 默认值
为了防止定义的值被覆盖,可以使用!default
, 这样只有在变量没有赋值,或者为null
的时候使用默认值,其它情况使用现有值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
// _library.scss
$black: #000 !default;
$border-radius: 0.25rem !default;
$box-shadow: 0 0.5rem 1rem rgba($black, 0.15) !default;
code {
border-radius: $border-radius;
box-shadow: $box-shadow;
}
// style.scss
@use 'library' with (
$black: #222,
$border-radius: 0.1rem
);
|
编译后
1
2
3
4
|
code {
border-radius: 0.1rem;
box-shadow: 0 0.5rem 1rem rgba(34, 34, 34, 0.15);
}
|
6.2. Built-in Variables
sass提供了一些内建的模块,参考Sass: Built-In Modules (sass-lang.com),里面提供了大量的函数和部分变量可以使用
比如:
1
2
3
|
// 数学模块的pi
@debug math.$pi; // 3.1415926536
|
6.3. 作用域
变量是分全局变量(global)和局部变量(local)的
- 局部变量无法在其它scope使用
- 如果局部变量和全局变量重名, 那么就会有2个变量存在,局部和全局的相互不影响,全局不会改变
- 使用
!global
可以确定使用的是全局变量,并可以进行改变
- 在一个外部的流程控制是可以改变变量的
6.3.1. 不能在局部scope使用局部变量
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
$global-variable: global value;
.content {
$local-variable: local value;
global: $global-variable;
local: $local-variable;
}
.sidebar {
global: $global-variable;
// This would fail, because $local-variable isn't in scope:
// local: $local-variable;
}
|
6.3.2. 全局与局部重名
相互不影响
1
2
3
4
5
6
7
8
9
10
|
$variable: global value;
.content {
$variable: local value;
value: $variable;
}
.sidebar {
value: $variable;
}
|
1
2
3
4
5
6
7
8
9
|
CSS OUTPUT
.content {
value: local value;
}
.sidebar {
value: global value;
}
|
6.3.3. !global标识
强制使用全局变量(如果重名的时候比较有用)
1
2
3
4
5
6
7
8
9
10
|
$variable: first global value;
.content {
$variable: second global value !global;
value: $variable;
}
.sidebar {
value: $variable;
}
|
1
2
3
4
5
6
7
8
|
.content {
value: second global value;
}
.sidebar {
value: second global value;
}
|
6.3.4. 在流程控制里
流程控制里是可以改变全局变量的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
$dark-theme: true !default;
$primary-color: #f8bbd0 !default;
$accent-color: #6a1b9a !default;
@if $dark-theme {
$primary-color: darken($primary-color, 60%);
$accent-color: lighten($accent-color, 60%);
}
.button {
background-color: $primary-color;
border: 1px solid $accent-color;
border-radius: 3px;
}
|
1
2
3
4
5
6
|
.button {
background-color: #750c30;
border: 1px solid #f5ebfc;
border-radius: 3px;
}
|
6.4. 进阶变量函数
sass提供了一些内置的函数,方便对变量进行操作,比如meta.variable-exists()
和meta.global-variable-exists()
用于检查变量是否存在
1
2
3
4
5
6
7
8
9
10
|
@debug meta.global-variable-exists("var1"); // false
$var1: value;
@debug meta.global-variable-exists("var1"); // true
h1 {
// $var2 is local.
$var2: value;
@debug meta.global-variable-exists("var2"); // false
}
|
7. 差值 Interpolation
使用sass的一个重要的特性就是选择器在Interpolation
的帮助下也可以变成灵活可变的, 使用#{}
将变量包含在里面就可以了,不光是选择器,
下面的地方都可以使用Interpolation.
下面对部分进行说明
7.1. 选择器
1
2
3
4
5
6
7
8
9
10
|
@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", "👭");
|
7.2. 属性名
1
2
3
4
5
6
7
8
9
10
|
@mixin prefix($property, $value, $prefixes) {
@each $prefix in $prefixes {
-#{$prefix}-#{$property}: $value;
}
#{$property}: $value;
}
.gray {
@include prefix(filter, grayscale(50%), moz webkit);
}
|
7.3. 自定义属性
7.4. css的At-rule
所有css的At-rule的名字和值都可以用Interpolation
@media
— A conditional group rule that will apply its content if the device meets the criteria of the condition defined using a media query.
@supports
— A conditional group rule that will apply its content if the browser meets the criteria of the given condition.
@document
— A conditional group rule that will apply its content if the document in which the style sheet is applied meets the criteria of the given condition. (deferred to Level 4 of CSS Spec)
@page
— Describes the aspect of layout changes that will be applied when printing the document.
@font-face
— Describes the aspect of an external font to be downloaded.
@keyframes
— Describes the aspect of intermediate steps in a CSS animation sequence.
@viewport
— Describes the aspects of the viewport for small screen devices. (currently at the Working Draft stage)
@counter-style
— Defines specific counter styles that are not part of the predefined set of styles. (at the Candidate Recommendation stage, but only implemented in Gecko as of writing)
@font-feature-values
(plus @swash
, @ornaments
, @annotation
, @stylistic
, @styleset
and @character-variant
) — Define common names in font-variant-alternates
for feature activated differently in OpenType. (at the Candidate Recommendation stage, but only implemented in Gecko as of writing)
@property
— Describes the aspect of custom properties and variables. (currently at the Working Draft stage)
@color-profile
— Allows a color profile to be defined for use by the color()
function.
参考: At-rules - CSS: Cascading Style Sheets | MDN (mozilla.org)
7.5. 一些特殊方法
1
2
3
4
5
6
7
8
9
|
@use "sass:math";
.logo {
$width: 800px;
width: $width;
position: absolute;
left: calc(50% - #{math.div($width, 2)});
top: 0;
}
|
7.6. 其它可以使用差值的示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
// 字符串 有引号或者没有引号
@debug "Roboto #{$roboto-variant}"; // "Roboto Mono"
@debug -#{$prefix}-flex; // -ms-flex
// extend
$error_style = .error
.error {
border: 1px #f00;
background-color: #fdd;
&--serious {
@extend #{$error_style};
border-width: 3px;
}
}
// import
@mixin google-font($family) {
@import url("http://fonts.googleapis.com/css?family=#{$family}");
}
|
8. References