Skip to content

Sass

Sass 是一种流行的CSS 预处理器,使用一种较为紧凑的、类似于缩进的语法,不使用花括号和分号来分隔样式规则。SCSS 则采用与原生 CSS 相似的语法,使用花括号和分号来分隔样式规则。sass从第三代开始,放弃了缩进式风格,并且完全向下兼容普通的css代码,这一代的sass也被称为scss。

一、嵌套

1、选择器嵌套

scss
.container {
    width: 900px;
    margin: 0 auto;
    .header {
        height: 90px;
        line-height: 90px;
        .logo {
            width:100px;
            height: 60px;
        }
    }
    .center {
        height: 600px;
        background-color: #f00;
    }
    .footer {
        font-size: 16px;
        text-align: center;
    }
}

//并列选择器
.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;
    }
  }
}

2、父选择器嵌套&

scss
.container {
    width: 900px;
    margin: 0 auto;
    a {
        color: #333;
        &:hover {
            text-decoration: underline;
            color: #f00;
        }
    }
    .top {
        border: 1px #ff0 solid;
        &-left {
            float: left;
            width: 200px;
        }
    }
}

3、属性嵌套

scss
.container {
    a {
        color: #0ff;
        font: {
            size: 14px;
            family: sans-serif;
            weight: bold;
        }
    }
}

4、占位符%

% 开头,并且不包含在 CSS 输出中。

scss
.alert:hover, %strong-alert {
  font-weight: bold;
}

%strong-alert:hover {
  color: red;
}

5、@at-root

scss
.container {
  display: flex;

  @at-root {
    background-color: gray;
    color: white;
  }

  .nested {
    font-size: 14px;
    @at-root {
      font-weight: bold;
    }
  }
}

二、注释

scss
// 这是单行注释,不会被编译

/*
* 这是多行注释,会被编译
*/

三、变量

1、定义规则

  • 变量以$开头,后面跟变量名
  • 变量名可包含字母、数字、下划线、连接符,且不能以数字开头;
  • 写法同CSS,即变量名和值之间用冒号(:)分隔;
  • 变量一定要先定义,后使用

TIP

下划线也连接符 通过下划线与连接符定义的同名变量视为同一变量,最终取决于最后一次定义。

scss
$font-size: 14px;
$font_size: 20px;

.container {
    font-size:$font-size;   //font-size:20px
}

2、变量值类型

sass支持6种主要的数据类型

  • Numbers:如12,20px
  • Strings:有引号字符串与无引号字符串,如"foo","bar",game
  • Colors:颜色英文单词、#RRGGBB、rgb(R, G, B),hsl(H, S, L)如red、#ff0edf、#0df98fff、rgb(255,0,0),rgba(255,255,0,.8),hsl(0, 100%, 50%)
  • Booleans:true、false
  • null
  • Lists:用空格或逗号分隔,如10px 20px 10px 20pxArial, sans-serif, Mircosoft YaHEI
  • Maps:相当于js中的object对象,如(key1: value, key2: value2)
  • Calculations:计算表达式,如calc(400px + 10%),min(100px, calc(1rem + 10%))
  • Functions:函数

3、变量默认值

scss
$color: #333;
//如果$color之前没定义就使用如下默认值
$color: #999 !default;
.container {
    border-color: $color;
}

4、变量作用域

局部变量

在选择器内定义的变量,只能在选择器范围内使用。

scss
.container {
    $font-size: 14px;   //只能在container容器内使用
    font-size: $font-size;
    .title {
        font-size: $font-size;
    }
}

全局变量

定义后能全局使用的变量。

  • 在选择器之外的最前处定义
scss
$font-size: 16px;

.container {
    font-size: $font-size;
}

.header {
    font-size: $font-size;
}
  • 使用!global定义
scss
.container {
    $font-size: 16px !global;
    font-size: $font-size;
}

.header {
    font-size: $font-size;
}

5、内置变量

定义在内置模块的变量且无法被修改。

scss
@use "sass:math" as math;

math.$pi: 0;    // This assignment will fail.

四、插值

#

scss
$class-name: danger;
$attr: color;
$author: '中年大叔学前端'

/*
 * 这是注释部分
 * @author: #{$author}
 */

a.#{$class-name} {
    border-#{$attr}: #ff0;
}

五、运算

1、关系运算符

