SASS 学习

1,113 阅读4分钟

什么是 SASS ?

SASS 文件有两种文件名后缀,分别是 .sass 和 .scss,.sass 是严格的嵌套缩进规则,而 .scss 的则是跟写 css 代码类似的大括号,分号这样的语法规则。所以个人比较喜欢 .scss 文件名后缀的。

SASS 是什么呢?它是 CSS 的扩展,是 CSS 的预处理。我们通过对 sass 文件进行编译,然后就得到对应的 css 文件。

一些扩展玩意

变量

在 Sass 中可以进行变量的定义,变量名以美元符号开头,形如:

$blue:    #007bff !default;
$indigo:  #6610f2 !default;
$purple:  #6f42c1 !default;
$pink:    #e83e8c !default;
$red:     #dc3545 !default;
$orange:  #fd7e14 !default;
$yellow:  #ffc107 !default;
$green:   #28a745 !default;
$teal:    #20c997 !default;
$cyan:    #17a2b8 !default;

这是 bootstrap 的一些颜色变量定义,其中的 !default 表示变量的默认值,即当变量没有赋值(++变量值为 null++)时,就会把该给定的值赋给变量。

变量的作用范围是在它定义的选择器嵌套层级的范围内有效(即类似块级作用域),在变量值后面加上 !global ,则变量的作用域提升为全局作用域。

变量要嵌套在字符串中,就必须要写在 #{} 之中。

// 这是一段添加浏览器厂商前缀的 mixin
@mixin prefix($declarations, $prefixes: ()) {
	@each $property, $value in $declarations {
		@each $prefix in $prefixes {
			#{'-' + $prefix + '-' + $property}: $value;
		}
		#{$property}: $value;
	}
}

嵌套规则

选择器嵌套,css 属性嵌套,例子如下(bootstrap 的小部分样式):

.alert-dismissible {
  padding-right: ($close-font-size + $alert-padding-x * 2);

  // Adjust close link position
  .close {
    position: absolute;
    top: 0;
    right: 0;
    padding: $alert-padding-y $alert-padding-x;
    color: inherit;
  }
}

以上涉及到 Sass 变量的加减乘除运算,即在 Sass 中是可以使用一些运算的,包括数字运算,颜色运算,列表运算等,有兴趣的可以在参考资料下找到具体的解析。

这里 .close 类就是嵌套在 .alert-dismissible 类里层,相当于 css:

.alert-dismissible .close {
  /* 属性 */
}

然后我们可以再看下下面的 Sass 代码,分别展示怎么引用父选择器嵌套属性

.form-check {
  position: relative;
  display: block;
  margin-bottom: $form-check-margin-bottom;
  // & 表示:父选择器
  &.disabled {
    .form-check-label {
      color: $text-muted;
    }
  }
}

.font-example {
  // 嵌套属性
  font: {
    family: sans-serif;
    size: 14rem;
    weight: bold;
  }
}

@mixin 和 @extend

@mixin 主要是用来实现样式的重用,不用大段代码到处复制粘贴,而且跟 JS 的函数很像,也是可以传递参数的。当然 @mixin 不仅可以包含属性,也可以包含 css 规则,包括选择器和选择器中的属性。

// bootstrap 的清除浮动 mixin
@mixin clearfix() {
  &::after {
    display: block;
    clear: both;
    content: "";
  }
}

// Sizing shortcuts
@mixin size($width, $height: $width) {
  width: $width;
  height: $height;
}

// bootstrap _alert.scss
@mixin alert-variant($background, $border, $color) {
  color: $color;
	// 这里展示了定义了 mixin 之后怎么去引用这个 mixin,也就是把 mixin 的代码拷贝过来
	// @include mixin名字(参数)
  @include gradient-bg($background);
  border-color: $border;
  hr {
    border-top-color: darken($border, 5%);
  }
  .alert-link {
	//   darken 是颜色函数
    color: darken($color, 10%);
  }
}

@extend className; 也就是继承一个选择器的意思。但这里并不是像 @mixin 一样把代码引进来。

$guter: 5px;
// color
$blue: #007bff !default;
$yellow: #ffc107 !default;

$priamry: $blue !default;
$warning: $yellow !default;

.btn {
	padding: $gutter;
	display: inline-block;
	text-align: center;
	white-space: nowrap;
	user-select: none;
}
.btn-primary {
	@extend .btn;
	background-color: $primary;
}
.table {
	.btn-warning {
		@extend .btn;
		background-color: $warning;
	}
}

然后让我们看下上面的 sass 编译出来的 css 是怎么样的?看看 @extend 的行为是不是我们了解的。

/* 注意看这里 */
.btn, .btn-primary, .table .btn-warning {
	padding: 5px;
	display: inline-block;
	text-align: center;
	white-space: nowrap;
	user-select: none;
}
.btn-primary {
	background-color: #007bff;
}
.table .btn-waning {
	background-color: #ffc107;
}

