前言
SASS是最古老,也是最成熟的CSS预处理语言,诞生于2007年。有着比LESS更强大的功能。不过最开始的缩进式语法,并不能被广大用户接受,所以虽然出现很早但是普及却不如LESS,但是随着自身语法的改进和Ruby on Rails的大力推进,绝大多数人都开始选用SASS作为自己的预处理器开发利器。官网给出的介绍是:它是一门高于CSS的元语言,能用来编写清晰且结构化的描述文件样式,有着比普通CSS更强大的功能。提供更简洁、更优雅的语法,同时提供多种功能来创建可维护和管理的样式表。
什么是CSS预处理器
CSS 预处理器用一种专门的编程语言,为 CSS 增加了一些编程的特性,进行 Web 页面样式设计,然后再编译成正常的 CSS 文件,以供项目使用,特点是预处理器是一门单独的语言,有变量、逻辑判断、函数,还有,使用时,需要编译成正常的CSS
CSS预处理器技术已经非常成熟,当然有许多不同的CSS预处理器,比如SASS/LESS/Stylus 等等,关于那种预处理器是最优秀的,各大技术论坛争论纷纷。本文将要介绍的就是能够让绝大多数前端开发工程师满意的一种:
SASS 和 SCSS
两者其实是同一种东西,我们平时都称之为Sass,两者不同之处有以下两点
-
文件扩展名不同分别为
.sass
和.scss
-
语法书写方式不同。SASS以严格缩进式语法来编写,不包含大括号和分号,类似Jade;而SCSS的语法书写则和CSS的语法书写非常类似,举个栗子
SASS语法 $font-stack: Helvetica, sans-serif //定义变量 $primary-color: #333 //定义变量 body font: 100% $font-stack color: $primary-color SCSS语法 $font-stack: Helvetica, sans-serif; $primary-color: #333; body { font: 100% $font-stack; color: $primary-color; } 两者编译出来的CSS文件 body { font: 100% Helvetica, sans-serif; color: #333; }复制代码
可见,Sass
和CSS
的书写语法差别很大,而Sass
书写则和CSS
几乎一样,所以这也是为什么越来越多的前端开发使用Sass
中的SCSS方式来开发的原因
Sass的安装
MAC系统
- brew install ruby
- sudo gem install sass
- sass -v
Window系统
打开ruby 命令行
命令行输入 gem install sass复制代码
如果上面安装失败,可能是因为该安装途径已经被墙了,需要更换安装的源,这里我们使用淘宝的源,附上安装步骤
Sass基础
接下来所说的所有语法书写格式都是以
.scss
格式
基本格式
以.scss
作为文件后缀,代码在一组大括号内且结束处都有一个分号作为结尾,同样的CSS代码
body { font: 100% Helvetica, sans-serif; color: #333;}复制代码
我们使用SCSS语法格式将上面重写一下
$font-stack: Helvetica, sans-serif;$primary-color: #333;body { font: 100% $font-stack; color: $primary-color;}复制代码
编译.scss文件
Sass是一个预处理器,将编写的.scss
文件编译成对应的.css
文件,项目中使用的还是.css
为后缀的文件。具体的编译方式有三种:命令编译、GUI编译、自动化编译
-
命令编译:使用指令代码进行编译
sass src/:out/
如 sass sass/:css/ 这条指令意味着把’sass’文件夹中的所有’.scss’文件编译成’.css’文件,并把这些’.css’文件放置到css目录下。这样做的缺点是只能一次性编译,每次更改后都需要重复编译。
如果这样做太麻烦的话,可以使用’watch’功能,watch功能会监视指定文件的改动,自动执行编译
sass --watch src/:out/复制代码
-
GUI编译:
推荐使用Koloa
-
自动化编译:这里推荐使用 gulp
var gulp = require('gulp'); var sass = require('gulp-ruby-sass'); gulp.task('sass', function () { gulp.sass('./scss/*.scss') .pipe(gulp.dest('./css')); }); gulp.task('watch', function() { gulp.watch('scss/*.scss', ['sass']); }); gulp.task('default', ['sass','watch']);复制代码
-
常见编译问题
- Sass不支持‘GBK’编码,所以在创建文件时就需要将编码格式设置为’utf-8’
- 不建议在项目中的文件路径或者文件名中出现中文汉字
不同的输出风格
Sass中编译出来的样式风格可以按照不同的风格进行显示。主要包括如下几种
- 嵌套式输出 nested
- 展开式输出 expanded
- 紧凑式输出 compact
- 压缩式输出 compressed
具体的输出方式通过编译指令完成
sass --watch test.scss:test.css --style nested复制代码
对于如下的css样式,分别举例四种输出方式
nav { ul {margin: 0;} li { display: inline-block; } a {display: block;}}复制代码
-
嵌套式输出 nested
nav ul { margin: 0; } nav li { display: inline-block; } nav a { display: block;}复制代码
-
展开式输出 expanded(和nested类似,但是大括号独占一行)
nav ul { margin: 0; } nav li { display: inline-block; } nav a { display: block; }复制代码
-
紧凑型输出 compact
nav ul { margin: 0; } nav li { display: inline-block; } nav a { display: block;}复制代码
-
压缩性输出 compressed
nav ul{margin:0;padding:0;}nav li{display:inline-block}nav a{display:block;}复制代码
SCSS 语法
变量
- 声明变量
Sass中变量包含三部分:$、变量名称、变量值,如
$width: 300px复制代码
-
变量类型
-
普通变量
$fontSize: 12px; body{ font-size: $fontSize; }复制代码
-
默认变量:仅需要在值得后面加上 !default
$baseLineHeight:1.5 !default; body{ line-height: $baseLineHeight; }复制代码
-
类似于JavaScript中的短路赋值 var onePoint = req.query.from || ‘China’;
变量的调用
直接在需要赋值的地方使用$ 变量名就可以完成调用
作用域
分为全局作用域和局部作用域
$color: orange !default;//定义全局变量.block { color: $color;//调用全局变量,orange}em { $color: red;//定义局部变量 a { color: $color;//调用局部变量,red }}复制代码
混合宏
使用混合宏可以自定义重复利用的而组件,关键字是 @mixin
。在混合宏中,我们可以自定义代码的样式,添加判断逻辑等等
-
混合宏的声明
不带参数的混合宏
@mixin border-radius { -webkit-border-radius: 5px; border-radius: 5px; }复制代码
带参数的混合宏:入参如果不存在使用默认的
5px
。这个5px
可以是页面的默认属性,而特殊的border-radius
则可以在调用是通过入参控制@mixin border-radius($radius:5px){ -webkit-border-radius: $radius; border-radius: $radius; }复制代码
-
调用混合宏
调用不带参数的混合宏(上文中定义的)
button { @include border-radius; }复制代码
调用带参数的混合宏
button { @include border-radius(3px); }复制代码
混合宏的不足
混合宏可以解决重复代码块的问题,但是也有不足。最大的不足之处在于混合宏会生成冗余的代码块,比如在不同的地方调用一个相同的混合宏时。
@mixin border-radius{ -webkit-border-radius: 3px; border-radius: 3px;}.box { @include border-radius; margin-bottom: 5px;}.btn { @include border-radius;}复制代码
生成的CSS内容如下
.box { -webkit-border-radius: 3px; border-radius: 3px; margin-bottom: 5px;}.btn { -webkit-border-radius: 3px; border-radius: 3px;}复制代码
可以看出两个地方调用混合宏,两个地方都出现了混合宏的代码内容,并没有只能的将相同的代码进行合并成如下的样式。
.box .btn{ -webkit-border-radius: 3px; border-radius: 3px;}.box { margin-bottom: 5px;}复制代码
@extend
继承
CSS原本就有继承机制的,内部元素默认会继承外部元素的某些属性。Sass中也有继承这么一说,通过@extend
来继承已经存在的代码块。
.btn { border: 1px solid #ccc; padding: 6px 10px; font-size: 14px;}.btn-primary { background-color: #f36; color: #fff; @extend .btn;}.btn-second { background-color: orange; color: #fff; @extend .btn;}复制代码
编译后
.btn, .btn-primary, .btn-second { border: 1px solid #ccc; padding: 6px 10px; font-size: 14px;}.btn-primary { background-color: #f36; color: #fff;}.btn-second { background-clor: orange; color: #fff;}复制代码
从示例代码中我们可以看出,在Sass中的继承,可以继承类样式中的所有代码,而编译出的CSS会合并到一起,形成组合选择器.btn, .btn-primary, .btn-second {}
的形式
混合宏定义了一个可以支持参数传递的复用代码块,但是代码块本身必不能直接作为样式;继承作为虽然不能提供参数传递的复用代码块,但是父类本身可以作为样式~
占位符
Sass
中的占位符 %placeholder
类似于继承中的基类,可以通过@extend
继承选中基类中的代码。但是不同的是通过占位符声明的代码,如果不被@extend
的话,不会产生任何代码,所以和继承是有差别的,举个栗子。
%mt5 { margin-top: 5px;}%pt5{ padding-top: 5px;}.btn { @extend %mt5; @extend %pt5;}.block { @extend %mt5; span { @extend %pt5; }}复制代码
从输出中可以看到,占位符的输出中不包含占位符本身
.btn, .block { margin-top: 5px;}.btn, .block span { padding-top: 5px;}复制代码
相同的实现,我们再来看一下继承
.mt5 { margin-top: 5px;}.pt5{ padding-top: 5px;}.btn { @extend .mt5; @extend .pt5;}.block { @extend .mt5; span { @extend .pt5; }} 继承的输出中包含了基类本身.mt5, .btn, .block { margin-top: 5px;}.pt5, .btn, .block span { padding-top: 5px;}复制代码
是不是感觉占位符很像继承和
@mixin
的混合体。不支持参数传递的复用代码块(继承),本身不出现在输出中(@mixin
)
混合宏 VS 继承 VS 占位符
什么时候该使用它们中的某一个呢?在这里总结一下如何使用这几个容易让人弄混的概念
- 混合宏:不会自动合并相同的样式文件,会造成代码冗余,但是可以传递参数
- 继承:会合并相同的代码,通过组合选择器输出,但是不能传递参数
- 占位符:编译出来的代码和使用继承基本上是一样的,自是不会在代码中出现占位符本身
占位符是独立定义的,不调用的时候是不会在代码充产生任何代码。而继承首先要保证有一个基类的存在,不管调用与不调用,积累的样式都会出现在编译出来的额CSS代码中
下面的代码帮助大家记忆三者的区别
//=========//混合宏写法@mixin mt($var){ margin-top: $var; }.block { @include mt(4px); span { display:block; @include mt(3px); }}.header { color: orange; @include mt(5px); span{ display:block; @include mt(5px); }}//混合宏写法输出.block { margin-top: 4px; }.block span { display: block; margin-top: 3px; }.header { color: orange; margin-top: 5px; }.header span { display: block; margin-top: 5px; }//=========//继承写法.mt{ margin-top: 5px; }.block { @extend .mt; span { display:block; @extend .mt; }}.header { color: orange; @extend .mt; span{ display:block; @extend .mt; }}// 继承写法输出.mt, .block, .block span, .header, .header span { margin-top: 5px; }.block span { display: block; }.header { color: orange; }.header span { display: block; }//=========//占位符%mt{ margin-top: 5px; }.block { @extend %mt; span { display:block; @extend %mt; }}.header { color: orange; @extend %mt; span{ display:block; @extend %mt; }}//占位符写法输出.block, .block span, .header, .header span { margin-top: 5px; }.block span { display: block; }.header { color: orange; }.header span { display: block; }复制代码