美文网首页基于Element-ui组件库
Vue组件库必备 Sass(Dart) 知识

Vue组件库必备 Sass(Dart) 知识

作者: WebJeffery | 来源:发表于2022-08-14 11:42 被阅读0次

    前言

    Sass 有三个版本 Dart SasslibsassRuby Sass

    • Dart Sass:用 Dart 语言写的 sass 实现,于2016年11月1日发布 alpha 版本,版本1.23.0之后完全支持模块化机制。
    • libSass 也就是俗称的 node-sass,用 c/c++ 实现的 sass 版本,使用广泛,其中 node-sass 是绑定了 libsassnodejs 库,可以极快的将 .scss 文件编译为 .css 文件,安装过程很慢,官方也不推荐再使用了。
    • Ruby Sass 是最初的 Sass 实现,但是2019年3月26日被停止了,以后也不会再支持,使用者需要迁移到别的实现上

    Sass 官方团队在2020年10月也正式宣布 Libsass 将弃用,以及基于它的 Node SassSassC,并且建议用户使用 Dart Sass,主要有以下几点说明:

    • 不再建议将 LibSass 用于新的 Sass 项目, 改为使用 Dart Sass
    • 建议现有的 LibSass 用户制定计划,最终迁移到 Dart Sass,并且所有 Sass 库都制定计划,最终放弃对 LibSass 的支持。
    • 不再计划向 LibSass 添加任何新功能,包括与新 CSS 功能的兼容性。
    • LibSassNode Sass 将在尽力而为的基础上无限期维护,包括修复主要的错误和安全问题以及与最新的 Node 版本兼容。

    为什么使用 Dart Sass

    目前 Dart Sass 已经作为 Sass 最新的版本了,当执行 npm install sass -D 默认使用的是 Dart Sass 包,vue-cliVite 脚手架默认也是使用最新版本 Dart sass,而且不需要安装 node-sass【之前安装 node-sass 经常失败】

    另外,element-plus 组件库也是使用 dart dass 模块的 sass:map@use 重构了所有的 SCSS 变量,解决了由 @import 造成的重复输出问题。

    所以,为了获得 sass 提供更多更强大的功能,强烈推荐使用 dart sass

    安装使用

    如果之前安装了 node-sass,可以先卸载

    npm uninstall node-sass
    

    安装 dart-sass

    npm install sass sass-loader@^10.1.1 -D
    

    注意:之前安装 sass-loader 版本是 13.0+,版本过高导致报错,提示 TypeError: this.getOptions is not a function,退回 10.+ 可以运行成功

    如果项目之前用到 /deep/ 需要替换为 ::v-deep,全局搜索 /deep/ , 将项目里的 /deep/ 替换为 ::v-deep

    SCSS变量

    scss 变量命名规则

    • 以美元符号 $ 开头,后面跟变量名;且必须先定义,后使用
    • 变量名不能以数字开头,可包含字母、数字、下划线、横线(连接符)
    • 通过连接符 - 与下划线 _ 定义的同名变量为同一变量
    • 写法同 css,即变量名和值之间用冒号 : 分隔
    $color:#F00;
    p {
        color: $color;
    }
    

    编译为

    p {
        color: #F00;
    }
    

    SCSS 变量有两种作用域:全局变量域局部变量域

    • 全局变量:声明在最外层的变量,可在任何地方使用;或在局部变量添加 !global 声明
    • 局部变量:嵌套规则内定义的变量只能在嵌套规则内使用
    $color: red;
    .container {
        $height: 500px;
        $font-size: 16px !global; // 全局变量,外部可以使用
        font-size: $font-size;
        color: $color;
        height: $height;
    }
    .footer {
        /**$font-size使用!global 申明成全局变量了*/
        font-size: $font-size; 
        /**
        * Error: Undefined variable. 
        * $height是.container下的局部变量,无法在.footer下面编译
        */
        height:$height;
    }
    

    编译 css

    .container {
        font-size: 16px;
        color: red;
        height: 500px;
    }
    
    .footer {
         /**$font-size使用!global 申明成全局变量了*/
        font-size: 16px;
    }
    

    CSS 变量

    Sass 默认支持css变量,通过 scss 变量 和 css 变量管理可以很容易实现换肤,element-plus 是这样实现的

    css 变量 声明一个自定义属性,属性名需要以两个减号(--)开始,定义变量 --变量名:变量值 例如: --main-color: black;,由 var() 函数来获取值,例如 color: var(--main-color)

    :root {
        --main-color: #F00;
    }
    p {
        color: var(--main-color);
    }
    

    :root 是在 HTML 文档的任何地方都可以访问到它

    注意: 自定义属性名是大小写敏感的,--my-color--My-color 会被认为是两个不同的自定义属性

    通过 JavaScript 获取或者修改 CSS 变量和操作普通 CSS 属性是一样

    // 获取一个 Dom 节点上的 CSS 变量
    element.style.getPropertyValue("--my-var");
    
    // 获取任意 Dom 节点上的 CSS 变量
    getComputedStyle(element).getPropertyValue("--my-var");
    
    // 修改一个 Dom 节点上的 CSS 变量
    element.style.setProperty("--my-var", jsVar + 4);
    

    SCSS 数据类型

    • 数字:1rem2vh1310px
    • 字符串:分有引号字符串与无引号字符串,"foo"'bar'baz
    • 颜色:blue, #04a3f9, rgba(255,0,0,0.5)
    • 布尔型:truefalse
    • 空值:null 是其类型的唯一值。表示缺少值,通常由函数返回以表示缺少结果;
    • 数组 (list):用空格或逗号作分隔符,1.5em 1em 02em,Helvetica,Arial,sans-serif
    • maps:相当于 JavaScriptobject 对象,格式括号包裹键值对,逗号隔开 (key1: value1, key2: value2)
    // 数字
    $layer-index: 10;
    $border-width: 3px;
    
    // 字符串
    $font-weight: bold;
    
    // 数组
    $font-base-family: "Open Sans", Helvetica, Sans-Serif;
    $block-base-padding: 6px 10px 6px 10px;
    
    // 颜色
    $top-bg-color: rgba(255, 147, 29, 0.6);
    
    // 布尔值
    $blank-mode: true;
    
    // null
    $var: null;
    
    // maps 值
    $fonts: (
      serif: "Helvetica Neue",
      monospace: "Consolas",
    );
    
    .container {
      // 内部变量
      font-family: $font-base-family;
      font-size: $font-size;
      padding: $block-base-padding;
    
      @if $blank-mode {
        background-color: #000;
      } @else {
        background-color: #fff;
      }
    
      content: type-of($var);
      content: length($var);
      color: $top-bg-color;
    }
    
    // 如果列表中包含空值,则生成的CSS中将忽略该空值。
    .wrap {
      font: 18px $font-weight map-get($fonts, "sans");
    }
    

    !default

    可以在变量的结尾添加 !default 来给变量设置默认值,有点类似 Javascript 的逻辑运算符 let content=value || "default value" 。注意,变量是 null 时将视为未被 !default 赋值

    // 如果$content之前没使用 !default,没办法赋值覆盖
    $content: "First content";
    $content: "Second content" !default;
    #main {
        content: $content;
    }
    

    编译成 css

    #main {
      content: "First content";
    }
    

    插值语句

    通过 #{} 插值语句可以在选择器、属性名、注释中使用变量,使用 #{} 插值语句将变量包裹起来即可,和 js 中的 模板字符串 很像

    $font-size: 12px;
    $line-height: 30px;
    $class-name: danger;
    $attr: color;
    $author: "福大命大";
    
    p {
        font: #{$font-size}/#{$line-height} Arial Helvetica, sans-serif;
    }
    
    /* 
    * 这是文件的说明部分
    * @author: #{$author}
    */
    
    a.#{$class-name} {
        border-#{$attr}: #f00;
    }
    

    编译为css

    p {
        font: 12px/30px Arial Helvetica, sans-serif;
    }
    
    /* 
    * 这是文件的说明部分
    * @author: 福大命大
    */
    a.danger {
        border-color: #f00;
    }
    

    条件语句 @if

    @if 语法和 js 类似,基本格式是 @if...@else if...@else

    $theme:3;
    .container {
        @if $theme >= 5 {
            background-color: red;
        }
        @else {
            background-color: blue;
        }
    }
    

    编译为 css

    .container {
        background-color: blue;
    }
    

    @for 循环

    for 在条件范围内重复操作,这个指令包含两种格式:

    • @for $var from start through end
    • @for $var from start to end

    两者区别在于 throughto 的含义

    • 使用 through 时,条件范围包含 startend 的值;
    • 使用 to 时条件范围只包含 start 的值不包含 end 的值;

    $var 可以是任何变量,比如 $istartend 必须是整数值。

    @for $i from 1 to 3 {
      #loading span:nth-child(#{$i}) {
          width: 20 * ($i - 1) + px;
      }
    }
    

    编译为 css

    #loading span:nth-child(1) {
        width: 0px;
    }
    
    #loading span:nth-child(2) {
        width: 20px;
    }
    

    如果把 to 换成 through

    #loading span:nth-child(1) {
        width: 0px;
    }
    
    #loading span:nth-child(2) {
        width: 20px;
    }
    
    #loading span:nth-child(3) {
        width: 40px;
    }
    

    @each 循环

    @each 指令的格式是 @each $var in $list , $var 可以是任何变量名,比如 $length 或者 $name,而 $list 是一连串的值,也就是值列表

    $color-list:red green blue turquoise darkmagenta;
    @each $color in $color-list {
        $index: index($color-list, $color);
        .p#{$index - 1} {
            background-color: $color;
        }
    }
    

    编译为 css

    .p0 {
        background-color: red;
    }
    
    .p1 {
        background-color: green;
    }
    
    .p2 {
        background-color: blue;
    }
    
    .p3 {
        background-color: turquoise;
    }
    
    .p4 {
        background-color: darkmagenta;
    }
    

    @while 循环

    @while 指令循环输出直到表达式返回结果为 false。这样可以实现比 @for 更复杂的循环。比如,可以借此生成栅格化布局

    $column:12;
    @while $column>0 {
       .col-sm-#{$column} {
          width: $column / 12 * 100%;
       }
        $column:$column - 1;
    }
    

    编译为 css

    .col-sm-12 {
        width: 100%;
    }
    
    .col-sm-11 {
        width: 91.6666666667%;
    }
    
    .col-sm-10 {
        width: 83.3333333333%;
    }
    
    .col-sm-9 {
        width: 75%;
    }
    
    .col-sm-8 {
        width: 66.6666666667%;
    }
    
    .col-sm-7 {
        width: 58.3333333333%;
    }
    
    .col-sm-6 {
        width: 50%;
    }
    
    .col-sm-5 {
        width: 41.6666666667%;
    }
    
    .col-sm-4 {
        width: 33.3333333333%;
    }
    
    .col-sm-3 {
        width: 25%;
    }
    
    .col-sm-2 {
        width: 16.6666666667%;
    }
    
    .col-sm-1 {
        width: 8.3333333333%;
    }
    

    @import

    scss 拓展了 @import 的功能,允许其导入 scss或 sass文件。被导入的文件将合并编译到同一个 css 文件中,被导入的文件中所包含的变量或者混合指令 (mixin) 都可以在导入的文件中使用。

    common.scss

    $color:red;
    

    index.scss

    @import "common.scss";
    .container {
        border-color: $color;
    }
    

    编译为 css

    .container {
      border-color: red;
    }
    

    以下情况下,@import 仅作为普通的 css 语句,不会导入 scss 文件:

    • 文件拓展名是 .css
    • 文件名以 http:// 开头;
    • 文件名是 url()
    • @import 包含媒体查询。
    @import "common.css";
    @import url(common);
    @import "http://xxx.com/xxx";
    @import 'landscape' screen and (orientation:landscape);
    

    scss 允许同时导入多个文件,例如同时导入 a.scssb.scss 两个文件,不用再单独写个 import 引入

    @import "a", "b";
    

    @Partials

    如果需要导入 scss 或者 sass 文件,但又不希望将其编译为 css,只需要在文件名前添加下划线,这样会告诉 scss 不要编译这些文件。
    注意:

    • 导入语句中不需要添加下划线
    • 不可以同时存在添加下划线与未添加下划线的同名文件,添加下划线的文件将会被忽略

    _common.scss

    $color:red;
    

    index.scss

    @import "common.scss";
    .container {
        border-color: $color;
    }
    

    编译为

    .container {
      border-color: red;
    }
    

    _common.scss 文件不会编译成 _common.css 文件,Partials 主要是用来定义公共样式的,专门用于被其他的 scss 文件 import 进行使用的

    @mixin

    混合指令(Mixin)用于定义可重复使用的样式。混合指令可以包含所有的css规则,绝大部分 scss 规则,甚至可以通过参数功能引入变量,输出多样化的样式;

    @mixin@include 配合使用

    // 定义一个区块基本的样式
    @mixin block {
        width: 96%;
        margin-left: 2%;
        border-radius: 8px;
        border: 1px #f6f6f6 solid;
    }
    // 使用混入 
    .container {
        .block {
            @include block;
        }
    }
    

    编译为 css

    .container .block {
        width: 96%;
        margin-left: 2%;
        border-radius: 8px;
        border: 1px #f6f6f6 solid;
    }
    

    @mixin 可以定义多个参数和默认值

    // 定义块元素内边距,参数指定默认值
    @mixin block-padding($top:0, $right:0, $bottom:0, $left:0) {
        padding-top: $top;
        padding-right: $right;
        padding-bottom: $bottom;
        padding-left: $left;
    }
    
    // 可指定参数赋值
    .container {
        /** 不带参数 */
        @include block-padding;
        /** 按顺序指定参数值 */
        @include block-padding(10px,20px);
        /** 给指定参数指定值 */
        @include block-padding($left: 10px, $top: 20px)
    }
    

    编译 CSS

    .container {
        /** 不带参数 */
        padding-top: 0;
        padding-right: 0;
        padding-bottom: 0;
        padding-left: 0;
        /** 按顺序指定参数值 */
        padding-top: 10px;
        padding-right: 20px;
        padding-bottom: 0;
        padding-left: 0;
        /** 给指定参数指定值 */
        padding-top: 20px;
        padding-right: 0;
        padding-bottom: 0;
        padding-left: 10px;
    }
    

    可变参数:使用 ... 处理参数不固定的情况,类似于js中的函数的剩余参数

    @mixin linear-gradient($direction, $gradients...) {
        background-color: nth($gradients, 1);
        background-image: linear-gradient($direction, $gradients);
    }
    
    .table-data {
        @include linear-gradient(to right, #F00, orange, yellow);
    }
    

    编译为

    .table-data {
        background-color: #F00;
        background-image: linear-gradient(to right, #F00, orange, yellow);
    }
    

    总结

    • mixin 是可以重复使用的一组 css 声明,有助于减少重复代码,只需声明一次,就可在文件中引用;
    • 使用参数时建议加上默认值;
    • @import 导入局部模块化样式(类似功能、同一组件);
    • @minix 定义的是可重复使用的样式

    @function 函数

    @function 用于封装复杂的操作,可以很容易地以一种可读的方式抽象出通用公式和行为,函数提供返回值,常用来做计算方面的工作

    @function 参数默认值

    //change-color和hue是内置方法
    //hue 返回$color的颜色为0到360度之间的一个数字。
    //change-color 用于设置颜色的属性
    @function invert($color, $amount: 100%) {
        //@error hue($color); 调试 210deg
        $inverse: change-color($color, $hue: hue($color) + 180);
        @return mix($inverse, $color, $amount);
    }
    
    $primary-color: #036;
    .header {
        background-color: invert($primary-color, 80%);
    }
    

    编译 CSS

    .header {
        background-color: #523314;
    }
    

    可变参数 看作 js function 的 rest 参数

    @function sum($numbers...) {
        $sum: 0;
        @each $number in $numbers {
            $sum: $sum + $number;
        }
        @return $sum;
    }
    
    $widths: 50px, 30px, 100px;
    .micro {
        width: sum($widths...);
    }
    

    编译为 CSS

    .micro {
        width: 180px;
    }
    

    @return 只允许在 @function 内使用,和 js 一样,遇到 return 就会返回

    总结

    • @function@mixin 参数的使用方式没啥区别;
    • @function 用来计算,@mixin 用来封装样式,@import 用来抽离他们为一个模块

    @extend继承

    elementUIel-button 组件为例,可以使用 @extend 继承已经存在的样式,使用逗号选择器。

    // # id选择器一样的
    .button {
        display: inline-block;
        margin-bottom: 0;
        font-weight: normal;
        text-align: center;
        white-space: nowrap;
        vertical-align: middle;
        cursor: pointer;
        background-image: none;
        border: 1px solid transparent;
        padding: 6px 12px;
        font-size: 14px;
        line-height: 1.42857143;
        border-radius: 4px;
        user-select: none;
    }
    
    .btn-default {
        @extend .button;
        color: #333;
        background-color: #fff;
        border-color: #ccc;
    }
    
    .btn-danger {
        @extend .button;
        color: #fff;
        background-color: #d9534f;
        border-color: #d43f3a;
    }
    

    编译成 css

    .button, .btn-danger, .btn-default {
        display: inline-block;
        margin-bottom: 0;
        font-weight: normal;
        text-align: center;
        white-space: nowrap;
        vertical-align: middle;
        cursor: pointer;
        background-image: none;
        border: 1px solid transparent;
        padding: 6px 12px;
        font-size: 14px;
        line-height: 1.42857143;
        border-radius: 4px;
        user-select: none;
    }
    
    .btn-default {
        color: #333;
        background-color: #fff;
        border-color: #ccc;
    }
    
    .btn-danger {
        color: #fff;
        background-color: #d9534f;
        border-color: #d43f3a;
    }
    

    占位符选择器

    占位符选择器 %,与常用的 idclass 选择器写法相似,只是 #. 替换成了 %,占位符选择器必须通过 @extend 指令调用

    .button %base {
        display: inline-block;
        margin-bottom: 0;
        font-weight: normal;
        text-align: center;
        white-space: nowrap;
        vertical-align: middle;
        cursor: pointer;
        background-image: none;
        border: 1px solid transparent;
        padding: 6px 12px;
        font-size: 14px;
        line-height: 1.42857143;
        border-radius: 4px;
        user-select: none;
    }
            
    .btn-default {
        @extend %base;
        color: #333;
        background-color: #fff;
        border-color: #ccc;
    }
    
    .btn-danger {
        @extend %base;
        color: #fff;
        background-color: #d9534f;
        border-color: #d43f3a;
    }
    

    效果和上面的类选择器一样,但是,他有个有优点,占位符选择器% 所属的样式未使用时,不会被编译到 css 文件中

    .button .btn-danger, .button .btn-default {
        display: inline-block;
        margin-bottom: 0;
        font-weight: normal;
        text-align: center;
        white-space: nowrap;
        vertical-align: middle;
        cursor: pointer;
        background-image: none;
        border: 1px solid transparent;
        padding: 6px 12px;
        font-size: 14px;
        line-height: 1.42857143;
        border-radius: 4px;
        user-select: none;
    }
    
    .btn-default {
        color: #333;
        background-color: #fff;
        border-color: #ccc;
    }
    
    .btn-danger {
        color: #fff;
        background-color: #d9534f;
        border-color: #d43f3a;
    }
    

    @use

    存在兼容性问题,仅在 Dart Sass 1.23.0 以上有效,官方文档有兼容性介绍

    css 真正意义上的模块化,可以从其它 scss 样式表中加载 mixinfunction 和变量,并将来自多个样式表的 css 组合在一起。scss 还提供了很多内置模块,我们可以通过 @use 使用,官方也推荐使用 @use 替换 @import,后续会废弃 @import

    @import缺点

    • 多处导入,存在样式重复加载。
    • 没有命名空间,为了避免撞名,不敢使用简写的 classname,因此起名总是需要注意。
    • 没有私有函数的概念,样式完全暴露在使用 import 的地方,这对ui库不够友好

    @use 使用默认带有命名空间,也可以重命名空间

    src/_corners.scss

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

    index.scss

    @use "src/corners"; // 默认命名空间 corners
    // @use "src/corners" as c; // 重命名空间
    .button {
        @include corners.rounded;
        padding: 5px + corners.$radius;
        // padding: 5px + c.$radius; // 重命名 c 引用
    }
    

    as * 让模块处于全局命名空间,不需要带上命名空间就可以直接使用

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

    使用

    @use "src/corners" as *;
    
    .button {
        @include rounded;
        padding: 5px + $radius;
    }
    

    私有模块

    变量使用 - 开头,@use 不会引入这个变量

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

    index.scss

    @use "src/corners";
    
    .button {
        @include corners.rounded;
        // Error: Private members can't be accessed from outside their modules
        padding: 5px + corners.$-radius;
    }
    

    @forward

    @forward 可以看作是转发,在当前模块引入另一个模块的所有变量、mixins 和函数,直接向外暴露 API,不会在当前模块增加代码,不同于 @use@forward 不能给变量添加命名空间

    例如在 bootstrap.css 引入 functionsvariablesmixins 文件,不能直接在 bootstrap.scss 文件中使用这些引入的模块。而是需要在另一个文件中引入 @use bootstrap 模块,再去使用这些方法

    /* bootstrap.scss */
    @forward"functions";
    @forward"variables";
    @forward"mixins";
    

    @forward 通过控制 showhide 显示或隐藏模块中的某些变量

    a.scss

    @mixin rounded {
        border-radius: 100px;
    }
    footer {
        height: 1px;
    }
    

    b.scss

    $radius: 3px;
    
    c.scss
    ```scss
    @forward "a" show rounded;
    @forward "b" hide $radius;
    

    index.scss

    @import "c.scss";
    
    .button {
        @include rounded;
        padding: $radius;
    }
    // Error: Undefined variable. padding: $radius;
    

    @at-root

    @at-root 用来跳出嵌套,在多级嵌套时比较常用,包含 withoutwith

    //没有跳出
    .parent-1 {
        color:#f00;
        .child {
            width:100px;
        }
    }
    
    //单个选择器跳出
    .parent-2 {
        color:#f00;
        @at-root .child {
            width:200px;
        }
    }
    
    //多个选择器跳出
    .parent-3 {
        background:#f00;
        @at-root {
            .child1 {
                width:300px;
            }
            .child2 {
                width:400px;
            }
        }
    }
    

    编译为

    .parent-1 {
        color: #f00;
    }
    .parent-1 .child {
        width: 100px;
    }
    
    .parent-2 {
        color: #f00;
    }
    .child {
        width: 200px;
    }
    
    .parent-3 {
        background: #f00;
    }
    .child1 {
        width: 300px;
    }
    
    .child2 {
        width: 400px;
    }
    

    @without和with

    默认 @at-root 只会跳出选择器嵌套,而不能跳出 @media@support,如果要跳出这两种,则需使用@at-root (without: media)@at-root (without: support)@at-root 的关键词有四个

    • all 表示所有;
    • rule 表示常规 css 选择器;
    • media 表示 media
    • support 表示 support@support主要是用于检测浏览器是否支持css的某个属性)

    默认的 @at-root@at-root (without:rule)

    /*跳出父级元素嵌套*/
    @media print {
        .parent1{
            color:#f00;
            @at-root .child1 {
                width:200px;
            }
        }
    }
    
    /*跳出media嵌套,父级有效*/
    @media print {
        .parent2{
            color:#f00;
            @at-root (without: media) {
                .child2 {
                    width:200px;
                }
            }
        }
    }
    
    /*跳出media和父级*/
    @media print {
        .parent3{
            color:#f00;
            @at-root (without: all) {
                .child3 {
                    width:200px;
                }
            }
        }
    }
    

    编译成

    /*跳出父级元素嵌套*/
    @media print {
        .parent1 {
            color: #f00;
        }
        .child1 {
            width: 200px;
        }
    }
    /*跳出media嵌套,父级有效*/
    @media print {
        .parent2 {
            color: #f00;
        }
    }
    .parent2 .child2 {
        width: 200px;
    }
    /*跳出media和父级*/
    @media print {
        .parent3 {
            color: #f00;
        }
    }
    .child3 {
        width: 200px;
    }
    

    @at-root与 & 配合使用

    .child{
        @at-root .parent &{
            color:#f00;
        }
    }
    

    编译为

    .parent .child {
        color: #f00;
    }
    

    SCSS 内置拓展

    scss内置扩展分为 color, list, map, math, meta, selector, string 等,扩展也就是 scss 内置的一些 function,相当于 JS 内置方法

    内置函数可以使用 @use 模块化引入,也可以直接使用他提供的全局函数名调用,以下两种方式是一样的。

    @use 'sass:list';
    p {
        color: nth($list: red blue green, $n: 2); // blue
        color: list.nth($list: red blue green, $n: 2); // blue
    }
    

    String 字符串函数

    scss 有许多处理字符串的函数

    • quote($string):向字符串添加引号
    quote(hello) //"hello"
    
    • unquote($string) 移除字符串的引号
    unquote("hello") //hello
    
    • str-index($string, $substring) 返回 substring 子字符串第一次在 string 中出现的位置。如果没有匹配到子字符串,则返回 null。区分大小写。
    str-index(abcd, a) // 1 
    str-index(abcd, ab) // 1 
    str-index(abcd, X) // null
    
    • str-length($string) 获取字符串长度
    str-length("hello") //5
    
    • string-insert($string, $insert, $index) 在字符串 string 中 index 位置插入 insert
    str-insert("Hello world!", " xiaoming", 6) //"Hello xiaoming world!"
    
    • str-slice($string, $start-at, $end-at: -1) 从 string 中截取子字符串,通过 start-at 和 end-at 设置始末位置,未指定结束索引值则默认截取到字符串末尾。和 js 感觉有点相似
    str-slice("abcd", 2, 3)   => "bc" 
    str-slice("abcd", 2)      => "bcd" 
    str-slice("abcd", -3, -2) => "bc" 
    str-slice("abcd", 2, -2)  => "bc"
    

    其他

    • to-lower-case(*string*) 将字符串转成小写
    • to-upper-case(*string*) 将字符串转成大写
    • unique-id() 返回一个无引号的随机字符串作为 id

    事例代码

    p {
        &:after {
            content: quote(这是里面的内容);
        }
        background-color: unquote($string: "#F00");
        z-index:str-length("scss学习");
    }
    

    编译结果

    p {
        background-color: #F00;
        z-index: 6;
    }
    p:after {
        content: "这是里面的内容";
    }
    

    Math 数学函数

    Math 数值函数处理数值计算

    • abs(number) 返回一个数值的绝对值
    abs(13) // 13 
    abs(-13) // 13
    
    • comparable(num1, num2) 返回一个布尔值,判断 num1num2 是否可以进行比较 ,注意是否可以比较,不是比较的结果
    comparable(15px, 10px) // true 
    comparable(20mm, 1cm) // true 
    comparable(35px, 2em) // false
    
    • ceil(*number*) 向上取整
    ceil(13.24) //14
    
    • floor(*number*) 向下取整
    floor(15.84) // 15
    
    • max(number... 返回最大值
    max(5, 7, 9, 0, -3, -7) // 9
    
    • min(number... 返回最小值
    min(7, 2, 0, -2, -7) // -7
    
    • percentage(number):将数字转化为百分比的表达形式
    percentage(1.2) // 120
    
    • random():返回 0-1 区间内的小数,
    random() // 0.2783
    
    • random(number)如果传入 number 参数,返回 1 至 number 之间的整数,包括 1 和 limit
    random(10) // 4
    
    • round(number):返回最接近该数的一个整数,四舍五入
    round(15.20) // 15 round(15.80) // 16
    
    • div($number1, $number2) //=> number 返回 $number2 除以 $number1 结果
    @debug math.div(1, 2); // 0.5
    @debug math.div(100px, 5px); // 20
    @debug math.div(100px, 5); // 20px
    @debug math.div(100px, 5s); // 20px/s
    @debug math.percentage(0.2); // 20%
    
    

    事例代码

    p {
        z-index: abs(-15); // 15
        z-index: ceil(5.8); //6
        z-index: max(5, 1, 6, 8, 3); //8
        opacity: random(); // 随机 0-1
    }
    

    编译为

    p {
        z-index: 15;
        z-index: 6;
        z-index: max(5, 1, 6, 8, 3);
        opacity: 0.8636254167;
    }
    

    List 列表函数

    List 特点

    • List 函数可以访问列表中的值,向列表添加元素,合并列表等。
    • List 列表是不可变的,因此在处理列表时,返回的是一个新的列表,而不是在原有的列表上进行修改。
    • 列表的起始索引值为 1,记住不是 0

    List 方法

    • append(*list*, *value*, [*separator*]) 将单个值 value 添加到列表尾部。separator 是分隔符,默认会自动侦测,或者指定为逗号或空格,分别用 commaspace 表示
    append((a b c), d) // a b c d 
    append((a b c), (d), comma) // a, b, c, d
    
    • index(list, value) 返回元素 value 在列表中的索引位置
    index(a b c, b) // 2 
    index(a b c, f) // null
    
    • is-bracketed(list) 判断列表中是否有中括号
    is-bracketed([a b c]) // true 
    is-bracketed(a b c) // false
    
    • list-separator(list) 返回一列表的分隔符类型。可以是空格或逗号
    list-separator(a b c) // "space"
    list-separator(a, b, c) // "comma"
    
    • join(list1, list2, [separator, bracketed]) 合并两列表,将列表 list2 添加到列表 list1 的末尾。separator 是分隔符,默认会自动侦测,或者指定为逗号或空格。bracketed 默认会自动侦测是否有中括号,可以设置为 true 或 false
    join(a b c, d e f) // a b c d e f 
    join((a b c), (d e f), comma) // a, b, c, d, e, f 
    join(a b c, d e f, $bracketed: true) // [a b c d e f]
    
    • length($list) 返回列表长度
    length(a b c) // 3
    
    • set-nth(list, n, value) 设置列表第 n 项的值为 value
    set-nth(a b c, 2, x) // a x c
    
    • nth($list, $n) 获取第 n 项的值
    nth(a b c, 3) // c
    
    • zip(lists) 将多个列表按照以相同索引值为一组,重新组成一个新的多维度列表,非常好用
    zip(1px 2px 3px, solid dashed dotted, red green blue) 
    // 1px solid red, 2px dashed green, 3px dotted blue
    

    事例代码

    p {
        z-index: length(12px); //1
        z-index: length(12px 5px 8px); //3
        z-index: index(a b c d, c); //3
        padding: append(10px 20px, 30px); // 10px 20px 30px
        color: nth($list: red blue green, $n: 2); // blue
        @debug list.zip(10px 50px 100px, short mid long); // 10px short, 50px mid, 100px long
    }
    

    编译结果

    p {
        z-index: 1;
        z-index: 3;
        z-index: 3;
        padding: 10px 20px 30px;
        color: blue;
    }
    

    Map(映射) 函数

    Sass Map 是不可变的,因此在处理 Map 对象时,返回的是一个新的 Map 对象,而不是在原有的 Map 对象上进行修改。

    Map(映射)对象是以一对或多对的 key/value 来表示

    • map-get(map, key) 返回 Map 中 key 所对应的 value(值)。如没有对应的 key,则返回 null 值
    $font-sizes: ("small": 12px, "normal": 18px, "large": 24px) 
    map-get($font-sizes, "small") // 12px
    
    • map-has-key(map, key) 判断 map 是否有对应的 key,存在返回 true,否则返回 false
    $font-sizes: ("small": 12px, "normal": 18px, "large": 24px) 
    map-has-key($font-sizes, "big") // false
    
    • map-keys(map) 返回 map 中所有的 key 组成的队列
    $font-sizes: ("small": 12px, "normal": 18px, "large": 24px) 
    map-keys($font-sizes) // "small", "normal, "large"
    
    • map-values(map) 返回 map 中所有的 value 并生成一个队列
    $font-sizes: ("small": 12px, "normal": 18px, "large": 24px) 
    map-values($font-sizes) // 12px, 18px, 24px
    
    • map-merge(map1, map2) 合并两个 map 形成一个新的 map 类型,即将 map2 添加到 map1的尾部
    $font-sizes: ("small": 12px, "normal": 18px, "large": 24px) 
    $font-sizes2: ("x-large": 30px, "xx-large": 36px)
    
    map-merge($font-sizes, $font-sizes2) 
    //"small": 12px, "normal": 18px, "large": 24px, "x-large": 30px, "xx-large": 36px
    
    • map.deep-merge($map1, $map2) 将两个嵌套 map 深度合并
    $helvetica-light: (
      "weights": (
        "lightest": 100,
        "light": 300
      )
    );
    $helvetica-heavy: (
      "weights": (
        "medium": 500,
        "bold": 700
      )
    );
    
    @debug map.deep-merge($helvetica-light, $helvetica-heavy);
    // (
    //   "weights": (
    //     "lightest": 100,
    //     "light": 300,
    //     "medium": 500,
    //     "bold": 700
    //   )
    // )
    @debug map.merge($helvetica-light, $helvetica-heavy);
    // (
    //   "weights": (
    //     "medium: 500,
    //     "bold": 700
    //   )
    // )
    
    • map-remove(map, keys... )移除 map 中的 keys,多个 key 使用逗号隔开
    $font-sizes: ("small": 12px, "normal": 18px, "large": 24px) 
    map-remove($font-sizes, "small") // ("normal": 18px, "large": 24px) 
    map-remove($font-sizes, "small", "large") // ("normal": 18px)
    
    • map.deep-remove($map, $key, $keys...) 多层嵌套删除,删除层级根据参数个数
    $fonts: (
      "Helvetica": (
        "weights": (
          "regular": 400,
          "medium": 500,
          "bold": 700
        )
      )
    );
    
    @debug map.deep-remove($fonts, "Helvetica", "weights", "regular");
    // (
    //   "Helvetica": (
    //     "weights: (
    //       "medium": 500,
    //       "bold": 700
    //     )
    //   )
    // )
    
    • map.set($map, $keys..., $value) 添加 keyvalue 值,第一个是 map,最后一个是 value,中间是 key,嵌套传入多个 key...
    $fonts: (
      "Helvetica": (
        "weights": (
          "regular": 400,
          "medium": 500,
          "bold": 700
        )
      )
    );
    
    @debug map.set($fonts, "Helvetica", "weights", "regular", 300);
    // (
    //   "Helvetica": (
    //     "weights": (
    //       "regular": 300,
    //       "medium": 500,
    //       "bold": 700
    //     )
    //   )
    // )
    

    事例代码

    @use 'sass:map';
    
    // 创建Map,类似于对象
    $map: (
      key: value,
      nextkey: nextvalue
    );
    
    // 使用
    .element:before {
      content: map-get($map, key);
    }
    

    上面编译输出后的结果如下:

    .element:before {
      content: value
    }
    

    Map@each 应用

    /* 定义一个sass map名称为$icons */
    $icons: (
      checkmark: a,
      plus: b,
      minus: c
    );
    
    /* 遍历map的所有key,创建各自的类 */
    @each $name, $value in $icons {
      .icon--#{$name} {
        content: $value;
      }
    }
    
    

    编译结果

    
    /* 遍历map的所有key,创建各自的类 */
    .icon--checkmark {
      content: "a";
    }
    
    .icon--plus {
      content: "b";
    }
    
    .icon--minus {
      content: "c";
    }
    

    @each 遍历嵌套 map 多个值

    • map 一个 key 赋予多个 value(相当于数组),多个 value 之间通过逗号 , 来分割
    • 定义一系列 buttons ,每一个 key 的第一个 valuebackground-color,第二个 valuefont-color
    • 遍历 $buttons 赋值给 $colors 对象。通过 nth($colors,1)(第一个参数是对象的名称,第二个参数是值得位置)拿到第一个key。如果需要拿第二个value,那将第二个参数改为 2。
    // _m-buttons.scss
    $buttons: (
      error: (#d82d2d, #666),
      success: (#52bf4a, #fff),
      warning: (#c23435, #fff)
    );
    
    .m-button {
      display: inling-block;
      padding: .5em;
      background: #ccc;
      color: #666;
    
      @each $name, $colors in $buttons {
        $bgcolor: nth($colors, 1);
        $fontcolor: nth($colors, 2);
    
        &--#{$name} {
          background-color: $bgcolor;
          color: $fontcolor;
        }
      }
    }
    

    编译结果

    .m-button {
      display: inline-block;
      padding: .5em;
      background: #ccc;
      color: #666;
    }
    
    .m-button--error {
      background-color: #d82d2d;
      color: #666;
    }
    
    .m-button--success {
      background-color: #52bf4a;
      color: #fff;
    }
    
    .m-button--warning {
      background-color: #c23435;
      color: #fff;
    }
    

    selector 选择器函数

    selector 相关函数可对选择 css 进行一些相应的操作

    • is-superselector(super, sub) 比较两个选择器匹配的范围,即判断 super 选择器是否包含了 sub 选择器所匹配的范围,是的话返回 true,否则返回 false
    is-superselector("div", "div.myInput") // true 
    is-superselector("div.myInput", "div") // false 
    is-superselector("div", "div") // true
    
    • selector-append(selectors) 将第二个 (也可以有多个) 添加到第一个选择器的后面。
    selector-append("div", ".myInput") // div.myInput 
    selector-append(".warning", "__a") 结果: .warning__a
    
    • selector-nest(selectors) 回一个新的选择器,该选择器通过提供的列表选择器生成一个嵌套的列表
    selector-nest("ul", "li") // ul li 
    selector-nest(".warning", "alert", "div") // .warning div, alert div
    
    • selector-parse(selector) 将字符串的选择符 selector 转换成选择器队列。
    selector-parse("h1 .myInput .warning") // ('h1' '.myInput' '.warning')
    
    • selector-replace(selector, original, replacement) 给定一个选择器,用 replacement 替换 original 后返回一个新的选择器队列
    selector-replace("p.warning", "p", "div") // div.warning
    
    • selector-unify(selector1, selector2) 将两组选择器合成一个复合选择器。如两个选择器无法合成,则返回 null 值。
    selector-unify("myInput", ".disabled") // myInput.disabled 
    selector-unify("p", "h1") // null
    
    • `simple-selectors(selectors) 将合成选择器拆为单个选择器
    simple-selectors("div.myInput") // div, .myInput 
    simple-selectors("div.myInput:before") // div, .myInput, :before
    

    事例代码

    @use 'sass:selector';
    
    @debug selector.is-superselector("a", "a"); // true
    
    // 可以直接使用@forward下的前缀
    @debug selector-append("a", ".disabled"); // a.disabled
    @debug selector-extend("a.disabled", "a", ".link"); // a.disabled, .link.disabled
    
    .header {
        content: selector-append(".a", ".b", ".c") + '';
        content: selector-unify("a", ".disabled") + '';
    }
    

    meta

    meta 提供一个 mixin 和一些原子级别的 function

    • meta.calc-args获取方法的参数
    • meta.calc-name获取方法名

    meta.load-css

    meta.load-css($url,$with:())$urlcss样式全部包含进来。注意,$url引入的函数,变量和mixinmeta.load-css()后的scss中并不能用,它只会返回编译后的css代码。它的第二个参数可以修改使用了!default的变量

    src/corners

    $border-contrast: false !default;
    
    code {
        background-color: #6b717f;
        color: #d2e1dd;
        @if $border-contrast {
            border-color: #dadbdf;
        }
    }
    

    index.scss

    @use "sass:meta";
    
    body.dark {
        @include meta.load-css("src/corners", $with: ("border-contrast": true));
    }
    

    编译为

    body.dark code {
        background-color: #6b717f;
        color: #d2e1dd;
        border-color: #dadbdf;
    }
    

    相关 function

    @use "sass:meta";
    
    @debug meta.calc-args(calc(100px + 10%)); // unquote("100px + 10%")
    @debug meta.calc-args(clamp(50px, var(--width), 1000px)); // 50px, unquote("var(--width)"), 1000px
    
    @debug meta.calc-name(calc(100px + 10%)); // "calc"
    @debug meta.calc-name(clamp(50px, var(--width), 1000px)); // "clamp"
    

    color 颜色函数

    scss包含很多操作颜色的函数。

    • rgb(red, green, blue) 创建一个 Red-Green-Blue (RGB) 色。其中 R 是 "red" 表示红色,G 是 "green" 绿色,B 是 "blue" 蓝色
    rgb(0, 255, 255);
    
    • rgba(red, green, blue, alpha) 根据红、绿、蓝和 透明度值 创建一个颜色
    rgba(0, 255, 255, 0.3);
    
    • hsl(hue, saturation, lightness) 通过色相(hue)、饱和度(saturation)和亮度(lightness)的值创建一个颜色
    hsl(120, 100%, 50%); // 绿色 
    hsl(120, 100%, 75%); // 浅绿色 
    hsl(120, 100%, 25%); // dark green 
    hsl(120, 60%, 70%); // 柔和的绿色 
    
    • hsla(hue, saturation, lightness, alpha) 通过色相(hue)、饱和度(saturation)、亮度(lightness)和 透明(alpha) 的值创建一个颜色
    hsl(120, 100%, 50%, 0.3); // 绿色带有透明度 
    hsl(120, 100%, 75%, 0.3); // 浅绿色带有透明度
    
    • grayscale(color) 将一个颜色变成灰色,相当于 desaturate( color,100%)
    grayscale(#7fffd4); // #c6c6c6
    
    • complement(color) 返回一个补充色,相当于 adjust-hue($color,180deg)
    complement(#7fffd4); // #ff7faa
    
    • invert(*color*, weight) 返回一个反相色,红、绿、蓝色值倒过来,而透明度不变
    invert(white); // black
    
    • red(color) 从一个颜色中获取其中红色值(0-255),可用于取出某个 hex 颜色中的红色值
    red(#7fffd4); // 127 
    red(red); // 255
    
    • green(color) 从一个颜色中获取其中绿色值(0-255)
    green(#7fffd4); // 255 
    green(blue); // 0
    
    • blue(color) 从一个颜色中获取其中蓝色值(0-255)
    blue(#7fffd4); // 212 
    blue(blue); // 255
    
    • hue(color) 返回颜色在 HSL 色值中的角度值 (0deg - 255deg)
    hue(#7fffd4); // 160deg
    
    • saturation(color) 获取一个颜色的饱和度值(0% - 100%)
    saturation(#7fffd4); // 100%
    
    • lightness(color) 获取一个颜色的亮度值(0% - 100%)
    lightness(#7fffd4); // 74.9%
    
    • alpha(color) 返回颜色的 alpha,返回值为 01
    alpha(#7fffd4); // 1
    
    • opacity(color) 获取颜色透明度值(0-1)
    opacity(rgba(127, 255, 212, 0.5); // 0.5
    
    • mix(color1, color2, weight) 把两种颜色混合起来。

    weight 参数必须是 0% 到 100%。默认 weight 为 50%,表明颜色各取 50% color1 和 color2 的色值相加。如果 weight 为 25%,那表明颜色为 25% color1 和 75% color2 的色值相加

    • adjust-hue(color, degrees) 通过改变一个颜色的色相值(-360deg - 360deg),创建一个新的颜色
    adjust-hue(#7fffd4, 80deg); // #8080ff
    
    • lighten(color, amount) 通过改变颜色的亮度值(0% - 100%),让颜色变亮,创建一个新的颜色

    • darken(color, amount) 通过改变颜色的亮度值(0% - 100%),让颜色变暗,创建一个新的颜色

    • saturate(color, amount) 提高传入颜色的色彩饱和度。等同于 adjust-color( color, saturation: amount)

    • desaturate(color, amount) 调低一个颜色的饱和度后产生一个新的色值。同样,饱和度的取值区间在 0% ~ 100%。等同于 adjust-color(color, saturation: -amount)

    • opacify(color, amount) 降低颜色的透明度,取值在 0-1 之。等价于 adjust-color(color, alpha: amount)

    • fade-in(color, amount)降低颜色的透明度,取值在 0-1 之。等价于 adjust-color(color, alpha: amount)

    • transparentize(color, amount) 提升颜色的透明度,取值在 0-1 之间。等价于 adjust-color(color, alpha: -amount)

    • fade-out(color, amount) 提升颜色的透明度,取值在 0-1 之间。等价于 adjust-color(color, alpha: -amount)

    事例代码

    .p1 {
        // 让颜色变亮
        color:scale-color(#5c7a29, $lightness: +30%);
    }
    
    .p2 {
        // 让颜色变暗
        color:scale-color(#5c7a29, $lightness: -15%);
    }
    
    .p3 {
        // 降低颜色透明度
        color:scale-color(#5c7a29, $alpha: -40%);
    }
    
    

    编译为

    .p1 {
        color: #95c249;
    }
    
    .p2 {
        color: #4e6823;
    }
    
    .p3 {
        color: rgba(92, 122, 41, 0.6);
    }
    

    调试相关

    @debug

    @debug 打印表达式的值,方便调试。

    $font-sizes: 10px + 20px;
        $style: (
            color: #bdc3c7
        );
    .container {
        @debug $style;
        @debug $font-sizes;
    }
    

    输出结果

    Debug:(color: #bdc3c7)
    Debug:30px
    

    @error

    @error 显示错误信息

    @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.
    }
    

    输出结果

    Error: "Property top must be either left or right."
      ╷
    3 │     @error "Property #{$property} must be either left or right.";
      │     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      ╵
      example.scss 3:5   reflexive-position()
      example.scss 19:3  root stylesheet
    
    

    @warn

    @warn显示警告性建议,会显示堆栈信息。

    $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);
    }
    

    显示警告信息

    Warning: Unknown prefix wekbit.
        example.scss 6:7   prefix()
        example.scss 16:3  root stylesheet
    

    总结

    内容知识比较多,通过查阅 Sass 官方文档和阅读文章翻译,收集整理常用 Sass 知识,方便在阅读 element-plus 组件库源码查阅

    相关文章

      网友评论

        本文标题:Vue组件库必备 Sass(Dart) 知识

        本文链接:https://www.haomeiwen.com/subject/jizcgrtx.html