• CSS - 预处理器SCSS


    目录

    SCSS简介

    SCSS 编译环境安装

    Live Sass Compiler

    ​编辑

    npm包 sass

    SCSS语法概览

    嵌套语法

    选择器嵌套

    选择器嵌套中的父选择器 &

    属性嵌套

    注释

    变量

    CSS3的变量定义与使用

    SCSS的变量定义与使用

    SCSS变量的类型

    SCSS变量定义的默认值

    运算

    等号运算

    比较运算

    逻辑运算 

    算术运算

    字符串连接

    插值语法

    插值语法的作用

    插值语法的使用

     流程控制

    @if、@else if、@else

    @for

    @while

    @each

    内置函数

    数组相关内置函数

    字符串相关函数 

    对象相关函数

    三元if函数 

    自定义函数

    混入

    @mixin和@inclue的基本使用

    带参数的@mixin和@include

    @include指定传参

    @mixin的参数默认值

    @mixin可变参数

    @mixin的使用场景

    继承

    @extend继承的基本使用

    占位符 %

    多继承

    继承和混入的区别

    普通导入

    原生CSS的@import导入

    SCSS的@import导入

    SCSS中@import注意

    模块导入

    SCSS的@import的缺点

    SCSS的@use模块化导入

    模块私有变量

    模块转发

    @use的不足之处

    @forward


    SCSS简介

    SCSS是一门编程语言,*.scss文件在特定环境下编译后能转化为原生的CSS代码。

    SCSS相较于原生CSS的优势在于:SCSS的语法更符合编程思维,而原生CSS准确来说并非一门编程语言。

    另外,SCSS完全兼容CSS语法,但是浏览器不支持识别scss文件。

    SCSS 编译环境安装

    Live Sass Compiler

    VSCode安装插件:Live Sass Compiler

    该插件是基于最新的dart sass开发的,因此支持scss最新语法特性,另外Live Sass Compiler还支持为样式添加针对不同浏览器兼容性处理。

     插件配置

    1. { // settings.json根
    2. "liveSassCompile.settings.formats": [
    3. {
    4. "format": "expanded", // 生成文件的内容格式,取值只有两种expanded(展开格式,默认的)、compressed(压缩格式)
    5. "extensionName": ".css", // 生成文件的扩展名,建议当expanded时使用.css,当compressed时使用.min.css
    6. "savePath": "~/../css" // 生成文件的保存路径,~表示当前目录,~/..表示当前目录的上一级目录,~/../css 表示当前目录同级目录下的css文件夹;当前目录指的是被编译的scss文件所在的目录
    7. }
    8. ],
    9. /* 排除不进行编译检查目录 */
    10. "liveSassCompile.settings.excludeList":[
    11. "/**/node_modules/**",
    12. "/.vscode/**"
    13. ],
    14. /* 是否生成对应的map */
    15. "liveSassCompile.settings.generateMap": true,
    16. /* 是否添加兼容前缀 例如:-webkit- -moz- 等等 */
    17. "liveSassCompile.settings.autoprefix": [
    18. "> 1%",
    19. "last 2 versions"
    20. ]
    21. }

    启动插件

    这个插件的设置中savepath,即生成的css文件的保存路径,不支持动态路径,比如

    1. // savepath: "~/../css"
    2. // 编译前目录结构
    3. |- scss
    4. |- index.scss
    5. |- index
    6. |- header.scss
    7. // 实际编译后目录结构
    8. |- scss
    9. |- index.scss
    10. |- index
    11. |- header.scss
    12. |- css
    13. |- header.css
    14. |- css
    15. |- index.css
    16. // 期望编译后目录结构
    17. |- scss
    18. |- index.scss
    19. |- index
    20. |- header.scss
    21. |- css
    22. |- index.css
    23. |- index
    24. |- header.css

    因此在使用live-sass-compiler插件编译scss时,我们定义scss文件时尽量只使用单级目录结构,而不要使用多级目录结构,比如

    1. // savepath: "~/../css"
    2. // 编译前目录结构
    3. |- scss
    4. |- index.scss
    5. |- header.scss
    6. // 编译后目录结构
    7. |- scss
    8. |- index.scss
    9. |- header.scss
    10. |- css
    11. |- index.css
    12. |- header.scss

    npm包 sass

    如果项目本身就是采用多级、深层次的样式目录,那么可以考虑使用npm包:sass。

    sass也是基于dart sass开发的,底层编译原理和live-compiler-sass插件一致。

    sass安装方式如下(前提:本地有node环境)

    sass进行监听编译

    sass --watch ./scss:./css

    sass命令参数含义: 

    • --watch:表示监听./scss目录下的scss文件的变更,一旦发生变更则生成对应css文件到./css目录下,该命令参数支持简写为-w

    其他命令参数可通过 sass --help 查看

    此时,我们就可以实现多级目录的样式编译

    1. // sass -w ./scss:./css
    2. // 编译前目录结构
    3. |- scss
    4. |- index.scss
    5. |- index
    6. |- header.scss
    7. // 编译后目录结构
    8. |- scss
    9. |- index.scss
    10. |- index
    11. |- header.scss
    12. |- css
    13. |- index.css
    14. |- index
    15. |- header.css

    但是,相较于live-compiler-sass而言,sass命令还少一个功能,那就是自动完成样式对不同浏览器的兼容性处理。这个只能后面在webpack打包时集成其他插件完成了。

    SCSS语法概览

    • 基础语法
    1. 嵌套语法
    2. 注释
    3. 变量
    4. 运算
    • 复用语法
    1. 混入 @mixin 和 @inclue
    2. 占位选择器 % 和 继承 @extend
    3. 插值语法 #{}
    • 流程控制
    1. @if
    2. @for
    3. @each
    4. @while
    • 函数
    1. 内置函数
    2. 自定义函数 @function
    • 导入与转发
    1. 导入 @import
    2. 模块导入 @use
    3. 模块转发 @forward

    嵌套语法

    选择器嵌套

    如下原生CSS代码中,在进行后代选择的过程中,出现了大量的重复选择器的书写,比如.container重复了四次,.header重复了三次,这在编程思维中其实算冗余代码,但是按照CSS的语法逻辑必须这样写,才能明确表达后代关系

    1. .container {
    2. width: 1440px;
    3. margin: 0 auto;
    4. }
    5. .container .header {
    6. width: 100%;
    7. height: 50px;
    8. }
    9. .container .header ul {
    10. list-style: none;
    11. }
    12. .container .header ul li {
    13. padding: 10px;
    14. }

    但是,如果使用SCSS语法来写的话,则可以类似于HTML标签的嵌套关系来表达后代层级关系

    1. .container {
    2. width: 1440px;
    3. margin: 0 auto;
    4. .header {
    5. width: 100%;
    6. height: 50px;
    7. ul {
    8. list-style: none;
    9. li {
    10. padding: 10px;
    11. }
    12. }
    13. }
    14. }

    我们可以发现, SCSS的嵌套语法实现后代选择器的代码形式非常简洁,并且后代层级关系也足够清晰,而SCSS嵌套语法编译后生成的CSS代码与原生CSS代码完全一致。

    选择器嵌套中的父选择器 &

    SCSS的嵌套语法只能实现CSS的后代选择器,而不能实现子代选择器,兄弟选择器,以及父元素自身的伪类、伪元素选择器,比如下面CSS代码

    1. .header {
    2. width: 100%;
    3. height: 50px;
    4. }
    5. .header>ul {
    6. list-style: none;
    7. }
    8. .header>ul>li {
    9. padding: 10px;
    10. }
    11. .header>ul>li:hover {
    12. background-color: #000;
    13. color: #fff;
    14. }

    此时,我们可以在SCSS嵌套中使用&来反引用父选择器

    1. .header {
    2. width: 100%;
    3. height: 50px;
    4. &>ul {
    5. list-style: none;
    6. &>li {
    7. padding: 10px;
    8. &:hover {
    9. background-color: #000;
    10. color: #fff;
    11. }
    12. }
    13. }
    14. }

    嵌套语法中&反引用的父选择器不仅可以当成选择器使用,还可以当成选择器名字组成部分使用,如下CSS代码

    1. .header {
    2. width: 100%;
    3. height: 50px;
    4. overflow: hidden;
    5. }
    6. .header > .header-left {
    7. float: left;
    8. }
    9. .header > .header-right {
    10. float: right;
    11. }

    如果用SCSS嵌套语法写的话:

    1. .header {
    2. width: 100%;
    3. height: 50px;
    4. overflow: hidden;
    5. &>&-left {
    6. float: left;
    7. }
    8. &>&-right {
    9. float: right;
    10. }
    11. }

    属性嵌套

    在CSS中存在带来相同前缀的样式属性,比如font-size、font-weight、font-family、font-style,此时如果不采用复合写法font样式的话,则可以使用SCSS的属性嵌套,比如原生CSS代码如下

    1. .header {
    2. width: 100%;
    3. height: 50px;
    4. font-size: 20px;
    5. font-weight: bold;
    6. font-family: 'Courier New';
    7. font-style: italic;
    8. }

    改用SCSS属性嵌套语法写的话

    1. .header {
    2. width: 100%;
    3. height: 50px;
    4. font: {
    5. size: 20px;
    6. weight: bold;
    7. family: 'Courier New';
    8. style: italic;
    9. }
    10. }

    我觉得SCSS的属性嵌套语法倒显得有点鸡肋,不如使用复合写法。

    注释

    SCSS的注释有两种:

    • // 单行注释
    • /* 多行注释  */

    SCSS编译为CSS后,会保留多行注释,不会保留单行注释。

    变量

    CSS3的变量定义与使用

    CSS3的变量相当于一种特殊的样式属性,和样式属性的区别在于,定义变量属性时,其名字需要加前缀”--“,如下代码:

    1. html {
    2. --bgColor: black;
    3. }

    CSS3变量需要通过var()函数来调用

    1. html>
    2. <html lang="en">
    3. <head>
    4. <meta charset="UTF-8" />
    5. <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    6. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    7. <title>Documenttitle>
    8. <style>
    9. html {
    10. --bgColor: black;
    11. background-color: var(--bgColor);
    12. }
    13. style>
    14. head>
    15. <body>body>
    16. html>

    选择器中定义的变量,可以在当前选择器中使用,也可以在选择器对应元素的后代元素的选择器中使用,我们可以理解为CSS3变量的作用域

    如果想设定变量的作用域是全局,即当前网页中所有选择器都可以使用,则可以将变量定义在html选择器中,或者:root选择器中

     :root选择器用于匹配文档的根元素,而文档的根元素就是html元素。

    但是在CSS中,:root选择器的优先级高于html选择器,因为:root是伪类选择器,权重是10,而html是标签选择器,权重是1。

     :root选择器的意义就在于定义全局变量,而html标签则更多的用于设置全局样式。

    SCSS的变量定义与使用

    SCSS变量的名字以$开头,且$后面不能直接跟着数字,否则会编译报错。

    SCSS变量可以既可以定义在选择器中,也可以不定义在选择器中,且SCSS变量不会被编译到CSS代码中,如下代码

    SCSS变量可以直接当成样式属性值使用

    SCSS变量也是有作用域概念的,没有定义在选择器中的变量就是全局变量,即所有选择器都可以使用的变量,定义在选择器中的变量就是局部变量,即局部变量只能给当前选择器以及其后代元素的选择器使用。

    我们需要特别注意的是,CSS3变量的作用域是网页构建过程中确定的,即CSS3变量的作用域可以参照HTML标签的层级关系,比如:

    单看CSS定义,我们无法知道.link和.container的关系,此时.link中使用.container中定义的变量--color是有可能发生问题的

     但是一旦,将CSS样式和HTML结构结合

    此时,.link就可以确定是.container的后代了,因此.link中使用.container的变量就顺理成章了。

    但是,SCSS是独立编译的,无法参照HTML结构来确认样式之间的祖先后代关系,因此,SCSS中变量的使用,需要严格按照SCSS代码嵌套语法产生的祖先后代关系,即使定义在:root中的变量,也无法给非嵌套的后代选择器使用,比如

    因此,我们提出在SCSS中将全局变量定义在选择器外面,而不是定义在:root选择器中。 

    SCSS变量的类型

    SCSS变量有六种数据类型,分别是:

    • 数字:有单位的、无单位的数字
    1. grid-coloum-start:1
    2. font-size:10px
    3. line-height:1.5em
    4. width:20rem
    5. width:100vw
    6. height:100vh
    • 字符串:有引号的,无引号的字符串
    1. font-family:‘Courier New'
    2. font-family:"Courier New"
    3. font-weight:bold
    • 颜色:颜色单词、#开头16进制数、rgba函数结果
    1. background-color:black
    2. color:#000
    3. background-color:rgba(0,0,0,0)
    • 布尔:true、false
    • 空:null
    • 数组:用空格或逗号隔开,
      1. font-family: 'Courier New', Courier, monospace;
      2. padding: 10px 12px 13px 14px;
    • 对象:用括号包裹的键值对,如(key1:value1,key2:value2)

    SCSS的变量不仅可以用做样式属性的值,还可以用作运算,流程控制,函数实参,混入实参,插值。

    SCSS变量定义的默认值

    1. $color: red !default;
    2. .header {
    3. color: $color;
    4. }

    即在变量值后面加!default修饰。

    额,我觉得这也是一个鸡肋。

    运算

    SCSS运算包括:

    • 等号运算
    • 比较运算
    • 逻辑运算
    • 算术运算
    • 字符串运算

    等号运算

    等号运算有两个运算符:

    • ==:等于
    • !=:不等于

    等号运算可以用于比较任意类型的值,等号运算的结果为布尔值,等号运算常用于条件判断

    等号运算其实也算是比较运算,但是SCSS中等号运算却被从比较运算中分离出来,这是因为等号运算可以比较任意类型的值,但是比较运算只能比较数字。

     

    比较运算

    比较运算有如下运算符:

    • <
    • <=
    • >
    • >= 

    SCSS中比较运算符只能比较数字类型的值,不能比较其他类型。

    如果比较非数字类型的值,SCSS编译会报错

     

    逻辑运算 

    SCSS逻辑运算符有三个:

    • and
    • or
    • not

     需要注意的是,not运算符作用的条件需要用()包裹,避免歧义,如下例子:

     

    算术运算

    SCSS中算术运算符包括:

    • +
    • -
    • *
    • /
    • %

    算术运算只针对数字类型的值,SCSS中数字类型的值包括:不带单位的数字和带单位的数字,以及百分比数字。

    其实,百分比数字可以看成有单位的数字,单位就是百分号。

    运算情况包括:

    • 无单位数字 和 无单位数字
    • 无单位数字 和 有单位数字
    • 有单位数字 和 有单位数字

    +运算演示:

    从上面运算可以看出:

    • 无单位数字 和 无单位数字 可以直接运算,结果为无单位数字
    • 无单位数字 和 有单位数字 可以直接运算,结果为有单位数字
    • 有单位数字 和 有单位数字 运算时,
    1. 如果单位相同,则可以直接运算,结果为有单位数字
    2. 如果单位不同,则看两个单位之间是否可以互相转化,若可以则转化为前面的单位后运算,若不可以则编译报错,比如pt和px可以互相转化,但是px和rem无法互相转化,px和%无法互相转化。

    -运算演示:

    和+运算同理。

    *运算演示:

    *运算需要注意的是,不仅数字会相乘,单位也会相乘,因此*运算中,不能进行有单位数字和有单位数字的乘法,只能进行有单位数字和无单位数字,无单位数字和无单位数字的乘法。

     

    /运算演示:

     / 运算需要注意,由于原生CSS中样式属性值经常使用 / 作为分隔符,比如

    • font: 30px/1.5em sans-serif;
    • grid-row: 1 / 2;
    • grid-column: 1 / 2;

    因此,SCSS中不会默认将 / 当成除号,只有如下情况才会将 / 当成除号

    • / 运算被()包裹
    • / 运算的一方是变量或函数调用
    • / 运算在算术表达式中

     

    下面是有单位数字和无单位数字之间的除法运算情况

    我们发现:

    • 无单位数字之间可以直接相除
    • 有单位数字 可以除 无单位数字,但是无单位数字不能除有单位数字,因为单位也会参加除法运算
    • 有单位数字 可以除 有单位数字,如果单位相同,则结果无单位,如果单位不同,但是可以转化,则结果无单位,若不可转化,则编译失败

    %运算演示:

     求余运算符和百分号单位符号相同,因此求余运算时,我们必须要保证%求余运算符两边有空格,否则%会被当成百分号,如上例子。

     其实,不仅仅是求余运算符两边要加空格,所有运算符两侧都建议加空格,避免歧义。

    其实本质上来说,求余运算也算除法运算的一种,只是除法运算结果是商,求余运算结果是余数。

    通过上面例子,我们可以发现,SCSS求余运算和除法运算存在区别:

    • 无单位数字之间可以直接求余,结果也无单位
    • 无单位和有单位数字之间可以直接求余,结果有单位
    • 有单位数字之间求余,
    1. 如果单位相同,则结果单位就是除数、被除数的单位,
    2. 如果单位不同,则看是否可以转化,若可以转化,则结果单位就是被除数的单位,若不可以转化则编译报错

     

    字符串连接

    + 不仅是算术运算中的加法运算符,还是字符串运算中的字符串连接符,字符串连接有两种情况:

    • "str" + str  即有引号字符串在前,此时结果字符串有引号
    • str + "str"  即无引号字符串在前,此时结果字符串无引号

     

    插值语法

    插值语法的作用

    / 在原生SCSS默认会被当成分隔符使用,但是当 / 两边中存在变量时,/ 就会被当成除法运算符,这会导致一些问题,如下代码:

     我们期望编译结果是:font: 12px/1.5em Arial;

    但是实际上,编译报错,因为 $font-size/$line-height 被当成了除法运算,但是除数和被除数的单位不同且无法转化,因此编译报错。

    此时,我们可以使用SCSS的插值语法来避免 $font-size/$line-height 中 / 被当成除号

     插值语法即 #{},插值语法可以将变量当成普通字符串输出。

    插值语法的使用

    插值语法可以在如下地方使用:

    • 选择器名
    • 属性名
    • 属性值
    • 注释 

    需要注意的是,插值语法中使用的变量必须要在使用前定义好,否则会报错 

     流程控制

    @if、@else if、@else

    @for

    @for有两种使用方式:

    • @for $i from 起始数值 to 结束数值
    • @for $i from 起始数值 through 结束数值

    两种方式都会从起始数值开始遍历,将遍历到的数值赋值给$i,区别在于,from...to不会遍历到结束数值,而只会遍历到结束数值前一个数,而from...through可以遍历到结束数值。

    从上面例子中,我们可以发现,from 1 to 3 实际只遍历了1,2;而from 1 through 3 遍历了 1,2,3。 

    @while

    @while是另一种实现循环的方式,@while需要通过一个变量来控制循环次数,如下例中$count

    @each

    @each用于遍历数组

    内置函数

    数组相关内置函数

    • length($list):返回数组$list的长度
    • nth($list, $n):返回数组$list中第$n个元素

    字符串相关函数 

    • quote($str):给入参的字符串添加引号
    • unquote($str):给入参的字符串去除引号

    对象相关函数

    • map-has-key($map, $key):判断对象$map是否有键$key

    • map-get($map, $key) :获取对象$map下键$key对应的值

    三元if函数 

    其实就是三元表达式 

    • if($condition, $if-true, $if-false):若$condition值为true,则返回$if-true,否则返回$if-false

     

    自定义函数

    SCSS允许我们自定义函数,语法如下:

    @function function-name([$val1, $val2, $val3, ...]) {

            @return $res;

    }

    函数通过@function声明。

    函数形参可以不传,可以传一个或多个,或者可变参数。

    函数必须通过@return返回,且必须要有返回值。

    我们可以将一些复杂逻辑定义为函数,来避免复杂逻辑的重复书写,而代替以函数调用。

    比如移动端适配布局时,我们需要将元素的固定尺寸换算为rem尺寸,或者vw尺寸,此时我们就可以将换算逻辑定义为函数:

    混入

    @mixin和@inclue的基本使用

    @mixin混入可以用于定义重复使用的样式,比如下面CSS代码

    1. .header {
    2. display: flex;
    3. justify-content: center;
    4. align-items: center;
    5. width: 500px;
    6. height: 100px;
    7. }
    8. .footer {
    9. display: flex;
    10. justify-content: center;
    11. align-items: center;
    12. width: 1400px;
    13. height: 50px;
    14. }

    我们可以发现,.header和.footer存在相同重复的样式定义,此时SCSS可以将这段重复样式提取到混入@mixin中,再在.header和.footer中通过@inclue引入混入样式

    1. @mixin center {
    2. display: flex;
    3. justify-content: center;
    4. align-items: center;
    5. }
    6. .header {
    7. @include center;
    8. width: 500px;
    9. height: 100px;
    10. }
    11. .footer {
    12. @include center;
    13. width: 1400px;
    14. height: 50px;
    15. }

    带参数的@mixin和@include

    @mixin定义的样式支持接收外部参数,来作为内部样式的值,如下 @mixin flex($justify,$align)接收了两个参数$justify,$align,并且这两个参数作为了混入样式justify-content、align-item的值。

    @mixin定义参数,需要通过@include来传递值,如下.header中@include flex(start,center)传了start给$justify,传了center给@align,而这种传参方式是顺序传参,即传参顺序严格按照@mixin定义的参数顺序来。

    @include指定传参

     @include除了可以顺序传参外,还支持指定传参,即不按照@mixin定义的参数顺序传值

    @mixin的参数默认值

    当@mixin样式需要的入参较多时,一般会设置一些默认值,来减轻@include传参压力,即对于有默认值的参数,@include可以不传值

    @mixin可变参数

    有一些样式的值可以无穷传,比如backgroud:linear-gradient,此时我们无法通过手动定义无穷个@mixin参数来接收,需要使用可变参数来接收,可变参数和普通参数的区别在于,可变参数名字后面需要紧跟着三个点

    上面代码中@mixin有两个参数,$direct是普通参数,$colors是可变参数,当@include传参时,第一个参数90deg传给了$direct,其余参数都传递给了$colors。

    @mixin的使用场景

    多个样式类,如果具有重复的样式属性名,但是样式属性值不同,此时可以将这些重复的样式提取到混入@mixin中定义,可以有效的减少代码。

    继承

    @extend继承的基本使用

    在原生CSS中,我们总是将多个相关类中相同的样式提取出来形成一个基本类,比如下面代码中.btn样式类就是.btn-success、.btn-danger的基本样式类,.btn-success、.btn-danger使用时必须搭配.btn

    1. html>
    2. <html lang="en">
    3. <head>
    4. <meta charset="UTF-8" />
    5. <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    6. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    7. <title>Documenttitle>
    8. <style>
    9. .btn {
    10. display: inline-block;
    11. padding: 6px 12px;
    12. font-size: 14px;
    13. font-weight: 400;
    14. line-height: 1.5em;
    15. text-align: center;
    16. vertical-align: middle;
    17. cursor: pointer;
    18. border: 1px solid transparent;
    19. border-radius: 4px;
    20. }
    21. .btn-success {
    22. color: #fff;
    23. background-color: #5cb85c;
    24. border-color: #5cb85c;
    25. }
    26. .btn-danger {
    27. color: #fff;
    28. background-color: #d9534f;
    29. border-color: #d43f3a;
    30. }
    31. style>
    32. head>
    33. <body>
    34. <a class="btn btn-success">成功a>
    35. <a class="btn btn-danger">失败a>
    36. body>
    37. html>

    当然,为了使用简单而言,上面样式定义可以更改为

    1. html>
    2. <html lang="en">
    3. <head>
    4. <meta charset="UTF-8" />
    5. <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    6. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    7. <title>Documenttitle>
    8. <style>
    9. .btn, .btn-success, .btn-danger {
    10. display: inline-block;
    11. padding: 6px 12px;
    12. font-size: 14px;
    13. font-weight: 400;
    14. line-height: 1.5em;
    15. text-align: center;
    16. vertical-align: middle;
    17. cursor: pointer;
    18. border: 1px solid transparent;
    19. border-radius: 4px;
    20. }
    21. .btn-success {
    22. color: #fff;
    23. background-color: #5cb85c;
    24. border-color: #5cb85c;
    25. }
    26. .btn-danger {
    27. color: #fff;
    28. background-color: #d9534f;
    29. border-color: #d43f3a;
    30. }
    31. style>
    32. head>
    33. <body>
    34. <a class="btn-success">成功a>
    35. <a class="btn-danger">失败a>
    36. body>
    37. html>

    这样在使用时,.btn-success、.btn-danger就可以单独使用了。

    而在SCSS中,.btn-success、.btn-danger就是继承.btn的公共基础样式,语法如下:

    1. .btn {
    2. display: inline-block;
    3. padding: 6px 12px;
    4. font-size: 14px;
    5. font-weight: 400;
    6. line-height: 1.5em;
    7. text-align: center;
    8. vertical-align: middle;
    9. cursor: pointer;
    10. border: 1px solid transparent;
    11. border-radius: 4px;
    12. }
    13. .btn-success {
    14. @extend .btn;
    15. color: #fff;
    16. background-color: #5cb85c;
    17. border-color: #5cb85c;
    18. }
    19. .btn-danger {
    20. @extend .btn;
    21. color: #fff;
    22. background-color: #d9534f;
    23. border-color: #d43f3a;
    24. }

    可以发现,编译结果和预期一致。 

    占位符 %

    1. .btn, .btn-danger, .btn-success {
    2. display: inline-block;
    3. padding: 6px 12px;
    4. font-size: 14px;
    5. font-weight: 400;
    6. line-height: 1.5em;
    7. text-align: center;
    8. vertical-align: middle;
    9. cursor: pointer;
    10. border: 1px solid transparent;
    11. border-radius: 4px;
    12. }
    13. .btn-success {
    14. color: #fff;
    15. background-color: #5cb85c;
    16. border-color: #5cb85c;
    17. }
    18. .btn-danger {
    19. color: #fff;
    20. background-color: #d9534f;
    21. border-color: #d43f3a;
    22. }

    上面CSS代码中,其实还有优化的空间,那就是.btn定义显得可有可无了,也就是说,不定义.btn,最终效果也一致。

    1. .btn-danger, .btn-success {
    2. display: inline-block;
    3. padding: 6px 12px;
    4. font-size: 14px;
    5. font-weight: 400;
    6. line-height: 1.5em;
    7. text-align: center;
    8. vertical-align: middle;
    9. cursor: pointer;
    10. border: 1px solid transparent;
    11. border-radius: 4px;
    12. }
    13. .btn-success {
    14. color: #fff;
    15. background-color: #5cb85c;
    16. border-color: #5cb85c;
    17. }
    18. .btn-danger {
    19. color: #fff;
    20. background-color: #d9534f;
    21. border-color: #d43f3a;
    22. }

    而在SCSS中,我们可以使用占位符%,来定义公共基础样式,而占位符选择器不会被编译到CSS中

    1. %btn {
    2. display: inline-block;
    3. padding: 6px 12px;
    4. font-size: 14px;
    5. font-weight: 400;
    6. line-height: 1.5em;
    7. text-align: center;
    8. vertical-align: middle;
    9. cursor: pointer;
    10. border: 1px solid transparent;
    11. border-radius: 4px;
    12. }
    13. .btn-success {
    14. @extend %btn;
    15. color: #fff;
    16. background-color: #5cb85c;
    17. border-color: #5cb85c;
    18. }
    19. .btn-danger {
    20. @extend %btn;
    21. color: #fff;
    22. background-color: #d9534f;
    23. border-color: #d43f3a;
    24. }

     占位符继承,相当于将占位符替换为继承类,比如.btn-success中@extend %btn,相当于将%btn类替换为.btn-success类,比如下面代码

     

    多继承

    一个选择器中可以继承多个公共基础样式,即一个选择器中可以多次@extend多个样式类

    对比SCSS和CSS来看,SCSS继承语法的语义更加明确,而CSS的语义就略显单薄。 

    继承和混入的区别

    继承的是多个样式共同使用的基础样式,样式内容相同,继承可以避免在多个样式内部书写重复基础样式。

    混入的是多个样式共同使用的公共样式,样式属性相同,但是值可能不同,利用混入的传参机制,可以避免在多个样式中书写重复的样式属性。

    普通导入

    原生CSS的@import导入

    原生CSS除了可以通过link标签属性在HTML引入外部CSS文件,还可以通过@import在HTML的style标签体中、或者CSS文件中引入外部CSS文件,当然这不是link和@import最大的区别,二者最大的区别在于:

    • link标签引入外部CSS文件,会阻塞JS的引入和执行,JS的执行必须等待link引入的外部CSS文件构建完CSSOM树,而JS会阻塞DOM树构建,因此link标签引入外部CSS文件会间接阻塞DOM树构建,影响网页构建速度。
    • @import引入外部CSS文件不会阻塞JS的执行,而是会等待JS执行完成后再进行加载和CSSOM构建,因此@import引入外部CSS文件不会影响网页构建速度。

    SCSS的@import导入

    SCSS的@import可以在scss文件A中导入其他scss文件B,被导入的scss文件B中的内容会被合并到当前scss文件A内容,一起编译到CSS文件中。而对于混入,占位符这些不会被编译到CSS中的B的内容,A可以随意使用。

    @import导入scss文件可以省略其.scss后缀。 

     另外我们发现当index.scss @import "comm"时,会导致comm.scss也被编译,那么如果我们不想comm.scss被编译呢,该如何处理呢?

    此时只需要将comm.scss重命名为_comm.scss即可,其余代码不变

    @import "comm" 会优先去找_comm.scss,找不到再去找comm.scss,如果再找不到就编译报错。

     

    如果目录下同时存在comm.scss和_comm.scss,则@import "comm"也会编译报错:

     

    SCSS中@import注意

    如果SCSS中@import出现如下情况:

    • @import "xxx.css"
    • @import url(xxx)
    • @improt "http://example.com/xxx"
    • @import "xxx" screen and (min-width: 768px)

    都会被当成原生CSS的@import导入语法 

    模块导入

    SCSS的@import的缺点

    SCSS的@import是非模块化的,即SCSS的@import支持重复导入同一个scss文件,并且多次导入的同一个scss文件的内容也会被多次合并,最终编译到CSS文件中

     

    SCSS的@use模块化导入

    SCSS的@use是@import的升级版,具有@import的大部分能力,但是存在如下不同:

    @use支持缓存导入的文件,将导入的文件当成一个模块,后面即使重复导入,也不会合入多次,而是只合入一次。

    @use多次导入同一个模块时,则需要为每次导入的模块定义别名,否则无法编译通过,如上图中index.scss中,@use "comm" as c1 中 as c1 就是定义模块别名。

    一般情况下,我们不会多次@use同一个模块,而是只导入一次,此时就不需要强制为模块定义别名,导入文件的名字就是模块的默认别名。

    我们可以通过模块别名来调用scss模块中混入、占位符、变量等

     

    另外,@use还支持导入css文件,并且会合入导入的css文件的内容,这是和SCSS的@import不同的另一个地方。

    模块私有变量

    由于@use的提出,每一个scss文件都可以被当成一个模块被导入,并且导入后可以被随意使用模块中定义的变量,如果某个变量只是模块内部使用,而不像被外部使用,此时可以将变量定义为私有的,即在变量的$符号和变量名之间加一个 - 连接

    模块转发

    @use的不足之处

    有这样一种常见,a.scss中导入了b.scss,b.scss中导入了c.scss,并且a.scss中需要使用c.scss中的变量

    如果我们使用@use导入,则无法实现上面需求

    如果想在a.scss中访问c.scss中的变量$c,则需要在a中@use "c".

    混入、占位符等同理。

    @forward

    上面的需求其实是一种模块转发,SCSS支持通过@forward来转发模块中的变量、混入、占位符等

    上面b.scss中@forward转发了c.scss中的变量、混入、占位符等,而a.scss中@use模块导入了b.scss,理论上,a.scss中可以直接使用$c、@mixin flex、%btn等,但是实际上,却需要通过b.scss的模块别名来调用。

     

  • 相关阅读:
    02-Redis持久化
    9.ClickHouse系列之数据一致性保证
    OAuth2的使用场景与理解(图解防止忘记)
    二维码智慧门牌管理系统:信息安全与运行安全
    Bootstrap Studio 6.2.X Crack
    【漏洞复现】WordPress插件wp-file-manager任意文件上传漏洞(CVE-2020-25213)
    入门Vue2 11 参数传递和重定向
    如何安装RAD Studio 11.2(delphi 11.2)
    如何使用按图搜索(拍立淘)获取商品数据
    git常用命令
  • 原文地址:https://blog.csdn.net/qfc_128220/article/details/126740411