高级用法

  • 条件语句

    $alarm-type: danger;
    p {
    	@if $alarm-type == danger {
    		color: red;
    	} @else if $alarm-type == warning {
    		color: orange;
    	} @else {
    		color: black;
    	}
    }
    

    上述代码编译后的 css 内容:

    p {
    	color: red;
    }
    

    条件判断语句,当 @if 后面的条件判断为真时,选择器内容为条件判断紧接着的大括号内的内容;否则是之后 @else 的内容。 即 @else 可以设置条件判断为非真时的内容属性。

  • 循环语句

    // @for 形式1:
    @for $index from 1 through 3 {
    	.item-#{$index} {
    		width: 2em * $index;
    	}
    }
    // @for 形式2:
    @for $index from 1 to 3 {
    	.item-#{$index} {
    		height: 2em * $index;
    	}
    }
    

    @for 循环语句,跟 JavaScript 的 for 循环差不多,两种形式,不同点在于 throughto,一个是前后闭区间,另一个是前是闭区间,后是开区间。 上述代码编译后的 css 如下,就可以看出区别:

    /* @for $index from 1 through 3 */
    .item-1 {
    width: 2em;
    }
    .item-2 {
    width: 4em;
    }
    .item-3 {
    width: 6em;
    }
    /* @for $index from 1 to 3 */
    .item-1 {
    height: 2em;
    }
    .item-2 {
    height: 4em;
    }
    
    // 还是用之前的例子,这里的 @each 循环形式
    // @each $var in <list or map>
    @mixin prefix($declarations, $prefixes: ()) {
    	@each $property, $value in $declarations {
    		@each $prefix in $prefixes {
    			#{'-' + $prefix + '-' + $property}: $value;
    		}
    		#{$property}: $value;
    	}
    }
    
    .btn {
    	@include prefix((display: flex), webkit moz ms);
    }
    

    property,value 分别对应 $declarations 的键值对;上述代码编译后的 css 内容:

    .btn {
    -webkit-display: flex;
    -moz-display: flex;
    -ms-display: flex;
    display: flex;
    }
    
    $num: 4;
    @while $num > 0 {
    	.item-#{$num} {
    		width: 2em * $num;
    	}
    	$num: $num - 2;
    } 
    

    @while 会重复输出嵌套样式,直到条件判断会 false,就会跳出循环;上述代码编译后的 css:

    .item-4 {
    width: 8em;
    }
    .item-2 {
    width: 4em;
    }
    
  • 自定义函数

    // 形式
    // @function functionName($parameter) {
    // 	@return value;
    // }
    // 以下是 bootstrap 中的自定义函数
    // Color contrast
    @function color-yiq($color) {
    $r: red($color);
    $g: green($color);
    $b: blue($color);
    
    $yiq: (($r * 299) + ($g * 587) + ($b * 114)) / 1000;
    
    @if ($yiq >= 150) {
    	@return $yiq-text-dark;
    } @else {
    	@return $yiq-text-light;
    }
    }
    

    其中的 red(color), green(color) 和 blue($color) 就是函数的使用方式,它们也是 sass 内置的颜色函数。

模块型目录结构

|-- sass
    |-- 0-plugins
    |   |-- plugins-dir.scss
    |
    |-- 1-base
    |   |-- _base-dir.scss
    |
    |-- 2-layouts
    |   |-- _layouts-dir.scss
    |
    |-- 3-mdoules
    |   |-- _modules-dir.scss
    |
    |-- _variables.scss
    |-- _mixins.scss
    |-- app.scss

app.scss 是主入口;

全局变量写在 _variables.scss;

4个文件夹下分别放置对应的入口 sass 文件;

具体解析请查看参考资料。

Questions

CSS 的 @import 和 Sass 的 @import 区别

一开始,我也是不清楚的,只知道都鼓励不要用 CSS 的 @import。为什么呢?因为只有执行到 CSS 文件中的 @import,浏览器才回去下载 @import 进来的 CSS 文件,这样就增加了下载时间、渲染响应时间,不利于页面的优化,也使用户体验不好。

Sass 的 @import 是会在编译生成 CSS 文件时就把相对应的文件 import 进去,即编译出来的 CSS 不需要再去请求下载 @import 的文件,因为此文件的内容已经导入到 编译好的 CSS 文件了。

一些 Sass 文件以下划线(_)开头是什么意思呢?

有时候你只是需要生成一个或几个 css 文件,而不需要对应的每个 sass 文件都编译生成对应的 css 文件,那么 sass 文件名以下划线开头(_),即告知,编译的时候该文件不会独立生成对应的 css 文件。

参考资料