变量
$base-color: #c6538c;
$border-dark: rgba($base-color, 0.88);
.alert {
border: 1px solid $border-dark;
}
⚠️注意
CSS 有自己的变量,它们与 Sass 变量完全不同。差异:
- Sass 变量都被 Sass 编译掉了。CSS 变量包含在 CSS 输出中。
- CSS 变量对于不同的元素可以具有不同的值,但 Sass 变量一次只有一个值。
- Sass 变量是必不可少的,这意味着如果您使用变量然后更改其值,则较早的使用将保持不变。CSS 变量是声明性的,这意味着如果更改该值,它将影响早期使用和以后的使用。
$variable: value 1;
.rule-1 {
value: $variable;
}
$variable: value 2;
.rule-2 {
value: $variable;
}
💡有趣的事实
与所有 Sass 标识符一样,Sass 变量将连字符和下划线视为相同。这意味着,$font-size
和 $font_size
既指代相同的变量。这是 Sass 早期的历史遗留,当时它只允许标识符名称中的下划线。一旦 Sass 添加了对连字符的支持以匹配 CSS 的语法,这两者就相当于使迁移更容易。
默认值
通常,当您为变量赋值时,如果该变量已有值,则会覆盖其旧值。
// _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
$black: #222;
$border-radius: 0.1rem;
@import 'library';
作用域
在样式表顶层声明的变量是全局变量。这意味着它们可以在声明之后的任何地方访问,甚至可以在另一个样式表中访问。但对于所有变量而言并非如此,在块中声明的那些(SCSS 中的花括号或 Sass 中的缩进代码)通常是本地的,并且只能在声明它们的块中访问。
$global-variable: global value;
.content {
$local-variable: local value;
global: $global-variable;
local: $local-variable;
}
.sidebar {
global: $global-variable;
}
如果需要在局部作用域内设置全局变量的值,则可以使用 !global
。标记为的变量声明 !global
将改变全局变量。该 !global
标志只能用于设置已在定义的全局变量,不能用于声明新的全局变量。
$variable: first global value;
.content {
$variable: second global value !global;
value: $variable;
}
.sidebar {
value: $variable;
}
控制语句的作用域
在 @if
语句中不能声明变量,必须在使用之前定义。
高级变量函数
variable-exists()
当前局部作用域是否有该变量,global-variable-exists()
当前作用域是否有该全局变量。
从变量对象中取出一个键的值使用。
$theme-colors: (
"success": #28a745,
"info": #17a2b8,
"warning": #ffc107,
);
.alert {
background-color: map-get($theme-colors, "warning");
}
插值
插值几乎可以在 Sass 样式表中的任何位置使用,以将 SassScript 表达式的结果嵌入到 CSS 中。
使用插值使用变量,color: #{$accent}
而不是写作 color: $accent
。
不要使用数字插值,因为插值返回不带引号的字符串,不能用于任何进一步的数学运算,它避免了 Sass 的内置安全措施,以确保正确使用单位。使用 $width * 1px
而不是 #{$width}px
。
功能
@import
扩展了 CSS 的 @import
规则,能够导入 Sass 和 CSS 样式表,提供对 mixin,函数和变量的访问,并将多个样式表的 CSS 组合在一起。与纯 CSS 导入不同,后者需要浏览器在呈现页面时发出多个 HTTP 请求,因此 Sass 导入在编译期间完全处理。
查找文件
不必明确写出要导入的文件的扩展名; @import "variables"
会自动加载 variables.scss
,variables.sass
或 variables.css
。
⚠️注意
为确保样式表适用于每个操作系统,Sass 按 URL 而不是文件路径导入文件。这意味着即使在 Windows 上,也需要使用正斜杠而不是反斜杠。
加载路径
所有 Sass 实现都允许用户提供加载路径:Sass 在解析导入时将查看的文件系统上的路径。例如,如果您node_modules/susy/sass
作为加载路径传递,则可以使用 @import "susy"
加载 node_modules/susy/sass/susy.scss
。
但是,始终会首先相对于当前文件解析导入。仅当不存在与导入匹配的相对文件时,才会使用加载路径,确保在添加新库时不会意外地弄乱相对导入。
💡有趣的事实
与其他一些语言不同,Sass 不要求您使用 ./
相对导入。相对入口始终可用。
片段
以 _
开头的 sass 文件不会被编译,而是在导入时编译。
嵌套
可以嵌套在样式规则或简单的 CSS 规则 中,导入的 CSS 嵌套在该上下文中,使得嵌套导入可用于将一大块 CSS 定义到特定元素或媒体查询。请注意,嵌套导入中定义的顶级 mixins,函数和变量仍然是全局定义的。
// _theme.scss
pre, code {
font-family: 'Source Code Pro', Helvetica, Arial;
border-radius: 4px;
}
// style.scss
.theme-sample {
@import "theme";
}
💡有趣的事实
嵌套导入对于确定第三方样式表的范围非常有用,但如果您是要导入的样式表的作者,通常最好在 mixin 中编写样式并在嵌套上下文中包含该 mixin。mixin 可以以更灵活的方式使用,并且在查看导入的样式表时如何使用它更清晰。
⚠️注意
嵌套导入中的 CSS 被评估为 mixin 这意味着任何父选择器都将引用样式表嵌套的选择器。
// _theme.scss
ul li {
$padding: 16px;
padding-left: $padding;
[dir=rtl] & {
padding: {
left: 0;
right: $padding;
}
}
}
// style.scss
.theme-sample {
@import "theme";
}
导入 CSS
除了导入 .sass
和 .scss
文件,Sass 还可以导入普通的旧 .css
文件。唯一的规则是导入不能明确包含 .css
扩展名,因为它用于表示纯CSS @import
。
// code.css
code {
padding: .25em;
line-height: 0;
}
// style.scss
@import 'code';
Sass 导入的 CSS 文件不允许任何特殊的 Sass 功能。为了确保作者不会在 CSS 中不小心写 Sass ,所有不是有效 CSS 的 Sass 功能都会产生错误。
纯 CSS @import
纯 CSS @import 有以下情况:
- 以 .css 后缀名导入的文件。
- 以
http://
或https://
的文件。 - 以
url()
函数导入。 - 具有媒体查询的文件。
@import "theme.css";
@import "http://fonts.googleapis.com/css?family=Droid+Sans";
@import url(theme);
@import "landscape" screen and (orientation: landscape);
插值
虽然 Sass 导入不能使用插值(以确保始终可以告诉 mixins,函数和变量来自哪里),但纯 CSS 导入可以。这使得可以动态地生成导入,例如基于 mixin 参数。
@mixin google-font($family) {
@import url("http://fonts.googleapis.com/css?family=#{$family}");
}
@include google-font("Droid Sans");
@mixin 和 @include
Mixins 允许您定义可在整个样式表中重复使用的样式。它们可以很容易地避免使用非语义类 .float-left
,并在库中分发样式集合。
参数
Mixins 还可以接受参数,这样就可以在每次调用时自定义它们的行为。mixin 必须以 SassScript 表达式的形式包含相同数量的参数。这些表达式的值在 mixin 的主体中可用作相应的变量。
@mixin rtl($property, $ltr-value, $rtl-value) {
#{$property}: $ltr-value;
[dir=rtl] & {
#{$property}: $rtl-value;
}
}
.sidebar {
@include rtl(float, left, right);
}
可选参数
@mixin replace-text($image, $x: 50%, $y: 50%) {
text-indent: -99999em;
overflow: hidden;
text-align: left;
background: {
image: $image;
repeat: no-repeat;
position: $x $y;
}
}
.mail-icon {
@include replace-text(url("/images/mail.svg"), 0);
}
关键字参数
在声明 mixin 时的语法与可选参数没有什么不同,只是在使用时需要传入与形式参数相同的名称。
@mixin square($size, $radius: 0) {
width: $size;
height: $size;
@if $radius != 0 {
border-radius: $radius;
}
}
.avatar {
@include square(100px, $radius: 4px);
}
注意
因为任意参数都可以作为名称传递,所以在重命名 mixin 参数时,要将传入原参数名的行为打印警告,以通知他们使用新的参数名称。
任意数量的参数
@mixin order($height, $selectors...) {
@for $i from 0 to length($selectors) {
#{nth($selectors, $i + 1)} {
position: absolute;
height: $height;
margin-top: $i * $height;
}
}
}
@include order(150px, "input.name", "input.address", "input.zip");
传入的剩余参数将作为参数列表传给 $selectors
。
你可以这样实现 mixin 重命名
@mixin btn($args...) {
@warn "The btn() mixin is deprecated. Include button() instead.";
@include button($args...);
}
内容块
@mixin hover {
&:not([disabled]):hover {
@content;
}
}
.button {
border: 1px solid black;
@include hover {
border-width: 2px;
}
}
⚠️注意
在内容块中使用变量必须提前定义。
@function
抽象公式和行为。
@function pow($base, $exponent) {
$result: 1;
@for $_ from 1 through $exponent {
$result: $result * $base;
}
@return $result;
}
.sidebar {
float: left;
margin-left: pow(4, 3) * 1px;
}
@return
它只能在 @function
体内使用,每个 @function
必须以 @return
结束。
@extend
.error:hover {
background-color: #fee;
}
.error--serious {
@extend .error;
border-width: 3px;
}
规则
@extend
可以拓展选择器的样式规则
- 永远不会生成 #main#footer 这样的选择器。
- 确保复杂选择器无论怎么嵌套都能工作。
- 尽可能除去冗余选择器,同时确保选择器的准确性。
- 合并相同规则的选择器。
- 智能地处理组合器,通用选择器和包含选择器的伪类。
.content nav.sidebar {
@extend .info;
}
// 不会拓展,因为 p 和 nav 不能同时存在
p.info {
background-color: #dee9fc;
}
// 无法确定 .guide 和 .content 的包含关系,所以 SASS 将两个都生成了
.guide .info {
border: 1px solid rgba(#000, 0.8);
border-radius: 2px;
}
// main.content 存在 main.content nav.sidebar 必然存在
main.content .info {
font-size: 0.8em;
}
强制和可选扩展
@extend
必须匹配到选择器,否则会产生错误。如果想让拓展是可选的,在末尾加上 !optional
。
@media
不能在 @media
中使用 @extend
。
@error
在编写带有参数的 mixin 和函数时,需要确保参数具有所期望的类型和格式。如果不是,则通知用户并且您的 mixin / function 停止运行。
@mixin reflexive-position($property, $value) {
@if $property != left and $property != right {
@error "Property #{$property} must be either left or right.";
}
$left-value: if($property == right, initial, $value);
$right-value: if($property == right, $value, initial);
left: $left-value;
right: $right-value;
[dir=rtl] & {
left: $right-value;
right: $left-value;
}
}
.sidebar {
@include reflexive-position(top, 12px);
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// Error: Property top must be either left or right.
}
@warn
在编写 mixin 和函数时,阻止用户传递某些参数或某些值。它们可能正在传递现已弃用的旧参数,或者它们可能以不太理想的方式调用 API。
$known-prefixes: webkit, moz, ms, o;
@mixin prefix($property, $value, $prefixes) {
@each $prefix in $prefixes {
@if not index($known-prefixes, $prefix) {
@warn "Unknown prefix #{$prefix}.";
}
-#{$prefix}-#{$property}: $value;
}
#{$property}: $value;
}
.tilt {
// Oops, we typo'd "webkit" as "wekbit"!
@include prefix(transform, rotate(15deg), wekbit ms);
}
@debug
开发样式表时查看变量或表达式的值, @debug
打印该表达式的值,以及文件名和行号。
@mixin inset-divider-offset($offset, $padding) {
$divider-offset: (2 * $padding) + $offset;
@debug "divider offset: #{$divider-offset}";
margin-left: $divider-offset;
width: calc(100% - #{$divider-offset});
}
@at-root
和 selector-unify()
函数一起使用表示使用根选择器作为 &
的值。
@mixin unify-parent($child) {
@at-root #{selector-unify(&, $child)} {
@content;
}
}
.wrapper .field {
@include unify-parent("input") {
/* ... */
}
@include unify-parent("select") {
/* ... */
}
}
使用 with 或者 without 告诉 @at-root
排除哪些规则。
@media print {
.page {
width: 8in;
@at-root (without: media) {
color: #111;
}
@at-root (with: rule) {
font-size: 1.2em;
}
}
}
除了 at-rules 的名称之外,还有两个可以在查询中使用的特殊值:
rule
指的是风格规则。例如,@at-root (with: rule)
排除所有 at-rules 但保留样式规则。all
指的是所有的规则和风格规则都应该被排除在外。
流程控制
@if 和 @else
false
和 null
在 Sass 中是假,空字符串、空列表和数字 0 在 Sass 中都是真。
@each
解构
$icons:
"eye" "\f112" 12px,
"start" "\f12e" 16px,
"stop" "\f12f" 10px;
@each $name, $glyph, $size in $icons {
.icon-#{$name}:before {
display: inline-block;
font-family: "Icon Font";
content: $glyph;
font-size: $size;
}
}
@for
使用 to 排除最后的数字,使用 through 包含最终数字。
$base-color: #036;
@for $i from 1 through 3 {
ul:nth-child(3n + #{$i}) {
background-color: lighten($base-color, $i * 5%);
}
}
参考
【1】Sass 官网文档