==!=<><=>=

2、逻辑运算符

andornot

3、算术运算符

+-*/%

TIP

以下三种情况/将被视为除法运算符:

  • 如果值或值的一部分是变量或函数的返回值时
  • 如果值被圆括号包裹时
  • 如果值是算数表达式的一部分时
scss
$width: 900px;

div {
    width: $width /2 ;
    z-index: round(10) / 2;
    height: (500px / 2);
    margin-left: 5px + 8px / 2px;
}

注意

  • %px不能一起运算
  • 纯数字与%px运算时会自动转化成相应的%px

4、字符串运算符

+

注意

  • 如果有引号字符串(位于+左侧)连接无引号字符串,则运算结果是有引号
  • 如果无引号字符串(位于+左侧)连接有引号字符串,则运算结果没有引号

六、函数

@function和@return

语法

scss
@function <function-name>(<parameters>) {
  // Function body
  @return <value>;
}

示例

scss
@function calculate-width($width, $padding) {
  @return $width + 2 * $padding;
}

.container {
  width: calculate-width(200px, 10px);
}

七、混入

@mixin和@include

scss
@mixin show {
    display : block;
}
@mixin hide($color) {
    display : none;
    color : $color;
}
@mixin block-margin($top, $right, $bottom: 0, $left: 0) {
    margin-top: $top;
    margin-right: $right;
    margin-bottom: $bottom;
    margin-bottom: $left;
}
@mixin linear-gradient($direction, $gradients...) {
    background-color: nth($gradients, 1);
    background-image: linear-gradient($direction, $gradients);
}

.box{
    width : 100px;
    @include show;
    @include hide(red);
    @include block-margin(10px, 20px, 10px, 30px);
    @include block-margin($left: 10px, $right: 20px, $top: 10px, $bottom: 20px);
    @include block-margin(10px,20px);
    @include linear-gradient(to right, #ff0, #f00, #f0f);
}

八、继承

@extend

scss
.color { color:red}
%line{  //占位符
    display : inline;
}

.box{
    @extend %line;
    @extend .color;
}

TIP

继承与混入的区别:

  • 继承会将公共部分单独抽离出来,减少代码冗余,而混入不会
  • 继承会编译后出现无用的类名(可以结合占位符%使用解决编译后出现无用类名问题),而混入不会

九、流程控制

1、@if...@else

语法

scss
@if <condition> {
  // Code block to be executed if the condition is true
} @else if <condition> {
  // Code block to be executed if the condition is true
} @else {
  // Code block to be executed if no condition is true
}

示例

scss
$color: red;

@if $color == red {
  .box {
    background-color: $color;
  }
} @else if $color == blue {
  .box {
    background-color: $color;
    color: white;
  }
} @else {
  .box {
    background-color: gray;
  }
}

2、@each

遍历列表

语法

scss
@each $item in <list> {
  // Code block to be executed
}

示例

scss
$colors: red, green, blue;

@each $color in $colors {
  .box-#{$color} {
    background-color: $color;
  }
}

遍历映射

语法

scss
@each $key, $value in <map> {
  // Code block to be executed
}

示例

scss
$font-sizes: (
  small: 12px,
  medium: 16px,
  large: 20px
);

@each $name, $size in $font-sizes {
  .text-#{$name} {
    font-size: $size;
  }
}

解构赋值遍历键值对

语法

scss
@each $var1, $var2 in <list> {
  // Code block to be executed
}

示例

scss
$list: (1, red), (2, green), (3, blue);

@each $num, $color in $list {
  .box-#{$num} {
    background-color: $color;
  }
}

3、@for

语法

scss
// 循环将从 <start> 开始,逐步增加到等于或大于 <end> 的值
@for $var from <start> through <end> {
  // Code block to be executed
}

// 循环将从 <start> 开始,逐步增加到小于 <end> 的值
@for $var from <start> to <end> {
  // Code block to be executed
}

示例

scss
$font-sizes: 12px 14px 16px 18px;

@for $i from 1 through length($font-sizes) {
  $font-size: nth($font-sizes, $i);
  h#{$i} {
    font-size: $font-size;
  }
}

4、@while

语法

scss
@while <condition> {
  // Code block to be executed
}

示例

scss
$first: 0;
$second: 1;
$count: 10;

