文章目录
一、变量$
需要复用的CSS值,比如字体、颜色等,可以使用 $
将其变成一个变量。
$base-color: #c6538c;
$border-dark: rgba($base-color, 0.88);
.alert {
border: 1px solid $border-dark;
}
在官网文档的”重大变化“中提到:为了提供与纯CSS的最大兼容性,较新版本的 Sass 要求将自定义属性值中的 SassScript 表达式写入插值中。插值也适用于较旧的 Sass 版本,因此建议用于所有样式表。
$accent-color: #fbbc04;
:root {
// Wrong,在最新的版本中将不可用。
--accent-color-wrong: $accent-color;
// Good,在所有的Sass版本中可用。
--accent-color-right: #{
$accent-color};
}
因为插值会从带引号的字符串中删除引号,所以可能需要将它们包装在 meta.inspect() 函数中以保留它们的引号。
@use "sass:meta";
$font-family-monospace: Menlo, Consolas, "Courier New", monospace;
:root {
--font-family-monospace: #{
meta.inspect($font-family-monospace)};
}
二、嵌套
// scss 可以使用变量、可以嵌套。文件扩展名.scss
$primary-color: #333;
nav {
color: $primary-color
ul {
margin: 0;
padding: 0;
list-style: none;
}
li {
display: inline-block; }
a {
display: block;
padding: 6px 12px;
text-decoration: none;
}
}
// css
nav ul {
margin: 0;
padding: 0;
list-style: none;
}
nav li {
display: inline-block;
}
nav a {
display: block;
padding: 6px 12px;
text-decoration: none;
}
三、父选择器 &
父选择器 & 是 Sass 发明的一种特殊选择器,在嵌套选择器中用于引用外部选择器。它可以以更复杂的方式来复用外部选择器。
.alert {
// 可用于向外部选择器添加伪类
&:hover {
font-weight: bold;
}
// 可用于在特定上下文中设置外部选择器的样式
[dir=rtl] & {
margin-left: 0;
margin-right: 10px;
}
// 可用于作为 伪类选择器的参数。
:not(&) {
opacity: 0.8;
}
}
四、插值 #{表达式}
用来输出或计算一个表达式的内容。字符串与变量的拼接使用 #{表达式}
。
常用于在写mixins时根据传入的参数创建选择器。
@each $size, $value in variables.$avatar-sizes {
// 根据传入的参数生成选择器
.thy-avatar-#{
$size} {
@include mixin.avatarSize($size, $value);
}
}
五、函数 @function 和 @return
@function
和 @return
结合,用于定义可在 SassScript 表达式中使用的自定义函数,函数最后通过@return返回计算结果。
与所有Sass标识符一样,函数名称将连字符和下划线视为相同。这意味着scale-color和scale_color都指的是相同的功能。
@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;
}
可选参数:可以通过定义一个默认值来使参数成为可选参数,如果该参数未传递,则将使用该默认值。
@function invert($color, $amount: 100%) {
$inverse: change-color($color, $hue: hue($color) + 180);
@return mix($inverse, $color, $amount);
}
$primary-color: #036;
.header {
background-color: invert($primary-color, 80%);
}
任意参数:如果@function声明中的最后一个参数以 ...
结尾,则该函数的所有额外参数都作为列表传递给该参数。此参数称为参数列表。
@function sum($numbers...) {
$sum: 0;
@each $number in $numbers {
$sum: $sum + $number;
}
@return $sum;
}
.micro {
width: sum(50px, 30px, 100px);
}
六、混合 @mixin 和 @include
@mixin
和@include
结合使用,使我们可以很容易地复用样式块。有助于保持样式表的简洁性。
同时可以给 @mixin 传参,使得样式的书写更加灵活。
@mixin theme($theme: DarkGray) {
background: $theme;
box-shadow: 0 0 1px rgba($theme, .25);
color: #fff;
}
.info {
@include theme;
}
.alert {
@include theme($theme: DarkRed);
}
.success {
@include theme($theme: DarkGreen);
}
七、内容块 @content
- mixin 除了接收参数之外,还可以接收整个样式块,该样式称为内容块。
- mixin 可以通过在主体中包含
@content
规则来声明它采用内容块。 内容块使用花括号传入,并且它被注入以代替 @content 规则。 - 内容块只能看到包含 mixin 的范围内的局部变量。
@mixin hover-active {
&:hover,
&:active {
@content;
}
}
button {
@include hover-active {
color: $hover-color;
}
}
// 最后button的样式效果会是:
button {
&:hover,
&:active {
color: $hover-color;
}
}
内容块可接收参数,如:
@mixin media($types...) {
@each $type in $types {
@media #{
$type} {
// 语法: @content(<arguments...>)
@content($type);
}
}
}
// 语法:@include <mixinName> using (<arguments...>)
@include media(screen, print) using ($type) {
h1 {
font-size: 40px;
@if $type == print {
font-family: Calluna;
}
}
}
八、模块化 @forward 和 @use
@forward
@forward
加载Sass样式表。使得它的mixins、functions和variables (被其它模块@use加载时)可用。
The @forward rule loads a Sass stylesheet and makes its mixins, functions, and variables available when your stylesheet is loaded with the @use rule. It makes it possible to organize Sass libraries across many files, while allowing their users to load a single entrypoint file.
1. 基本使用
// src/_list.scss (样式片段文件A,里面含有mixin)
@mixin list-reset {
margin: 0;
padding: 0;
list-style: none;
}
// bootstrap.scss (在样式的入口文件B中 forward 样式片段A)
@forward "src/list";
// styles.scss (在需要使用到样式片段文件A的样式的地方,通过@use将样式模块加载进来,然后通过@include使用前面定义好的样式片段。)
@use "bootstrap";
li {
@include bootstrap.list-reset;
}
实际应用:在做segment组件的过程中,样式模块的处理如下:
// 第一步:先定义好mixin.scss文件,里面含有一些mixins。 src/segment/styles/mixin.scss
// 第二步: 在src/styes/mixins/index.scss中 @forward一下 (src/styes/mixins/index.scss最终会被 @forward 到 样式模块入口文件 src/styles/basic.scss)
@forward '../../segment/styles/mixin.scss';
// 第三步: 在需要使用到以上mixin的地方,通过@use将需要使用到的某个模块加载进来,然后通过模块变量访问里面的mixin。
2. 添加前缀
语法: @forward "<url>" as <prefix>-*
。它会把指定的前缀添加到模块转发的每个mixin、函数和变量名的开头。
// src/_list.scss
@mixin reset {
margin: 0;
padding: 0;
list-style: none;
}
// bootstrap.scss
@forward "src/list" as list-*;
// styles.scss
@use "bootstrap";
li {
@include bootstrap.list-reset;
}
3. 控制可见性
有时,我们不想forward模块中的每个成员,而是想将某些成员(mixin、function、variable)进行保密。语法:
@forward "<url>" show <members...>
:forward模块中的指定成员。
@forward "<url>" hide <members...>
:forward模块中除指定成员之外的其它成员。
示例:
// src/_list.scss
$horizontal-list-gap: 2em;
@mixin list-reset {
margin: 0;
padding: 0;
list-style: none;
}
@mixin list-horizontal {
@include list-rest;
li {
display: inline-block;
margin: {
left: -2px;
right: $horizontal-list-gap;
}
}
}
// bootstrap.scss
@forward "src/list" hide list-reset, $horizontal-list-gap;
4. 配置模块 with
@forward 规则还可以加载带有配置的模块。 这与 @use 的工作方式基本相同,但有一点:@forward 规则可以在其配置中使用 !default
。 它允许模块更改上游样式表的默认值,同时仍允许下游样式表覆盖它们。
// _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;
}
// _opinionated.scss
@forward 'library' with ( // @forward样式模块时,可以更改上游样式表的默认值
$black: #222 !default, ⭐️⭐️
$border-radius: 0.1rem !default ⭐️⭐️
);
// style.scss
@use 'opinionated' with (// @use加载样式模块时,可以修改并覆盖上游样式表的变量
$black: #333 ⭐️⭐️⭐️
);
5. 综合使用示例
@use
- @use从其它 Sass 样式表中加载 mixins、函数和变量,并将来自多个样式表的CSS组合在一起。
- 我们可以创建只包含一小片段样式的样式文件(file with partial Sass,官方叫 partial)。它可以被包含在其它样式文件中。
- partial 是一个以下划线开头的 Sass 文件,下划线告知Sass这只是个含部分样式的文件。
- Sass 支持将样式拆分成一个个小模块写在不同的文件里,我们可以使用
@use
将另一个 Sass 文件作为模块加载进来。 - 这意味着我们可以在 Sass 文件中使用基于文件名的命名空间来引用它的 变量、mixin 和 functions。
九、扩展 @extend 和 %占位符选择器
- 在写样式时,有时候会出现一个类应该具有另一个类的所有样式以及它自己的特定样式的情况,这时我们可以使用@extend从一个选择器共享一组CSS属性到另一个选择器。我们还可以在此基础上进行样式扩展。
- 想写仅用于扩展的样式我们可以写成一个占位符类,以
%
开头。 - @extend允许选择器相互继承样式。即可以继承占位符类,也可以继承普通的样式类。
示例:继承占位符类:
// 这个样式会被输出,因为%message-shared在后面被 @extend扩展了
%message-shared {
border: 1px solid #ccc;
padding: 10px;
color: #333;
}
// 这个样式不会被输出,因为它没有被扩展
%equal-heights {
display: flex;
flex-wrap: wrap;
}
.message {
@extend %message-shared;
}
.success {
@extend %message-shared;
border-color: green;
}
.error {
@extend %message-shared;
border-color: red;
}
.warning {
@extend %message-shared;
border-color: yellow;
}
示例:继承普通的样式类:
注意:
- 我们应该避免使用@extend,因为它会破坏代码结构合理性,把不相关的选择器串联到一起。而不仅仅是你想要的那一个。
- LibSass目前允许复合选择器.message.info被扩展(会在未来的版本中废弃)。Dart Sass不支持扩展复合选择器。我们最好只扩展单个简单的选择器。
示例:想要同时继承.message和.info。
// 错误的示范
.message {
border: 1px solid black;
}
.info {
font-size: 1.5rem;
}
.heads-up {
@extend .message.info;
}
// 正确的示范
.message {
border: 1px solid black;
}
.info {
font-size: 1.5rem;
}
.heads-up {
@extend .message, .info;
}
十、@extend与@include的区别
相同点:均是用来调用可复用样式的。
不同点:
- @include与@mixin搭配使用,@include后面跟的是mixin的名称。@include用于使用可复用样式 mixin 。
- @extend与%占位符选择器搭配使用,@extend后面跟的是选择器名称。@extend用于使用可复用样式 选择器 。
- @extend和@mixin如何选择使用哪个? 当我们需要使用到参数来配置样式时,选择 mixins。
// 示例:@mixin @include
@mixin foo {
color: red;
font-weight: bold;
line-height: 2;
}
.#{
unique-id()}-#{
$i} {
@include foo;
content: "ibf#{
&}jaslbw";
}
// 示例:%占位符选择器 @extend
%foo {
color: red;
font-weight: bold;
line-height: 2;
}
.#{
unique-id()}-#{
$i} {
@extend %foo;
content: "ibf#{
&}jaslbw";
}
十一、@at-root
@at-root
将其中的样式放在CSS 文档的根目录中,而不是使用正常的嵌套。它最常用于使用 SassScript 父选择器和选择器函数进行高级嵌套。
在以下示例中,@at-root 是必要的,因为 Sass 在执行选择器嵌套时不知道使用什么插值来生成选择器。 这意味着即使使用 & 作为 SassScript 表达式,它也会自动将外部选择器添加到内部选择器。 @at-root 明确告诉 Sass 不要包含外部选择器。
@use "sass:selector";
@mixin unify-parent($child) {
@at-root #{
selector.unify(&, $child)} {
@content;
}
}
.wrapper .field {
@include unify-parent("input") {
/* ... */
}
@include unify-parent("select") {
/* ... */
}
}
注意: @at-root 只会摆脱样式规则(style rules)。 像 @media 或 @supports 之类的@规则都将被保留。如果我们@at-root的时候不想保留外部嵌套的@media等规则,我们可以使用诸如媒体查询功能(media query features)之类的语法来精确控制它包含的内容。我们可以通过 with
或 without
来指定哪些规则需要排除。
@at-root (with: <rules...>) { ... }
: 告诉 Sass 只执行列出的规则。
@at-root (without: <rules...>) { ... }
: 告诉 Sass 应该排除哪些规则。
除了 @规则
之外,还有两个特殊的值可用于 @at-root 查询,分别是 rule
和 all
。
rule
: 是指样式规则(styles rule),例如 @at-root(with: rule) 只保留样式规则,其它所有@规则都排除掉。
all
: 是指的是所有 @规则 和 style规则 都应该被排除。
@media print {
.page {
width: 8in;
// 将该at-root包裹的样式在document的根部发出,摆脱外部嵌套的@media规则。
@at-root (without: media) {
color: #111;
}
// 将该at-root包裹的样式在document的根部发出,同时只保留外层的样式规则,其它所有@规则都排除掉。
@at-root (with: rule) {
font-size: 1.2em;
}
}
}
十二、@warn、@error、@debug
@error
导致编译失败并显示错误消息。在写带有参数的mixin和函数时,通常希望这些参数的类型和格式是我们想要的。如果不是,则需要通知用户,并且停止mixins/functions的运行。
@warn
在不完全停止编译的情况下打印警告。在写mixins和functions时,阻止用户传递某些参数或某些值。
@debug
出于调试目的打印消息。在开发样式时,可用于查看变量和表达式的值。
@mixin reflexive-position($property, $value) {
@if $property != left and $property != right {
@error "Property #{
$property} must be either left or right.";
}
...
}
// @warn
@mixin prefix($property, $value, $prefixes) {
@each $prefix in $prefixes {
@if not index($known-prefixes, $prefix) {
@warn "Unknown prefix #{
$prefix}.";
}
...
}
}
// 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});
}
十三、流程控制规则
操作符
@if、@else if、@else
条件表达式可以使用布尔运算符:and
, or
, not
。
// 使用 #{
} 来装一个变量来与字符串进行拼接,相当于ts里的 ${
}
@mixin label-size($size, $padding, $minusValue: 0px) {
@if $size == xlg {
&--#{
$size} {
padding: #{
$padding - $minusValue} 10px;
font-size: variables.$font-size-lg;
}
} @else if $size == lg {
&--#{
$size} {
padding: #{
$padding - $minusValue} 10px;
font-size: variables.$font-size-base;
}
} @else if $size == default {
padding: #{
$padding - $minusValue} 10px;
} @else {
&--#{
$size} {
padding: #{
$padding - $minusValue} 10px;
}
}
}
// 条件表达式可以使用布尔运算符:and, or, not
@mixin segmented-size-variant($size, $height) {
&-#{
$size} &-item-label {
@if ($size == xs or $size == sm or $size == md) {
font-size: variables.$font-size-sm;
} @else {
font-size: variables.$font-size-base;
}
}
}
@each in
用于遍历一个 list 列表 或 map 键值对。
// 单层循环,遍历list
$sum: 0;
@each $number in $numbers {
$sum: $sum + $number;
}
// 单层循环,遍历map
@each $size, $value in $removeLinkSizes {
.remove-link-#{
$size} {
@include close.set-close-link-size($value);
}
}
// 双重循环
@each $prop, $abbrev in (width: w, height: h) {
@each $size, $length in variables.$sizes {
.#{
$abbrev}-#{
$size} {
#{
$prop}: $length !important;
}
}
}
// 解构
$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 变量 from A through/to B
从一个数字(A表达式的结果)到另一个数字(B表达式的结果)向上或向下计数来对代码块执行指定次数。 如果使用 to
,则排除最后的数字; 如果使用 through
,则最后一个数字包括在内。
// 变量 $i 从 1 到 23
@for $i from 1 to 24 {
.thy-col-#{
$i} {
display: block;
box-sizing: border-box;
width: 0;
flex: 0 0 math.percentage(math.div($i, 24));
}
}
// 变量 $i 从 1 到 24
@for $i from 1 through 24 {
.thy-col-#{
$i} {
display: block;
box-sizing: border-box;
width: 0;
flex: 0 0 math.percentage(math.div($i, 24));
}
}
@while
重复执行某个代码块,直到满足条件为止。
@use "sass:math";
// 将 $value 除以 $ratio 直到它小于$base
@function scale-below($value, $base, $ratio: 1.618) {
@while $value > $base {
$value: math.div($value, $ratio);
}
@return $value;
}
$normal-font-size: 16px;
sup {
font-size: scale-below(20px, 16px);
}
十四、兼容CSS规则
Sass兼容Css的@规则,语法:
@<name> <value> , @<name> { ... }
或 @<name> <value> { ... }
@supports
@supports
的作用:用来查询浏览器是否支持某个CSS属性。它可以解决浏览器的兼容性问题。用@supports来判断浏览器是否支持这个css属性,如果支持,它里面包含的样式表就会起作用,否则不会起作用。
@mixin sticky-position {
position: fixed;
// 如果浏览器支持position: sticky,则设置上position: sticky样式。
@supports (position: sticky) {
position: sticky;
}
}
.banner {
@include sticky-position;
}
// 如果浏览器不支持display: grid,则div设置上float:right样式
@supports not (display: grid) {
div {
float: right;
}
}
// 支持使用 and or not 等组合判断
@supports (display: grid) and (not (display: inline-grid)) {
}
@media
@media (min-width: $layout-breakpoint-small) {
.hide-extra-small {
display: none;
}
}
@keyframes
@keyframes规则的工作原理与一般的@规则类似,不同之处在于其子规则必须是有效的关键帧规则( <number>%
、 from
或 to
),而不是普通的选择器。
@keyframes slide-in {
from {
margin-left: 100%;
width: 300%;
}
70% {
margin-left: 90%;
width: 150%;
}
to {
margin-left: 0%;
width: 100%;
}
}
十五、除法 math.div(a,b)
使用 math.div(a,b)
或 calc(a/b)
来替代除法 a/b
。
@use "sass:math";
// 废弃
@debug (12px/4px); // 3
// Good
@debug math.div(12px, 4px); // 3
// Good
@debug calc(12px / 4px); // 3
End!