Sass 是什么
CSS 预处理器,它允许您使用变量,嵌套规则,混合,函数等,所有这些都使用完全 CSS 兼容的语法。Sass 有助于保持大型样式表的组织良好,并且可以轻松地在项目内和项目间共享设计。
安装
npm install -g sass
Sass 编译
自动编译 Sass
sass --watch sass:css
修改编译输出的 CSS 格式
Sass 编译输出的格式有四种:
- nested(嵌套,默认格式)
- compact(紧凑)
- expanded(拓展)
- compressed(压缩)
Sass 编译后的格式为拓展
sass --watch sass:css --style expanded
编译后输出的代码:
ul {
font-size: 15px;
}
ul li {
list-style: none;
}
语法
SASS/SCSS
Sass 支持两种不同的语法,SCSS 和 SASS 。
SCSS 是 CSS 的超集,所有合法的 CSS,都是 SCSS 的语法。它不是严格的 CSS 超集。当 Sass 在样式表中遇到无效语法时,解析将失败,并且将向用户显示错误语法的位置及其原因。请注意,这与 CSS 不同,CSS 从大多数错误中恢复而不是立即失败。
@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 使用缩进语法,而不是花括号和分号。
@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
注释
SCSS
/*
* 多行注释会被保留,在压缩输出时不会保留。
*/
/*!
* 强制注释,一直保留在 CSS 里。
*/
// 不会出现在编译后的 CSS 中。
文档注释
使用 Sass 编写样式库时,可以使用注释来记录 库提供的 mixins,function,变量和占位符选择器,以及库本身。这些注释由 SassDoc 工具读取,它使用它们生成漂亮的文档。
文档注释是静默注释,在需要注释正上方写三个斜杠 ///
。SassDoc 将注释中的文本解析为 Markdown,并支持许多有用的注释来详细描述它。
/// 幂运算
///
/// @param {number} $base
/// 基数
/// @param {integer (unitless)} $exponent
/// 指数
/// @return {number} `$base` to the power of `$exponent`.
@function pow($base, $exponent) {
$result: 1;
@for $_ from 1 through $exponent {
$result: $result * $base;
}
@return $result;
}
特殊功能
CSS 定义了许多函数,大多数函数都可以使用 Sass 的普通函数语法。它们被解析为函数调用,解析为纯 CSS 函数,并按原样编译为 CSS。但是有一些特殊的语法,不能仅被解析为 SassScript 表达式。所有特殊函数调用都返回不带引号的字符串。
url()
如果 url()
参数为不带引号的 URL,则 Sass 原样解析它。
$roboto-font-path: "../fonts/roboto";
@font-face {
// 这将被解析为一个普通的函数调用,它接受一个带引号的字符串
src: url("#{$roboto-font-path}/Roboto-Thin.woff2") format("woff2");
font-family: "Roboto";
font-weight: 100;
}
@font-face {
// 这被解析为一个普通的函数调用,它接受一个算术表达式
src: url($roboto-font-path + "/Roboto-Light.woff2") format("woff2");
font-family: "Roboto";
font-weight: 300;
}
@font-face {
// 解析为特殊的插入函数
src: url(#{$roboto-font-path}/Roboto-Regular.woff2) format("woff2");
font-family: "Roboto";
font-weight: 400;
}
calc()、element()、progid:…()、expression()
progid:…(),expression() 在新版浏览器被废弃,Sass 为了向下兼容解析。calc()、element() 在 CSS 规范中
,需要特殊解析。
.logo {
$width: 800px;
width: $width;
position: absolute;
left: calc(50% - #{$width / 2});
top: 0;
}
min()、max()
$padding: 12px;
.post {
// 在插值解析后直接编译为 CSS
padding-left: max(#{$padding}, env(safe-area-inset-left));
padding-right: max(#{$padding}, env(safe-area-inset-right));
}
.sidebar {
// 在插值解析后直接编译为 CSS
padding-left: max($padding, 20px);
padding-right: max($padding, 20px);
}
样式规则
概述
样式规则是 Sass 的基础,就像它们用于CSS一样,它们的工作方式相同。
.button {
padding: 3px 10px;
font-size: 12px;
border-radius: 3px;
border: 1px solid #e1e4e8;
}
嵌套
Sass 让你编写更少的代码。您可以在另一个内部编写一个样式规则,而不是一遍又一遍地重复相同的选择器。Sass 会自动将外部规则的选择器与内部规则组合在一起。
nav {
ul {
margin: 0;
padding: 0;
list-style: none;
}
li { display: inline-block; }
a {
display: block;
padding: 6px 12px;
text-decoration: none;
}
}
⚠️注意
嵌套规则非常有用,但难以直观地显示您实际生成的 CSS 数量。嵌套越深,提供 CSS 所需的代码就越多,浏览器渲染它所需的工作就越多。要注意嵌套的层次不要太深!
选择器列表
嵌套规则很聪明地处理选择器列表(即逗号分隔的选择器)。每个复杂选择器(逗号之间的选择器)分别嵌套,然后将它们组合回选择器列表。
.alert, .warning {
ul, p {
margin-right: 0;
margin-left: 0;
padding-bottom: 0;
}
}
选择器组合器
您也可以嵌套使用组合子选择器。您可以将组合子选择器放在外部选择器的末尾,内部选择器的开头,或者甚至是两者之间。
ul > {
li {
list-style-type: none;
}
}
h2 {
+ p {
border-top: 1px solid gray;
}
}
p {
~ {
span {
opacity: 0.8;
}
}
}
插值
您可以使用插值将变量和函数调用等表达式中的值注入选择器。这在您编写 mixins 时特别有用,因为它允许您根据用户传入的参数创建选择器。
@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", "👭");
💡有趣的事实
Sass 仅解析插值后解析选择器。这意味着您可以安全地使用插值生成选择器的任何部分,而不必担心它不会解析。
您可以将插值与父选择器 &
,@at-root
规则和选择器功能结合使用,以在动态生成选择器时发挥一些强大的功能。
属性声明
声明的值可以是任何 SassScript 表达式,它将被评估并包含在结果中。
.circle {
$size: 100px;
width: $size;
height: $size;
border-radius: $size / 2;
}
插值
属性的名称可以包含插值,这使得可以根据需要动态生成属性。您甚至可以插入整个属性名称!
@mixin prefix($property, $value, $prefixes) {
@each $prefix in $prefixes {
-#{$prefix}-#{$property}: $value;
}
#{$property}: $value;
}
.gray {
@include prefix(filter, grayscale(50%), moz webkit);
}
嵌套
许多 CSS 属性以相同的前缀开头,作为一种命名空间。例如 font-family
,font-size
和 font-weight
所有的开始 font-
。通过允许嵌套属性声明,Sass 使这更容易,更少冗余。外部属性名称被添加到内部,由连字符分隔。
.enlarge {
font-size: 14px;
transition: {
property: font-size;
duration: 4s;
delay: 2s;
}
&:hover { font-size: 36px; }
}
其中一些 CSS 属性具有使用命名空间作为属性名称的简写版本。对于这些,您可以编写速记值和更明确的嵌套版本。
.info-page {
margin: auto {
bottom: 10px;
top: 2px;
}
}
隐藏的声明
有时你只想要一些属性声明出现在某些时候。如果声明的值是 null
或者是一个空的不带引号的字符串,Sass 根本不会将该声明编译为 CSS。
$rounded-corners: false;
.button {
border: 1px solid black;
border-radius: if($rounded-corners, 5px, null);
}
自定义属性
CSS 自定义属性(也称为 CSS 变量)具有不同寻常的声明语法:它们在声明值中几乎允许任何文本。更重要的是,JavaScript 可以访问这些值,因此任何值都可能与用户相关。这包括通常被解析为 SassScript 的值。
因此,Sass 以不同于其他属性声明的方式解析自定义属性声明。所有令牌,包括那些看起来像 SassScript 的令牌,都按原样传递给 CSS。唯一的例外是插值,这是将动态值注入自定义属性的唯一方法。
$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;
}
⚠️注意
不幸的是,插值会从字符串中删除引号,这使得当它们来自 Sass 变量时,很难将引用的字符串用作自定义属性的值。作为解决方法,您可以使用该 inspect()
函数来保留引号。
$font-family-sans-serif: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto;
$font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas;
:root {
--font-family-sans-serif: #{inspect($font-family-sans-serif)};
--font-family-monospace: #{inspect($font-family-monospace)};
}
父选择器
当在内部选择器中使用父选择器时,它将替换为相应的外部选择器。
.alert {
&:hover {
font-weight: bold;
}
[dir=rtl] & {
margin-left: 0;
margin-right: 10px;
}
:not(&) {
opacity: 0.8;
}
}
添加后缀
您还可以使用父选择器向外部选择器添加额外的后缀。当使用像 BEM 这样使用高度结构化类名的方法时,这尤其有用。只要外部选择器以字母数字名称(如类,ID和元素选择器)结尾,就可以使用父选择器追加其他文本。
.accordion {
max-width: 600px;
margin: 4rem auto;
width: 90%;
font-family: "Raleway", sans-serif;
background: #f4f4f4;
&__copy {
display: none;
padding: 1rem 1.5rem 2rem 1.5rem;
color: gray;
line-height: 1.6;
font-size: 14px;
font-weight: 500;
&--open {
display: block;
}
}
}
在 SassScript 中
如果 &
表达式在任何样式规则之外使用,则返回 null
。由于 null
是假,这意味着您可以轻松地使用它来确定是否在样式规则中调用 mixin。
@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);
}
高级嵌套
您可以将其 &
用作普通的 SassScript 表达式,这意味着您可以将其传递给函数或将其包含在插值中 - 即使在其他选择器中也是如此!将它与选择器功能和 @at-root
规则结合使用,可以以非常强大的方式嵌套选择器。
例如,假设您要编写与外部选择器和元素选择器匹配的选择器。你可以写一个像这样的 mixin,它使用该 selector-unify()
函数 &
与用户的选择器结合。
@mixin unify-parent($child) {
@at-root #{selector-unify(&, $child)} {
@content;
}
}
.wrapper .field {
@include unify-parent("input") {
/* ... */
}
@include unify-parent("select") {
/* ... */
}
}
⚠️注意
当 Sass 嵌套选择器时,它不知道使用什么插值来生成它们。这意味着即使您用作 &SassScript 表达式,它也会自动将外部选择器添加到内部选择器。这就是为什么你需要明确地使用 @at-root
规则来告诉 Sass 不要包含外部选择器。
占位符选择器
占位符选择器不会被编译为 CSS
.alert:hover, %strong-alert {
font-weight: bold;
}
%strong-alert:hover {
color: red;
}
它一般和继承 @extend
一起使用
%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;
}
参考
【1】Sass 官网文档