@while $count > 0 {
  $next: $first + $second;
  $first: $second;
  $second: $next;
  $count: $count - 1;
}

十、导入

@use

@use 规则从其他 Sass 样式表中加载混合、函数和变量,并将来自多个样式表的 CSS 组合在一起。由 @use 加载的样式表称为“模块”。

语法

scss
@use "<url>"

示例:加载成员

<namespace>.<variable>, <namespace>.<function>(), @include <namespace>.<mixin>()

scss
// src/_corners.scss
$radius: 3px;

@mixin rounded {
  border-radius: $radius;
}

// style.scss
@use "src/corners";

.button {
  @include corners.rounded;
  padding: 5px + corners.$radius;
}

TIP

私有成员 以 - 或 _ 开头的名称

scss
// src/_corners.scss
$-radius: 3px;

@mixin rounded {
  border-radius: $-radius;
}

// style.scss
@use "src/corners";

.button {
  @include corners.rounded;

  padding: 5px + corners.$-radius;    // This is an error! $-radius isn't visible outside of `_corners.scss`.
}

示例:自定义模块命名

@use "<url>" as <namespace>

scss
// src/_corners.scss
$radius: 3px;

@mixin rounded {
  border-radius: $radius;
}

// style.scss
@use "src/corners" as c;

.button {
  @include c.rounded;
  padding: 5px + c.$radius;
}

示例:配置模块

@use <url> with (<variable>: <value>, <variable>: <value>)

scss
// _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
);

WARNING

  • 不必显式写出要加载的文件的扩展名; @use "variables" 将自动加载 variables.scss 、 variables.sass 或 variables.css
  • 模块将始终首先相对于当前文件加载,不要求使用 ./ 进行相对导入,直接@use "variables"即可自动加载路径,仅当不存在与模块 URL 匹配的相对文件时,才会使用加载路径
  • 仅作为模块加载而不是自行编译的 Sass 文件以 _开头(如 _public.scss ),这些被称为部分文件,它们告诉 Sass 工具不要尝试自行编译这些文件,导入部分时可以省略 _
  • 如果在文件夹中写入 _index.scss_index.sass ,则在加载文件夹本身的 URL 时将自动加载索引文件
  • 除了加载 .sass 和 .scss 文件外,Sass 还可以加载普通的旧 .css 文件

与 @import 的区别

  • @use 仅使变量、函数和混合在当前文件的范围内可用。它永远不会将它们添加到全局范围
  • @use 只加载每个文件一次。这可确保您最终不会意外地多次复制依赖项的 CSS
  • @use 必须出现在文件的开头,并且不能嵌套在样式规则中
  • 每个 @use 规则只能有一个 URL
  • @use 要求在其 URL 两边加上引号,即使使用缩进语法也是如此

十一、导出

@forward

语法

scss
@forward "<url>"

示例

scss
// src/_list.scss
@mixin list-reset {
  margin: 0;
  padding: 0;
  list-style: none;
}

// bootstrap.scss
@forward "src/list";

// styles.scss
@use "bootstrap";

li {
  @include bootstrap.list-reset;
}

示例:添加前缀@forward "<url>" as <prefix>-*

scss
// 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;
}

示例:控制可见性@forward "<url>" hide <members...>@forward "<url>" show <members...>

scss
// src/_list.scss
$horizontal-list-gap: 2em;

@mixin list-reset {
  margin: 0;
  padding: 0;
  list-style: none;
}

@mixin list-horizontal {
  @include list-reset;

  li {
    display: inline-block;
    margin: {
      left: -2px;
      right: $horizontal-list-gap;
    }
  }
}

// bootstrap.scss
@forward "src/list" hide list-reset, $horizontal-list-gap;

示例:配置模块@forward <url> with (<variable>: <value>, <variable>: <value>)

scss
// _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 (
  $black: #222 !default,
  $border-radius: 0.1rem !default
);

