美文网首页
Sass学习笔记4 - 总结篇

Sass学习笔记4 - 总结篇

作者: 陌上无人花自开否 | 来源:发表于2020-07-02 11:33 被阅读0次

    CSS预处理器 —— Sass学习笔记4

    注释

    1. 单行注释: // 不会被编译后的css文件中
    2. 多行注释:/* */ 会被完整输出到编译后的 CSS 文件中
      1. ! 作为多行注释的第一个字符:表示在压缩输出模式下保留这条注释并输出到 CSS 文件中,通常用于添加版权信息
      2. 多行注释中也可以写入 #{} 插值语句 (interpolation) ,用于输出变量值

    嵌套规则

    1. 后代选择器

    2. 父选择器标识符 &

      1. & 的值:如果不存在父选择器,那么&的值就是空值null;若是存在,那么&的值就是一个用逗号分隔的数组列表(数组的知识可见变量类型——数组Lists一章
    3. 群组选择器

    4. 子组合选择器 >

    5. 同层组合选择器 + 和 ~

    #main {
        color: #0ff0;  
    
        // 父选择器标识符 -- 在编译时, &会被替换成父选择器 #main
        &:hover{            // 用法1: 表示给#main元素添加hover样式
            color: #fff;
        }
        .ie &{  // 用法2:在父选择器标识符&之前添加选择器,表示在.ie下的#main样式
            color: #00f;
        } 
        &-bar { // 用法3:用作占位符,编译时会用父选择器的名称替换&,表示#main-bar
            border: 1px solid; 
        } 
    
        // 后代选择器 -- 在编译时,会在.redbox前面加上父选择器名,也就是 #main .redbox
        .redbox { 
            color: #000;
        }
    
        // 群组选择器 -- 编译时,会将#main和h1,h2,h3分别组合,然后将三者重新组合成一个群组选择器,也就是 #main h1, #main h2, #main h3{a{margin-bottom: .8em;}}
        h1, h2, h3 {
            // 后代选择器
            a {margin-bottom: .8em}
        }
        
        // 直接子元素 >,编译时会在前面加上父选择器名,编译为: #main > section
        > section { background: #eee }
        
        // 同层组合选择器+ 编译为 nav + #main
        // 父选择器标识符&会被替换成父选择器名,表示 nav元素紧跟其后的#main元素
        nav + & { margin-top: 0 } 
        
        // 同层全体组合选择器~ 编译为:#main ~ artical
        // 表示#main元素后面所有同一层级的article元素,不管它们中间是否隔着别的元素 
        ~ article { border-top: 1px dashed #ccc } 
    }
    

    编译结果

    #main { color: #0ff0;}
    // 父选择器标识符编译出来的结果
    #main:hover { color: #fff; }
    .ie #main { color: #00f; }
    #main-bar { border: 1px solid; }
    // 后代选择器编译出来的结果
    #main .redbox { color: #000; }
    // 群组选择器编译出来的结果
    #main h1 a, #main h2 a, #main h3 a { margin-bottom: .8em; }
    #main > section { background: #eee; } // 子组合选择器编译结果
    nav + #main { margin-top: 0; } // 同层组合选择器编译结果
    #main ~ article { border-top: 1px dashed #ccc; } // 同层全体组合选择器编译结果
    
    @mixin does-parent-exist {
      @if & { // 如果父选择器存在,那么就给父元素添加hover样式
        &:hover { 
          /* 查看一下&的值: #{&} */ 
          color: red;
        }
      } @else {
        a {
          color: red;
        }
      }
    }
    div p{ @include does-parent-exist(); }
    // div p:hover { /*parent: div p:hover*/ color: red; }
    

    属性嵌套

    嵌套属性的规则:把属性名从中划线 - 的地方断开在根属性后边添加一个冒号 :紧跟一个{ },把子属性部分写在这个{ }块中

    编译规则:如果选择器嵌套一样,sass会把你的子属性一一解开,把根属性和子属性部分通过中划线 - 连接起来

    #main{
        // 属性嵌套在编译时,会将根属性与子属性通过中划线【-】连接起来
        background:{
            color: #f00;
            image: url('1.jpg');
            repeat: no-repeat;
            position: 50% 50%;
        }
        // 命名空间也可以包含自己的属性值
        font: 12px/24px {
            weight: 600;
            family: 'Microsoft Yahei';
        }
        // 指明例外规则
        border: 1px solid #ddd{
            left: 0;
            right: 0;
        }
    }
    

    编译结果

    #main { 
        background-color: #f00; 
        background-image: url("1.jpg"); 
        background-repeat: no-repeat; 
        background-position: 50% 50%;     
        font: 12px/24px; 
        font-weight: 600; 
        font-family: 'Microsoft Yahei'; 
        border: 1px solid #ddd; 
        border-left: 0; 
        border-right: 0; 
    }
    
    

    变量 $

    $变量名: 变量值; // 变量值:css中所有合法的属性值都可以,还可以是属性名。。 // 全局变量
    body{ 
        $变量名: 变量值; // 规则块内 -- 局部变量
        css属性: $变量名; // 变量引用。编译成css时,该$变量名会被其所指代的变量值替换
    }
    

    1. 变量作用域

    1. 全局作用域:不在嵌套规则内定义的变量则可在任何地方使用(嵌套规则外 -- 全局变量)
    2. 块级作用域:嵌套规则内定义的变量只能在嵌套规则内使用(嵌套规则内 -- 局部变量)
    3. 将局部变量转换为全局变量可以添加 `!global` 声明(嵌套规则内 -- 全局变量 -- $变量名: 变量值 !global;)
    

    2. 变量声明

    1. sass变量名以美元符号$开头,大小写敏感
    2. 可以用中划线和下划线两种形式命名,中划线方式更普遍
    3. 两种用法互相兼容,也就是说,用中划线声明的变量可以用下划线的方式引用,反之亦然
    4. 变量声明后还未生效,只有当变量被引用后才生效

    3. 变量赋值

    变量的赋值与css的赋值是一样的

    1. 任何可以用作css属性值的赋值都可以用作sass的变量值
    2. 在声明变量时,变量值也可以引用其他变量
    3. 可以在变量值后面使用 !global 声明,将局部变量 变成 全局变量
    4. 可以在变量第一次赋值时在后面使用 !default 指定变量默认值
      1. 只在第一次赋值时有用。也就是说,如果变量已经被赋值,就不会再被重新赋值,但是如果变量还没有被赋值,则会被赋予新的值。
      2. 变量是 null 空值时将视为未被 !default 赋值。

    4. 变量引用

    1. 凡是css属性的标准值可存在的地方,变量就可以使用。css生成时,变量会被它们的值所替代。
    2. 变量可以修改,但一经修改,所有引用此变量的地方(同一作用域)生成的值都会随之改变
    3. 变量有一种特殊的引用方法:插值语句 #{变量}

    插值语句 #{}

    插值 (interpolation) —— 将一个占位符,替换成一个值。

    • 通过 #{} 插值语句可以在选择器属性名中使用变量 —— 其实就是字符串连接的语法糖而已。
    • #{} 插值语句也可以在属性值中插入 SassScript —— 可以避免 Sass 运行运算表达式,直接编译 CSS。
    $name: foo;
    $attr: border;
    p.#{$name} { // 在选择器中使用变量
      #{$attr}-color: blue; // 在属性名中使用变量
    }
    // p.foo { border-color: blue; }
    
    p {
      $font-size: 12px;
      $line-height: 30px;
      font: #{$font-size}/#{$line-height};  // 避免将/用作除法运算符
    }
    // p { font: 12px/30px; }
    

    1. 用于css函数

    • Sass会把CSS函数(包括伪类)认为是字符串,所以想要在最后获得它们的值,要求你转义所有同它们一起使用的变量。否则结果会与你的预期大不相同
      • 比如:calc()url()linear-gradient()radial-gradient()cubic-bezier()
    $sidebar-width: 250px;
    $max: 3;
    // for语句循环
    @for $i from 1 through $max {
        .el:nth-of-type(#{$i}) { // 与css伪类一起使用,需要转义
            width: calc(100% - #{$sidebar-width}); // 与css函数calc一起使用,需要转义
        }
    }
    // 编译结果
    .el:nth-of-type(1) { width: calc(100% - 250px * 1); }
    .el:nth-of-type(2) { width: calc(100% - 250px * 2); }
    .el:nth-of-type(3) { width: calc(100% - 250px * 3); }
    

    2. 用于css指令

    • 与css指令一起使用,比如@support@page,最重要的是@media
      • 如果@media后面紧跟 变量,那么就必须使用插值才可以
      • 如果@media后面紧跟(()),就不再需要插值变量了,因为Sass会求出所有在这些括号里面的值
    $screen: screen;
    @media #{$screen} { // @media字符串后面紧跟着变量,那么就必须使用插值进行转义
        // ...
    }
    
    $value: 1336px;
    @media (max-width: $value) { // @media字符串后面紧跟着(),那么()中的变量就无需插值,sass会先求出括号中的值
        // ...
    }
    

    变量类型

    SassScript 支持 6 种主要的数据类型(变量的6中主要数据类型):

    • 数字1, 2, 13, 10px
    • 字符串,有引号字符串与无引号字符串,"foo", 'bar', baz
    • 颜色blue, #04a3f9, rgba(255,0,0,0.5)
    • 布尔型true, false
    • 空值null
    • 数组 (list),用空格或逗号作分隔符1.5em 1em 0 2em, Helvetica, Arial, sans-serif
    • maps, 相当于 JavaScript 的 object,(key1: value1, key2: value2)

    SassScript 也支持其他 CSS 属性值,比如 Unicode 字符集,或 !important 声明。然而Sass 不会特殊对待这些属性值,一律视为无引号字符串

    可以使用 type-of() 检查变量或者一段表达式的类型

    1. 字符串类型

    • 有引号字符串 (quoted strings) :如 "Lucida Grande" 'Microsoft Yahei'
    • 无引号字符串 (unquoted strings),如 sans-serifbold
    • 一般情况下,变量字符串在编译时类型不会有变化,sass中有引号,编译的css中也就有引号,sass中无引号,编译的css中也就没有引号。但是有一种例外情况,就是在使用插值语句#{}时,有引号字符串会被编译成无引号字符串。
    $font-family: 'Microsoft Yahei', sans-serif; // 一个有引号字符串,一个无引号字符串
    body { 
        font: 14px/24px $font-family;
        font-family: #{$font-family}; // 使用插值语句
    }
    // 编译后. 可发现在编译css文件时不会改变字符串的类型
    body { 
        font: 14px/24px "Microsoft Yahei", sans-serif; // 在编译 CSS 文件时不会改变字符串类型
        font-family: Microsoft Yahei, sans-serif;   // 有引号字符串被编译为无引号字符串
    }
    

    2. 数组 Lists

    sass 中的数组(或者叫列表)指的是 通过 空格 或者 逗号 分隔的一系列的值。事实上,独立的值也被视为数组 —— 只包含一个值的数组。数组中也可以包含子数组。如用逗号分隔:1px 2px, 5px 6px ,还有用空格分隔 (1px 2px) (5px 6px)

    数组的规则:

    • 除非列表太长不能写在80字符宽度的单行中,否则应该始终单行显示。 —— 最好单号显示
    • 除非适用于CSS,否则应该始终使用逗号作为分隔符。 —— 建议使用逗号分隔
    • 除非为空或者嵌套在另一个数组中,否则始终不要使用括号。
    • 始终不要添加尾部的逗号 —— 基于逗号分隔的数组允许保留结尾的逗号,但建议不要保留

    注意:

    • 列表第一项的索引是1,而不是0,这一点和javascript数组不同
    $list: ();  // 空数组。若被引用,编译会报错 —— 空数组不可以直接编译成 CSS
    
    $list-space: "item-1" "item-2" "item-3"; // 使用空格进行分隔
    $list-space: "item-1","item-2","item-3"; // 使用逗号进行分隔
    
    // 数组嵌套推荐使用小括号
    $list: ( 
        ("item-1.1", "item-1.2", "item-1.3"), 
        ("item-2.1", "item-2.2", "item-2.3"),
        ("item-3.1", "item-3.2", "item-3.3")
    );
    
    // nth获取元素中指定的某个值
    $list:"antzone",2,"softwhy.com";
    .div {
        content: nth($list,1);  // content: length($list) 求数组的长度
    }
    

    操作数组的函数:

    1. length($list):返回一个列表的长度值。
    2. index(list,value):返回一个值在列表中的位置值
    3. nth(list,index):返回一个列表中指定的某个标签值。
    4. append(list1,val, [$separator]):将某个值放在列表的最后。
    5. join(list1,list2, [$separator]):将两个列给连接在一起,变成一个列表。
    6. zip($lists…):将几个列表结合成一个多维的列表。。

    3. Maps

    ​ Maps可视为键值对的集合,键被用于定位值。和Lists不同,Maps必须被圆括号包围键值对被逗号分割

    ​ Maps可用于任何Lists可用的地方,在List函数中 Map会被自动转换为List , 如 (key1: value1, key2: value2)会被List函数转换为 key1 value1, key2 value2 ,反之则不能。

    操作Maps的函数:

    1. map-has-key(map,key) 判断某个key是否存在于map中
    2. map-get(map,key) 获取map中键key对应的值
    3. map-merge(map1,map2) 将两个maps合并成一个新的maps,不影响原来的maps对象
    4. map-keys(map) 和 map-values(map)
    5. map-remove(map,key) 从map中删除一个key,返回一个新的map
    6. keywords($args) 返回一个函数的阐述,这个参数可以动态设置key和value
    7. @each name,value in $map 循环maps

    示例:搭配函数使用

    // 声明一个Maps变量:Maps必须被圆括号包围,键值对被逗号分割
    $layer: (
      offcanvas: 1,
      lightbox: 500,
      dropdown: 10,
      tooltip: 15
    );
    
    // 定义函数,参数$name对应$layer中的key
    @function layer($name) {
      @if map-has-key($layer, $name) { // 判断传入的参数是否存在于$layer
        @return map-get($layer, $name); // 根据$name获取$layer中对应的值
      }
    
      @warn "The key #{$name} is not in the map '$layer'";
      @return null;
    };
    // 使用
    .m-lightbox {
      z-index: layer(lightbox); // 调用方法,并传入对应的值
    } 
    // 编译后
    .m-lightbox { z-index: 500; }
    

    搭配列表一起使用

    // 定义maps变量,每个key的值都是一个列表,表示(背景颜色, 字体颜色)
    $buttons: (
        error: (#d82d2d, #666), 
        success: (#52bf4a, #fff),
        warning: (#c23435, #fff)
    );
    // 使用
    .m-button {
        display: inling-block;
        padding: .5em; 
        // 遍历maps遍历
        @each $name, $colors in $buttons {
            $bgcolor: nth($colors, 1);  // 通过nth获取数组中的第一项
            $fontcolor: nth($colors, 2);// 通过nth获取数组中的第二项
            // 父选择器标识符&的第三种用法:用在选择器中作为占位符
            &--#{$name} {
                background-color: $bgcolor;
                color: $fontcolor;
            }
        }
    } 
    // 编译后
    .m-button { display: inling-block; padding: .5em;}
    .m-button--error { background-color: #d82d2d; color: #666; }
    .m-button--success { background-color: #52bf4a; color: #fff; }
    .m-button--warning { background-color: #c23435; color: #fff; }
    

    运算

    所有数据类型均支持相等运算 ==!=,此外,每种数据类型也有其各自支持的运算方式

    1. 数字运算

    SassScript 支持数字的运算有:

    1. 数字的加减乘除、取整等运算 (+, -, *, /, %),如果必要会在不同单位间转换值。
    2. 关系运算 <, >, <=, >=
    3. 可用于所有数据类型的相等运算 **==, != **

    1.1 除法运算

    在 SassScript 中, / 有两个作用:分隔数字、除法运算符

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

    • 如果值,或值的一部分,是变量或者函数的返回值
    • 如果值被圆括号包裹
    • 如果值是算数表达式的一部分

    如果需要使用变量,同时又要确保 / 不做除法运算而是完整地编译到 CSS 文件中,只需要用 #{} 插值语句将变量包裹。

    p { 
        $width: 1000px;
        width: $width/2;            // 值的一部分是变量 —— 除法运算符
        width: round(1.5)/2;        // 值是算术表达式的一部分 —— 除法运算符
        height: (500px/2);          // 值被圆括号包裹 —— 除法运算符
        margin-left: 5px + 8px/2px; // 加减乘除运算
        // 要使用变量,又要确保 `/` 不做除法运算 而是 完整地编译到 CSS 文件中 —— 使用插值语句
        $font-size: 12px;
        $line-height: 30px;
        font: #{$font-size}/#{$line-height};    // font: 12px/30px;
    }
    

    1.2 内置函数

    • percentage($number) 将一个不带单位的数值转成百分比
    • round($number)$number 四舍五入为整数,$number可带单位
    • ceil($number) 大于 $number ,向上取整
    • floor($number)ceil()相反,去除 $number 小数,向下取整
    • abs($number),返回 $number 的绝对值
    • min($numbers…),返回 $number... 的最小值
    • max($numbers…),返回 $number... 的最大值
    • random([$limit]),返回一个随机数

    2. 颜色值运算

    颜色的值(RGB)是分段计算进行的,也就是分别计算红色,绿色,以及蓝色的值

    1. 颜色与颜色进行算术运算; color: #010203 + #040506; // color: #050709;
    2. 颜色与数字进行算术运算;color: #010203 * 2; // color: #020406;
    3. 若颜色值中包含 alpha channel(rgba 或 hsla 两种颜色值),则必须拥有相等的 alpha 值才能进行运算
      1. 也就是说:rgba + rgba ; hsla + hsla ... 这两者的透明度 a 必须相同才可以进行运算。因为术运算不会作用于 alpha 值
      2. 颜色值的 alpha channel 可以通过 opacifytransparentize 两个函数进行调整
    4. IE 滤镜要求所有的颜色值包含 alpha 层,而且格式必须固定 #AABBCCDD,使用 ie_hex_str 函数可以很容易地将颜色转化为 IE 滤镜要求的格式
    p {
        color: #010203 + #040506; // 编译为 color: #050709;
        // 计算 01 + 04 = 05、02 + 05 = 07、03 + 06 = 09 
    
        color: #010203 * 2; // 编译为 color: #020406;
        // 计算 01 * 2 = 02、02 * 2 = 04、03 * 2 = 06
        
        color: rgba(255, 0, 0, 0.75) + rgba(0, 255, 0, 0.75); // 两者的alpha必须相同,都为0.75
        // 编译为:color: rgba(255, 255, 0, 0.75);
    } 
    
    $red: rgba(255, 0, 0, 0.5);
    $green: #00ff00;
    p {
        color: opacify($red, 0.3); // 使用 opacity 函数 -- color: rgba(255, 0, 0, 0.8);
        background-color: transparentize($red, 0.25); // 使用 transparentize 函数 
        // 编译结果: background-color: rgba(255, 0, 0, 0.25); 
    } 
    div { // 使用ie-hex-str函数将颜色转化未符合 IE 滤镜要求的格式  #RRGGBBAA
      filter: progid:DXImageTransform.Microsoft.gradient(enabled='false', startColorstr='#{ie-hex-str($green)}', endColorstr='#{ie-hex-str($red)}');
    }
    // 编译结果
    div {
      filter: progid:DXImageTransform.Microsoft.gradient(enabled='false', startColorstr=#FF00FF00, endColorstr=#80FF0000);
    }
    

    2.1 内置函数

    对于颜色的操作,scss提供了大量内置函数,非常方便。

    • rgba() 能省掉手工转换 hex 到 rgb 格式的工作
    • opacify () 增加透明度
    • transparentize () 减少透明度值
    • lighten / darken 是基于 HSL 明度变换,这个比较适合 button 按钮的 normal 态和 hover 态变换,
    • saturate / desaturate 是基于 HSL 饱和度 变换,
    • tint / shade 色彩算法,通过增加 白色(tint) 和 黑色(shade) 的占比来生成系列色
    • complement 补色
      • 在色彩理论中,如果一种颜色与另一种颜色混合后,呈现中性的灰黑色,那么这两种颜色就互为补色

    3. 字符串运算

    1. 使用 + 可用于连接字符串
      1. 有引号字符串+无引号字符串=有引号字符串; 'a' + b = 'ab'
      2. 无引号字符串+有引号字符串=无引号字符串;a + 'b' = ab
    2. 运算表达式与其他值连用时,用空格做连接符。 margin: 3px + 4px auto;
    3. 有引号的文本字符串中使用 #{} 插值语句可以添加动态的值。 contnet: 'welcome, #{username}'
    4. 空的值被视作插入了空字符串。 $value: null; content: 'I ate #{value} pies';

    3.1 内置函数

    • unquote($string) 删除 $string 前后的引号。
    • quote($string)$string前后添加引号
    • str-length($string) 返回 $string 的长度
    • str-insert($string, $insert, $index) 在指定位置插入字符
    • str-index($string, $substring) 返回指定字符在字符串的位置
    • to-upper-case($string)$string小写字母转成大写字母
    • to-lower-case($string)$string大写字母转成小写字母

    4. 布尔运算

    SassScript 支持布尔型的 andor 以及 not 运算。

    5. 数组运算

    数组不支持任何运算方式,只能使用 list functions 控制(见变量类型——数组一章)。

    5.1 内置函数

    1. length($list):返回一个列表的长度值。
    2. index(list,value):返回一个值在列表中的位置值
    3. nth(list,index):返回一个列表中指定的某个标签值。
    4. append(list1,val, [$separator]):将某个值放在列表的最后。
    5. join(list1,list2, [$separator]):将两个列给连接在一起,变成一个列表。
    6. zip($lists…):将几个列表结合成一个多维的列表。。

    Sass高级 —— 规则和指令

    @-Rules 与指令

    1. @import

    Sass 拓展了 @import 的功能,允许其导入 SCSS 或 Sass 文件。

    1. 例外情况

    通常,@import 寻找 Sass 文件并将其导入,但在以下情况下,@import 仅作为普通的 CSS 语句,不会导入任何 Sass 文件。

    • 文件拓展名是 .css
    • 文件名以 http:// 开头;
    • 文件名是 url()
    • @import 包含 media queries。
    2. 基础知识

    Sass 拓展了 @import 的功能:

    • 若不存在上面的4种情况,文件的拓展名是 .scss.sass,则导入成功
      • 就算没有指定拓展名,Sass 也会试着寻找文件名相同,拓展名为 .scss.sass 的文件并将其导入
    • Sass 允许同时导入多个文件,使用逗号 , 进行分隔
    • 导入文件也可以使用 #{ } 插值语句,但只能作用于 CSS 的 url() 导入方式,而不是通过变量动态导入 Sass 文件
    • 被导入的文件将合并编译到同一个 CSS 文件
    • 被导入的文件中所包含的变量或者混合指令 (mixin) 都可以在导入的文件中使用 —— 变量和mixin可通用
    • Sass 在当前地址寻找 Sass 文件
      • 如果需要设定其他地址,可以用 :load_paths 选项,或者在命令行中输入 --load-path 命令
    /** 4种情况 @import仅作为普通的 CSS 语句 */
    @import "foo.css";                      // 文件拓展名是 .css
    @import "foo" screen;                   // @import 包含 media queries
    @import "http://foo.com/bar";   // 文件名以 http:// 开头
    @import url(foo);                           // 文件名是 url()
    
    /** 正确示例 */
    @import "foo.scss";     // 1- 文件的拓展名是 .scss 或 .sass 
    @import "foo";              // 2- 没有扩展名,Sass会试着找 foo.scss 或者 foo.sass 进行导入
    @import "rounded-corners", "text-shadow";           // 同时导入多个文件,使用逗号进行分隔
    
    /** 3- 使用插值语句 -- 只能作用域 CSS 的 url() 导入方式*/
    $family: unquote("Droid+Sans");     // 字符串内置函数unquote(str)去除引号
    @import url("http://fonts.googleapis.com/css?family=\#{$family}"); // CSS url()方式导入
    // 编译结果: @import url("http://fonts.googleapis.com/css?family=Droid+Sans");
    
    3. 局部 (Partials)

    ​ 如果需要导入 SCSS 或者 Sass 文件,但又不希望将其编译为 CSS,只需要在文件名前添加下划线,这样会告诉 Sass 不要编译这些文件,但导入语句中却不需要添加下划线

    —— 需要导入 + 不希望被编译 ---- 将文件命名时,前面加上下划线。
    —— 如:文件名为 _colors.scss; 导入 @import colors.scss; 其实导入的就是 _colors.scss文件
    —— 注意:不可存在同名文件,即不能再有 colors.scss 文件 ---- 因为导入语句中不需要添加下划线

    注意,不可以同时存在添加下划线与未添加下划线的同名文件,添加下划线的文件将会被忽略。

    4. 嵌套 @import

    ​ 大多数情况下,一般在文件的最外层(不在嵌套规则内)使用 @import,其实,也可以将 @import 嵌套进 CSS 样式或者 @media 中,与平时的用法效果相同,只是这样导入的样式只能出现在嵌套的层中。

    可以理解成作用域:

    • 在文件最外层使用 @import ---- 导入的样式、变量、mixin等全局可用 ---- 全局
    • 在嵌套规则内,或者@media中 ---- 导入的样式只能出现在嵌套的层中 ---- 局部

    注意: 不可以在混合指令 (mixin) 或控制指令 (control directives) 中嵌套 @import

    2. @media

    CSS中的 @media 规则指定一组规则的目标媒体类型(以逗号分隔)

    Sass 中 @media 指令与 CSS 中用法一样,只是增加了一点额外的功能:允许其在 CSS 规则中嵌套

    1. 如果 @media 嵌套在 CSS 规则内,编译时,@media 将被编译到文件的最外层,包含嵌套的父选择器
    2. @mediaqueries 允许互相嵌套使用,编译时,Sass 自动添加 and
    3. @media 甚至可以使用 SassScript(比如变量,函数,以及运算符)代替条件的名称或者值
    $media: screen;
    $feature: -webkit-min-device-pixel-ratio;
    $value: 1.5;
    
    .navbar {
      width: 300px;
      // 1- @media嵌套在 CSS 规则内
      @media #{$media} { // 3-使用 SassScript 如果@media后面直接跟变量,就需要用插值语句;
        .sidebar {
          // 2- 嵌套使用
          @media ($feature: $value) {// 3-使用 SassScript 如果跟着圆括号,则不需要用插值语句
            width: 500px;
          }
        }
      }
    }
    // 编译结果
    .navbar { width: 300px; }
    // 嵌套在 CSS 规则内的@media,编译时,将被编译到文件的最外层,包含嵌套的父选择器
    @media screen and (-webkit-min-device-pixel-ratio: 1.5) { 
      .navbar .sidebar { width: 500px; } 
    }
    

    3. @extend

    ​ 情形:一个元素使用的样式与另一个元素完全相同,但又添加了额外的样式。

    ​ 通常做法:在 HTML 中给元素定义两个 class,一个通用样式,一个特殊样式。

    ​ 不便之处:必须时刻记住特殊样式需要参考通用样式

    ​ 解决之法:使用 @extend ,告诉 Sass 将一个选择器下的所有样式(包括其他使用到该选择器的样式)继承给另一个选择器

    1. 如何工作@extend继承它后面选择器的样式,但并不是简单的将样式插入到被继承选择器所在的位置,而是智能的进行了合并,比如避免无谓的重复,不能匹配任何元素的选择器也会删除
      1. 比如 a:hover{...} .error{ @extend a:hover; } 将a的所有样式继承给.error
      2. 编译时,使用.error替换a:hover,然后合并到一起,也就是 a:hover, .error{....}
    2. @extend-Only 选择器】通过 %占位符名称 标记的样式不会被编译,通过 @extend
    3. 延伸复杂的选择器】Sass 允许延伸任何定义给 单个元素 的选择器,不止是简单的Class 选择器,比如 .special.coola:hover 或者 a.user[href^="http://"]
    4. 多重延伸】同一个选择器可以一次继承多个选择器,它所包含的属性将继承给所有被延伸的选择器
      1. 比如 .warn{...} .error{ ... } .success{ @extend .warn; @extend .error; } 也可以写成 .success{ @extend .warn , .error; }
    5. 继续链】当一个选择器延伸给第二个后,可以继续将第二个选择器延伸给第三个。。。
      1. 比如 .warn{...} .error{ @extend .warn; } .success{ @extend .error; } 那么success也会继承.warn
    // .error以及其他使用到.error 的样式
    .error {
      border: 1px solid #f00;
    }
    .error.intrusion { // 其他使用到 .error 的样式也会同样继承给 .seriousError 
      background-image: url("./image/hacked.png");
    }
    // a:hover以及其他使用到a:hover的样式
    a:hover {
      text-decoration: underline;
    }
    .comment a.user:hover { // 合并规则:合并选择器列
      font-weight: bold;
    }
    // @extend-Only 选择器 -- 该选择器不能被编译
    .success %place-s{  
      font-size: 14px;
    }
    
    // @extend的使用
    .seriousError {             // 【多重延伸】 也可以写成 @extend .error, a:hover;
      @extend .error;       // 【延伸】使用 @extend 继承.error的所有样式
      @extend a:hover;      // 【延伸复杂的选择器】使用 @extend 继承a:hover 的所有样式
      border-width: 3px;    // 单独给 .seriousError 设定特殊样式
    }
    .criticalError {
      @extend .seriousError;    // 【继续延伸】将.seriousError的所有样式延伸给.criticalError
      color: #fff;                      // 单独给 .criticalError 设定特殊样式
    }
    .font{
      @extend %place-s;
    }
    

    编译为

    .error, .seriousError, .criticalError { 
      border: 1px solid #f00; 
    }
    .error.intrusion, .seriousError.intrusion, .criticalError.intrusion { 
      background-image: url("./image/hacked.png"); 
    }
    a:hover, .seriousError, .criticalError{ 
      text-decoration: underline; 
    }
    .comment a.user:hover, .comment .user.seriousError, .comment .user.criticalError { 
      font-weight: bold; 
    }
    .success .font{ 
      font-size: 14px;
    }
    .seriousError, .criticalError { 
      border-width: 3px; 
    }
    .criticalError { 
      color: #fff; 
    }
    
    1. 选择器列】暂时不可以将选择器列延伸给其他元素,但是,却可以将其他元素延伸给选择器列

      1. 比如 不可以 @extend .foo .bar@extend .foo + .bar;但是可以:.foo .bar{ @extend a; }
    2. 合并选择器列】有时会遇到复杂的情况,比如选择器列中的某个元素需要延伸给另一个选择器列,这种情况下,两个选择器列需要合并。当两个列 (sequence) 合并时:

      1. 没有包含相同的选择器,将生成两个新选择器:第一列出现在第二列之前,或者第二列出现在第一列之前
      2. 包含了相同的选择器,相同部分将会合并在一起,其他部分交替输出
      3. 注意:按照全排列的方式,生成可能选择器组合的数目也许很庞大,scss只会生成最可能的选择器组合
    #admin .tabbar a {
      font-weight: bold;
    }
    
    // 1-【合并选择器列】没有包含相同的选择器
    #demo .overview .fakelink { 
      @extend a;                                        // 延伸选择器列 #admin .tabbar a 中的单个元素a
    }
    /** 编译结果 */
    #admin .tabbar a, 
    #admin .tabbar #demo .overview .fakelink,   // 生成新的选择器1:第一列在第二列之前
    #demo .overview #admin .tabbar .fakelink {  // 生成新的选择器2:第二列在第一列之前
      font-weight: bold; 
    }
    
    // 2-【合并选择器列】包含相同的选择器-#admin
    #admin .overview .fakelink {    
      @extend a;                                        // 延伸选择器列 #admin .tabbar a 中的单个元素a
    }
    /** 分析
     * 由于它们具有共同的祖辈#admin选择器,所以将其放在所有选择器的开头毫无疑问。
     * 将.fakelink选择器插入到被继承的a选择器位置。
     * 但是我们无法判断.tabbar和.overview谁包含谁,所以两者就相互包含一下
     */
    
    /** 编译结果 */
    #admin .tabbar a, 
    #admin .tabbar .overview .fakelink,  
    #admin .overview .tabbar .fakelink {  
      font-weight: bold; 
    }
    
    1. !optional 声明】如果要求 @extend 不生成新选择器,可以通过 !optional 声明达到这个目的
    p{
      color:red;
      // @extend .notice;       // 由于并不存在一个名为notice的样式类,所以会报错
      @extend .notice !optional;    // 由于是可选的,即便notice样式类不存在也不会报错
    }
    // 编译结果
    p{ color: red; }
    
    1. 在指令中延伸】在指令中使用 @extend 时 有一些限制
      1. 比如在 @media (或者其他 CSS 指令)中使用 @extend,必须延伸给相同指令层中的选择器
    .warn{ color: yellow; }
    @media print {
      .error { color: #fdd; }
      .seriousError {
        @extend .error;                 // OK
        @extend .warn;                  // ERROR    .warn在"@media print"指令外层
        border-width: 3px;
      }
    }
    

    4. @at-root

    1. @at-root指令可以使一个或多个规则被限定输出在文档的根层级上,而不是被嵌套在其父选择器下
    2. 默认情况下,@at-root只会跳出选择器嵌套,而不能跳出指令,比如@media或@support指令
    3. 如果要跳出指令,可以搭配 without 和 with
      1. without 的作用是指定跳出哪些指令
      2. with 的作用是指定不跳出哪些指令,其他的指令都跳出
        1. @at-root (without/with: all); 表示所有
        2. @at-root (without/with: rule); 表示常规css
        3. @at-root (without/with: media); 表示 @media 指令
        4. @at-root (without/with: support); 表示 @support 指令
    .parent{
      color:red;
      @at-root .child { // 使用@at-root 将.child规则输出到文档的根层级上
        color: #fff;
      }
      // 多个规则
      @at-root {
        .child-1 { color: yellow; }
        .child-2 { color: red; }
      }
    }
    // 编译结果
    .parent { color: red; }
    .child { color: #fff; }
    .child-1 { color: yellow; }
    .child-2 { color: red; }
    
    // 默认情况下@at-root并不会使指定的规则或则选择器跳出指令
    @media print { 
      @at-root{
        .foo {  color: green;  } 
      }
    }
    // 编译结果 @media print { .foo { color: green; } }
    
    // 搭配without
    @media print {
      .parent{
        color:red;
        @at-root (without: media) { // 指定只跳出media,但并不会跳出.parent
          .child { color: #0ff; }
        }
      }
    }
    // 编译结果 @media print { .parent { color: red; } } .parent .child { color: #0ff; }
    
    // 搭配 without:all
    @media print {
      .parent{
        color:red;
        @at-root (without: all) {   // all标识要跳出所有
          .child { color: #0ff; }
        }
      }
    }
    // 编译结果  @media print { .parent { color: red; } }  .child { color: #0ff; }
    
    // 搭配 with
    @media print { 
      @supports ( transform-origin: 5% 5% ) { 
        @at-root (with: supports){ // 除了supports,其他指令都跳出
          .foo { color: green; }
        }
      } 
    }
    // 编译结果  @supports (transform-origin: 5% 5%) { .foo { color: green; } }
    

    5. @debug

    @debug伪指令检测错误,并将SassScript表达式值显示到标准错误输出流

    $font-sizes: 10px + 20px
    .container{ 
      @debug $font-sizes;
    }
    

    6. @warn

    Sass @warn指令在出现问题并希望向用户提供警告性建议时使用。它将SassScript表达式的值显示到标准错误输出流。

    $main-color:  #bdc3c7;
    @warn "Darker: " darken($main-color, 30%);
    

    控制指令

    ​ SassScript 提供了一些基础的控制指令,比如在满足一定条件时引用样式,或者设定范围重复输出格式。控制指令是一种高级功能,日常编写过程中并不常用到,主要与混合指令 (mixin) 配合使用,尤其是用在 Compass 等样式库中。

    if(exp, value1, value2)

    语法:if( expression, value1, value2 )

    说明:内置函数,基于条件expression,如果表达式结果为真,则返回 value1;为假则返回 value2。函数的结果可以参考可能未被定义的变量或具有进一步的计算。

    h2{
       color: if( 1 + 1 == 2 , green , red);
    }
    // 编译结果
    h2 { color: green; }
    

    @if exp {}

    1. @if 的表达式返回值不是 false 或者 null 时,条件成立,输出 {} 内的代码

    2. @if 声明后面可以跟多个 @else if 声明,或者一个 @else 声明。如果 @if 声明失败,Sass 将逐条执行 @else if 声明,如果全部失败,最后执行 @else 声明

    $type: monster;
    p {
      @if 1 + 1 == 2 { border: 1px solid; } // 表达式的值是 true -- 真
      @if 5 < 3 { border: 2px dotted; }     // 表达式的值是 false  -- 假
      @if null  { border: 3px double; }     // 表达式的值是 null  -- 假
    
      @if $type == ocean {
        color: blue;
      } @else if $type == matador {
        color: red;
      } @else if $type == monster {
        color: green;
      } @else {
        color: black;
      }
    }
    
    

    @for

    @for 指令可以在限制的范围内重复输出格式,每次按要求(变量的值)对输出结果做出变动。

    两种格式:

    1. @for $var from <start> through <end>
    2. @for $var from <start> to <end>

    区别在于 throughto 的含义:

    1. 当使用 through 时,条件范围包含 <start><end> 的值; start <= $val <= end ----- [start, end]
    2. 使用 to 时条件范围只包含 <start> 的值不包含 <end> 的值; start <= $val < end ----- [start, end)

    $var 可以是任何变量,比如 $i<start><end> 必须是整数值

    @for $index from 1 through 3 {
      .item-#{$index} { width: 2em * $index; }
    }
    // 编译结果
    .item-1 { width: 2em; } .item-2 { width: 4em; } .item-3 { width: 6em; }
    

    @each

    语法: @each $var in <list or map>

    说明:$var 可以是任何变量名,比如 $length$name

    <list or map> 是一连串的值,也就是值列表(数组、Maps ...)

    @each 将变量 $var 作用于值列表中的每一个项目,然后输出结果,例如:

    // 声明变量 $animal   循环列表: puma, sea-slug, egret, salamander
    @each $animal in puma, egret, sea-slug, salamander {
      .#{$animal}-icon {
        background-image: url('/images/#{$animal}.png');
      }
    }
    // 编译结果
    .puma-icon { background-image: url('/images/puma.png'); }
    .egret-icon { background-image: url('/images/egret.png'); }
    .sea-slug-icon { background-image: url('/images/sea-slug.png'); }
    .salamander-icon { background-image: url('/images/salamander.png'); }
    

    1. @each 多个分配

    语法: @each $var1, $var2, $var3 ... in <list>

    说明:<list> 表示列表的列表,每个变量将保存子列表的元素

    $mul-list: (puma, black, default), (slug, blue, pointer), (egret, white, move);
    @each $animal, $color, $cursor in $mul-list {
      .#{$animal}-icon {
        background: url('/images/#{$animal}.png');
        border-color: 2px solid $color;
        cursor: $cursor;
        }
    }
    // 编译结果
    .puma-icon { background: url('/images/puma.png'); border-color: black; cursor: default; }
    .slug-icon { background: url('/images/slug.png'); border-color: blue; cursor: pointer; }
    .egret-icon { background: url('/images/egret.png'); border-color: white; cursor: move; }
    

    2. @each 多个分配与映射

    语法: @each $var1, $var2 in <map>

    说明:<map> 表示键值对的列表

    $mul-map: (h1: red, h2: green, h3: blue);
    @each $header, $color in $mul-map {
      #{$header} {
        color: $color;
      }
    }
    // 编译结果
    h1 { color: red; } h2 { color: green; } h3 { color: blue; }
    

    @while

    @while 指令重复输出格式直到表达式返回结果为 false。这样可以实现比 @for 更复杂的循环,只是很少会用到。

    语法: while(condition) { // CSS codes... }

    说明:要注意,计数器变量需要在每次迭代时递增/递减。

    $i: 30;
    @while $i > 0 {
      .paddding-#{$i} { padding-left: 1px * $i; }
      $i: $i - 10;  // 计数器变量在每次迭代时递减
    }
    // 编译结果 
    .paddding-30 { padding-left: 30px; }
    .paddding-20 { padding-left: 20px; }
    .paddding-10 { padding-left: 10px; }
    

    混合指令

    Mixins允许创建一组可以在整个样式表中重复使用的样式,而不需要重新创建非语义类。混合指令可以包含所有的 CSS 规则绝大部分 Sass 规则,甚至通过参数功能引入变量,输出多样化的样式。

    ​ 在CSS中,mixin可以存储多个值或参数和调用函数; 它有助于避免编写重复的代码。混合名称可以交替使用下划线和连字符。

    1 定义 @mixin

    混合指令的用法是在 @mixin 后添加名称与样式

    语法: @mixin 混合指令名称 { // css code, sass code ... }

    附:为便于书写,@mixin 可以用 = 表示;即: =混合指令名称 { // css code, sass code ... }

    1. 混合样式中也可以包含其他混合样式
    2. 混合样式中应该只定义后代选择器,这样可以安全的导入到文件的任何位置。
    // 定义混合指令 clearfix
    @mixin clearfix {
      display: inline-block;
      &:after {                     // 使用父选择器标识符
        content: "."; 
        height: 0;
        clear: both;
        visibility: hidden;
      }
      * html & { height: 1px }
    }
    

    2 引用 @include

    @include 指令用于在文档中引用混合样式mixin。格式是在其后添加混合名称,并传递需要的参数(可选)。由mixin定义的样式可以包含在当前规则中。

    语法: @include 混合指令名称( 参数[可选] )

    附:为便于书写,@include 可以用 + 表示;即: +混合指令名称( 参数[可选] )

    1. 可在规则块中引用mixin;也可在最外层引用混合样式,不会直接定义属性,也不可以使用父选择器

    2. 混合样式中也可以包含其他混合样式

      @mixin highlighted-background { background-color: #fc0; }  
      @mixin does-parent-exist {
        @if & {            // 如果父选择器存在,那么就给父元素添加hover样式
          &:hover {
            /* 查看一下&的值: #{&} */
            color: red;
          }
        } @else {
          a {
            @include highlighted-background;   // 混合样式中也可以包含其他混合样式
            color: red;
          }
        }
      }
      div p{ @include does-parent-exist(); }   // 在嵌套规则块中引用mixin
      @include does-parent-exist();                        // 直接在代码最外层引用mixin 
      // 编译结果
      div p:hover { /* 查看一下&的值: div p:hover */ color: red; }
      a { background-color: #fc0; color: red; }
      

    3 参数 (Arguments)

    ​ 参数用于给混合指令中的样式设定变量并且赋值使用。在定义混合指令的时候,按照变量的格式,通过逗号分隔,将参数写进圆括号里。引用指令时,按照参数的顺序,再将所赋的值对应写进括号:

    定义: @mixin 混合指令名称( param1:默认值,param2, ... ) { // css code, sass code... }

    引用: @include 混合指令名称( val1,val2, ... )

    两种参数类型:关键字参数,可变参数

    1. 【关键字参数】引用mixin时使用 @include mixin-name($param1: $val1, $param2: $val2, ... )

      1. 关键词参数可以打乱顺序使用,如果使用默认值也可以省缺
      2. 参数名被视为变量名,下划线、短横线可以互换使用
    2. 【可变参数变量】

      1. 用于声明mixin @mixin mixin-name( $args...)
      2. 用于引用mixin @include mixin-name( $vals...)
    // 定义了两个参数$color和$width, $width的缺省值为 1in
    @mixin sexy-border($color, $width: 1in) { 
      border: { 
        color: $color; 
        width: $width; 
        style: dashed;
      }
    }
    h1 { @include sexy-border($color: blue, $width: 2in); } // 【关键字参数】
    p { @include sexy-border(blue); } // 只传入一个参数$color, 使用$width的默认值
    
    // 【可变参数变量】 用于引用mixin
    $values: #ff0000, 2in;
    h2{ @include sexy-border($values...); }
    
    // 编译结果
    h1 { border-color: blue; border-width: 2in; border-style: dashed; }
    p { border-color: blue; border-width: 1in; border-style: dashed; }
    h2 { border-color: blue; border-width: 2in; border-style: dashed; }
    

    可变参数变量:用于声明mixin

    // 用于声明mixin
    @mixin box-shadow($shadows...) {    // 参数变量 用于定义mixin
      -moz-box-shadow: $shadows;
      -webkit-box-shadow: $shadows;
      box-shadow: $shadows;
    }
    .shadows {
      @include box-shadow(0px 4px 5px #666, 2px 6px 10px #999);
    }
    // 编译为
    .shadowed {
      -moz-box-shadow: 0px 4px 5px #666, 2px 6px 10px #999;
      -webkit-box-shadow: 0px 4px 5px #666, 2px 6px 10px #999;
      box-shadow: 0px 4px 5px #666, 2px 6px 10px #999;
    }
    

    可变参数变量传递:

    // 传递
    @mixin wrapped-stylish-mixin($args...) {
      font-weight: bold;
      @include stylish-mixin($args...);
    }
    @mixin stylish-mixin($args...){
      /* #{$args} */
      color: nth($args, 1);
      width: nth($args, 2);
    }
    .stylish {
      @include wrapped-stylish-mixin(#00ff00, $width: 100px);
    }
    // .stylish { font-weight: bold; /* #00ff00, 100px */ color: #00ff00; width: 100px; }
    

    4 导入代码块

    ​ 在引用混合样式的时候,可以先将一段代码导入到混合指令中,然后再输出混合样式,额外导入的部分将出现在 @content 标志的地方。

    1. 若传入的代码块中有用到变量,该变量一定是引用时能够访问到的,而不能是mixin内部的
      1. 也就是说,在引用时 —— 先计算再传递给mixin
    2. @content 在指令中出现过多次或者出现在循环中时,额外的代码将被导入到每一个地方。
    $color-1: white;
    $color: red;
    @mixin colors($color: blue) {
      background-color: $color;
      @content;
      border-color: $color;
    }
    .colors {
      @include colors { color: $color-1; } //传递的内容块在引用时就计算,所以引用的变量不能时mixin内的
    }
    // 编译结果
    .colors { background-color: blue; color: white; border-color: blue; }
    

    函数指令

    @function 自定义函数名(param1,param2 ...){
    @return 返回值
    }

    调用: 自定义函数名(val1, val2 ...); 或者 自定义函数名($param1: val1, $param2: val2 ...);

    Sass 支持自定义函数,并能在任何属性值或 Sass script 中使用

    1. 【命名约定】为了避免命名冲突,函数名称可以带前缀,以便可以轻松区分;函数和其他Sass标识符可以交替使用下划线(_)和连字符( - )
    2. 就像mixin一样,函数也可以访问全局定义的变量,也可以接受参数,也支持变量参数。
    3. 应该使用 @return 来调用函数的返回值。
    4. 可以使用关键字参数调用SASS定义的函数 fn-name( $param1: val1, $param2: val2 ... )
    $grid-width: 40px;
    $gutter-width: 10px;
    
    @function grid-width($n) {
      @return $n * $grid-width + ($n - 1) * $gutter-width;
    }
    
    #sidebar { width: grid-width(5); }  // 使用关键字参数调用 width: grid-width($n: 5);
    

    相关文章

      网友评论

          本文标题:Sass学习笔记4 - 总结篇

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