// style.scss
@use 'opinionated' with ($black: #333);

TIP

@forward 规则的配置可以在其配置中使用 !default 标志。这允许模块更改上游样式表的默认值,同时仍允许下游样式表覆盖它们。

十二、内置模块

1、color函数

  • rgba($color, $alpha):设置颜色的透明度,返回一个新的带有透明度的颜色值
  • lighten($color, $amount):使颜色变亮,返回一个更亮的颜色值
  • darken($color, $amount):使颜色变暗,返回一个更暗的颜色值
  • saturate($color, $amount):使颜色饱和度增加,返回一个更饱和的颜色值
  • desaturate($color, $amount):使颜色饱和度减少,返回一个更不饱和的颜色值
  • mix($color1, $color2, $weight):混合两个颜色,返回一个介于两者之间的颜色值

2、list函数

  • list.append($list, $val, $separator: auto):将值 $val 添加到列表 $list 的末尾,使用指定的分隔符 $separator。返回更新后的列表。
  • list.index($list, $value):返回值 $value 在列表 $list 中的第一个匹配项的索引。
  • list.join($list1, $list2, $separator: auto, $bracketed: auto):将列表 $list2 连接到列表 $list1 的末尾,使用指定的分隔符 $separator。如果 $bracketed 参数为 true,则将结果列表包裹在方括号中。返回连接后的列表。
  • list.length($list):返回列表 $list 的长度(元素数量)。
  • list.separator($list):返回列表 $list 中的分隔符。
  • list.nth($list, $n):返回列表 $list 中的第 $n 个元素。

3、map函数

  • map.deep-merge($map1, $map2):深度合并两个映射 $map1 和 $map2,返回合并后的映射。如果有相同的键,后者的值将覆盖前者。
  • map.deep-remove($map, $key, $keys...):从映射 $map 中深度删除指定的键 $key 及其嵌套键 $keys,返回删除后的映射。
  • map.get($map, $key, $keys...):获取映射 $map 中指定键 $key 及其嵌套键 $keys 对应的值。
  • map.set($map, $key, $value):将映射 $map 中的键 $key 设置为指定的值 $value,返回更新后的映射。
  • map.keys($map):返回映射 $map 中所有的键组成的列表。
  • map.values($map):返回映射 $map 中所有的值组成的列表。

4、math函数

  • math.ceil($number):返回不小于 $number 的最小整数。
  • math.clamp($min, $number, $max):将 $number 限制在 $min 和 $max 之间,如果 $number 小于 $min,返回 $min;如果 $number 大于 $max,返回 $max;否则返回 $number。
  • math.floor($number):返回不大于 $number 的最大整数。
  • math.max($number...):返回一组数中的最大值。
  • math.min($number...):返回一组数中的最小值。
  • math.round($number):将 $number 四舍五入为最接近的整数。
  • math.abs($number):返回 $number 的绝对值。
  • math.hypot($number...):返回给定一组数的平方和的平方根。
  • math.div($number1, $number2):将 $number1 除以 $number2,返回结果。
  • math.percentage($number):将 $number 转换为百分比形式(乘以 100 并添加百分号)。
  • math.random($limit: null):生成一个随机数。如果提供了 $limit 参数,则随机数将介于 0 和 $limit 之间。

5、meta函数

  • meta.calc-args($calc):返回给定 calc() 函数的参数列表
  • meta.calc-name($calc):返回给定 calc() 函数的名称
  • meta.call($function, $args...):调用指定名称的函数,并传递给定的参数
  • meta.content-exists():检查当前选择器是否具有 ::content 伪元素
  • meta.feature-exists($feature):检查指定功能(feature)是否存在
  • meta.function-exists($name, $module: null):检查指定名称的函数是否存在
  • meta.get-function($name, $css: false, $module: null):获取指定名称的函数,返回函数的定义
  • meta.global-variable-exists($name, $module: null):检查指定名称的全局变量是否存在
  • meta.inspect($value):返回给定值的字符串表示形式
  • meta.keywords($args):返回关键字参数的名称列表
  • meta.mixin-exists($name, $module: null):检查指定名称的混合器是否存在
  • meta.module-functions($module):获取指定模块中定义的函数列表
  • meta.module-variables($module):获取指定模块中定义的变量列表
  • meta.type-of($value):返回给定值的类型
  • meta.variable-exists($name):检查指定名称的变量是否存在

6、selector函数

  • selector.is-superselector($super, $sub):检查 $super 是否是 $sub 的超级选择器(即,是否包含 $sub 的所有匹配)。返回布尔值。
  • selector.append($selectors...):将多个选择器合并为一个选择器。返回合并后的选择器。
  • selector.extend($selector, $extendee, $extender):将 $extender 扩展到 $extendee 的选择器上,并返回扩展后的选择器。
  • selector.nest($selectors...):将多个选择器嵌套在一起形成一个复合选择器。返回嵌套后的选择器。
  • selector.parse($selector):将选择器解析为简单选择器的列表。
  • selector.replace($selector, $original, $replacement):将选择器中的 $original 替换为 $replacement,返回替换后的选择器。
  • selector.unify($selector1, $selector2):将两个选择器合并为一个共同选择器。返回合并后的选择器。
  • selector.simple-selectors($selector):提取选择器中的简单选择器(如类名、ID、伪类等),返回简单选择器的列表。

7、string函数

  • string.quote($string):在字符串 $string 的两端添加引号(单引号或双引号),返回带引号的字符串。
  • string.index($string, $substring):返回字符串 $string 中子字符串 $substring 的第一个匹配项的索引。
  • string.insert($string, $insert, $index):在字符串 $string 的指定索引 $index 处插入 $insert,返回插入后的字符串。
  • string.length($string):返回字符串 $string 的长度。
  • string.slice($string, $start-at, $end-at: -1):从字符串 $string 中截取指定范围的子字符串。
  • string.split($string, $separator, $limit: null):将字符串 $string 根据分隔符 $separator 进行拆分为多个子字符串,并返回子字符串的列表。
  • string.to-upper-case($string):将字符串 $string 转换为大写形式。
  • string.to-lower-case($string):将字符串 $string 转换为小写形式。
  • string.unique-id():生成一个唯一的字符串标识符,每次调用都返回不同的值。
  • string.unquote($string):移除字符串 $string 的引号,返回不带引号的字符串。

十三、BEM命名架构

BEM (Block Element Modifier) 是一种前端开发中常用的命名约定和方法论,用于管理和组织 CSS 类名。BEM 的目标是创建可重用、可维护且易于理解的代码。

BEM 架构的核心思想是将页面分解为独立的块(Blocks),并在其内部定义元素(Elements)和修饰符(Modifiers)。这种分层结构有助于创建模块化、高度可组合的代码。

下面是 BEM 架构的主要组成部分:

  • Block(块): 块是页面上的独立组件或模块,它们是可重用的独立实体。每个块都有一个唯一的类名作为标识符,类名使用连字符分隔(例如:.block-name)
  • Element(元素): 元素是块的组成部分,它们没有独立存在的意义。元素的类名由块的类名和元素名组成,用双下划线连接(例如:.block-name__element-name)
  • Modifier(修饰符): 修饰符用于改变块或元素的外观、状态或行为。修饰符的类名由块或元素的类名、连字符和修饰符名组成,用双连字符连接(例如:.block-name--modifier-name 或 .block-name__element-name--modifier-name)

1、定义

scss
$namespace:'kw' !default;
$block-selector: "-" !default;
$element-selector: "__" !default;
$modifier-selector: "--" !default;
 
@mixin B($block) {
   $block-name: $namespace + $block-selector + $block;
   .#{$block-name}{
     @content; //内容替换
   }
}
 
@mixin E($element) {
    $element-name: & + $element-selector + $element;
    @at-root {  //跳出父级层
        #{$element-name } {
            @content;
        }
    }
}
 
@mixin M($modifier) {
    $modifier-name: & + $modifier-selector + $modifier;
    @at-root {
        #{$modifier-name} {
            @content;
        }
    }
}

2、引入

js
// 以vite为例
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
 
export default defineConfig({
    plugins: [vue()],
    css: {
        preprocessorOptions: {
            scss: {
                additionalData: "@import './src/bem.scss';"
            }
        }
    }
})

3、使用

vue
<!--以vue为例-->
<script setup lang="ts" >
  import { ref, reactive } from "vue"
  import Menu from './Menu/index.vue'
  import Content from './Content/index.vue'
  import Header from './Header/index.vue'
</script>

<template>
  <div class="kw-wraps">
        <div class="kw-wraps--primary">
          <Menu></Menu>
        </div>
        <div class="kw-wraps__right">
          <Header></Header>
          <Content></Content>
        </div>
  </div>
</template>
 
<style scoped lang="scss">
  @include B(wraps){
    //  ...
    @include E(right){
      // ...
    }
    @include M(primary){
      // ...
    }
  }
</style>

读书、摄影、画画、弹琴、编程