一、CSS预处理器出现的原因
1、无法嵌套书写代码繁重、冗杂、逻辑混乱。
2、没有变量和样式复用机制,属性值只能以字面量的形式重复输出。
总结:代码复用性低,不易于维护。
注:现在的CSS是可以定义变量的。
二、出名的CSS预处理器介绍
1、SCSS/SASS
SASS(.scss)。于2007年诞生,最早也是最成熟的CSS预处理器器,拥有ruby社区的支持和compass这一最强大的CSS框架,目前受LESS影响,已经进化到了全面兼容CSS的SASS。
2、LESS
LESS(.less)。于2009年诞生,借鉴了SASS的长处,并兼容了CSS语法,使得开发使用起来更为顺手,但是相比于SASS,其编程功能不够丰富,反而初始SASS进化称为了SCSS。
3、Stylus
Stylus(.stylus)。于2010年诞生,出自Node.js社区,主要用来给Node项目进行CSS预处理支持,人气较前两者偏低。
三、SCSS和SASS之间的关系
SASS有两套语法:
1、第一个或更新的语法被称为SCSS。它是CSS语法的扩展,这意味着每个有效的CSS样式都是具有相同含义的有效CSS文件。下文描述的SASS功能增强了此语法,使用此语法的文件扩展名为.scss。
2、第二种或更旧的语法被称为SASS,提供了一种更为简洁的CSS编写方式。它使用缩进而不是方括号来表示选择器的嵌套,并使用换行符而不是分号来分隔属性。使用此语法的文件扩展名为.sass。
- 任何一种格式可以直接导入(@import)到另一种格式中使用,或者通过sass-convert命令行工具转换成另一种格式。
四、使用CSS预处理器的优劣
1、优点
CSS预处理器为CSS增加了一些编程的特性,无需考虑浏览器的兼容性问题。支持嵌套、变量和逻辑等。可以让CSS更加简洁、逻辑分明等等。
2、缺点
CSS的文件体积和复杂性不可控,增加了调试难度和成本等。
五、选择SCSS的原因
1、官方介绍
SASS是一款强化CSS的辅助工具,它在CSS语法的基础上增加了变量(variables)、嵌套(nested rules)、混合(mixins)、导入(inline imports)等高级功能,这些拓展令CSS更加强大与优雅,使用SASS以及SASS的样式库(如compass)有助于更好的组织管理样式文件,以及更高效的开发项目。
2、特色功能
- 完全兼容CSS3
- 在CSS基础上增加变量、嵌套(nesting)、混合(mixins)等功能
- 通过函数进行颜色值与属性值的运算
- 提供控制指令(control directives)等高级功能
- 自定义输出格式
六、环境配置
less、scss(sass)和stylus代码并不能被浏览器直接解析,所以必须先将它们编译成css代码。
现有框架已经提供了css预处理选项,编译相关配置会自动帮我们生成!所以只有在“练习”情况下才有必要安装该环境。
1、安装分类
(1)不依赖编辑器
#全局安装scss预处理器,使用终端命令实现编译
① Node环境下的node-sass模块(推荐)
② Node环境下的dart-sass模块(性能上更好)
③ Ruby环境下的sass模块
④ Dart环境下的sass模块
注:这里的推荐顺序针对的是“练习”场景,而开发环境下推荐使用的是dart-sass
本质:某个语言的第三方库或者命令行工具。
(2)依赖编辑器
① IDE代表:Webstrom 前提是安装上述“1”中的命令行编译工具,配置自动命令,另安装一个代码提示插件scss。
② 编辑器代表:vscode 安装Easy Sass(编译)和Sass(代码提示)两个插件。
2、安装步骤
(1)不依赖编辑器
首选 Node环境(node-sass)
a、安装
- 安装node
- 安装cnpm(不推荐直接将源换为淘宝镜像!!!)
$npm i -g cnpm --registry=https://registry.npm.taobao.org
- 安装node-sass
$npm i -g node-sass 或 $cnpm i -g node-sass
- 检查是否安装成功
$node-sass -v
b、使用
① 单文件编译
$node-sass 原有的scss文件 生成的css文件
$node-sass 原有的scss文件 -o 生成目录
# example:
$node-sass a.scss b.css
$node-sass a.scss css_files
② 多文件编译
$node-sass 原有的scss文件目录 -o 生成的css文件目录
#example:
$node-sass c -o d
③ 文件监听模式
在“①”和“②”的基础上添加“-w”命令行参数即可
$node-sass -w 原有的scss文件 -o 生成目录
$node-sass -w 原有的css文件目录 -o 生成的css文件目录
-dart-sass
a、安装
1、安装node https://node.js.org(官网)或 https://npm.taobao.org/mirrors/node(镜像)
2、*安装cnpm(不推荐直接将源换位淘宝镜像!!)
$npm i -g cnpm --registry=https://registry.npm.taobao.org
3、安装dart-sass
$npm i -g sass 或 $ cnpm i -g sass
#注:该模块为第三方库,所以可以考虑使用cnpm i sass -D(-D == --save-dev)仅对某个小项目当做开发时依赖进行使用。
b、使用
/* 该模块的官方文档:https://sass-lang.com/documentation/js-api */
var sass = require('sass');
sass.render({file:scss_filename},function(err,result){/* ...*/});
//OR
var result = sass.renderSync({file:scss_filename});、
//注:默认情况下renderSync()的速度是render()的两倍以上,这是由于异步回到所带来的开销导致的。
Ruby环境
a、安装
1、安装Ruby Downloads
2、安装完成后需测试安装有没有成功,运行
CMD
输入命令:ruby -v3、*配置镜像
$ gem sources -a https://gems.ruby-china.com/-r https://rubygems.org
4、*查看源
$ gem sources -l
确保只有gems.ruby-china.com一个源
5、安装css
$gem install sass
6、检查是否安装成功
$ sass -v
如果出现了SSL证书错误情况,修改~/.gemrc文件,增加ssl_verify_mode:0配置,以便于RubyGems可以忽略SSL证书错误。
# ~表示用户根目录,windows的文件位置为C:\Users\用户名\.gemrc
---
:sources:
-https://gems.ruby-china.com
:ssl_verify_mode:0
b、使用
#注:最好带上“-C --sourcemap==none”参数。
#注:Sass命令行工具根据文件的拓展名判断所使用的的语法格式,没有文件名时sass命令默认编译.sass文件,添加--sass选项或者使用scss命令编译SCSS文件。
① 单文件编译
$sass 原有的scss文件[:]生成的css文件
#example:
$sass a.scss b.css
② 多文件编译
$ sass --watch 原有的scss文件目录:生成是css文件目录
#注:必须加“--watch”
③ 文件监听模式
$sass --watch 原有的scss文件:生成的css文件
$sass --watch 原有的scss文件目录:生成的css文件目录
# example
$sass --watch -C --sourcemap=none scss:css
#效果:编译进程不结束,监听文件内容
Dart环境
a、安装
1、安装Dart https://dart.dev/tools/sdk/archive
2、*配置镜像,添加环境变量
https://pub.flutter-io.cn 或 https://mirrors.tuna.tsinghua.edu.cn/dart-pub/
3、windows打开此电脑,添加系统变量PUB-HOSTED_URL=https://pub.flutter-io.cn
Linux键入$echo 'export PUB_HOSTED_URL=https://pub.flutter-io.cn' >>~/.bashrc
4、安装sass
全局安装:$pub global activate sass (可执行文件)
项目安装:pubspec.yaml填写好依赖后,执行$pub get (.dart代码)
5、检查是否安装成功:$sass -v
b、使用
① 全局安全模式
1、单文件编译
$sass 原有的scss文件[:]生成的css文件
#example:
$sass a.scss b.css
2、多文件编译
$sass 原有的scss文件目录/:生成的css文件目录/
#example
$sass scss/:css/
3、文件监听模式
$sass --watch 原有的scss文件:生成的css文件
$sass --watch 原有的scss文件目录:生成的css文件目录
#注:都必须加上“:”
# example
$sass --watch scss:css
#效果:编译进程不结束,监听文件内容
②局部安全模式
/* 运行.dart代码*/
/* 前提是在pubsepc.yaml文件中添加依赖
dev_dependencies:
sass:lastest
main.dart */
import 'package:sass/sass.dart ’as sass;
void main(List<String> args){
print(sass.compile(args.first);)
}
//OR
void main(List<String> args){
var result = sass.compile(arguments[0]);
new File(arguments[1]).writeAsStringSync(result);
}
// dart main.dart styles.scc styles.css
(2)依赖编辑器
① WebStrom
- 安装上述命令行工具之一(以node-sass为例演示)
- 依次打开并点击:webstrom -> Settings -> Tools -> Files Watchers -> + -> 选择SCSS文件标识
- Name随意写,供自己看而已
- File Type选择SCSS Style Sheet
- Scope选择All Places
- Program选择可执行文件的路径(这里以node-sass为例)
- Arguments按需选择(这里以*$FileName$:$FileNameWithoutExtension$.css*为例)
- Output paths to refresh按需选择(这里以*$FileNameWithoutExtension$.css*为例)
- 点击OK,配置完成
②VSCode
- 安装Easy Sass(编译)和Sass(代码提示)两个插件(注意大小写,否则找不到)
- 点击插件右下角的设置图标后点击"扩展设置",最后点击"在settings.json中编辑",开始设置关于Easy Sass的配置
- 会自动生成下方图片内的配置
- 添加*"easysass.targetDir": $path*,可将编译后的css文件放入*$path*路径下(默认为当前路径)。例如生成到css文件下内。
七、SassScript
在CSS属性的基础上Sass提供了一些名为SassScript的新功能,SassScript可用作于任何属性,允许属性使用变量、算术运算等额外功能。
弱类型语言,对语法要求没那么严格。
1、注释
① Sass支持标准的CSS多行注释/* */,以及单行注释//,前者会被完整输出到编译后的CSS文件中,而后者不会。
② 将!作为多行注释的第一个字符表示在压缩输出模式下保留这条注释并输出到CSS文件中,通常用于添加版权信息。
③ 插值语句(interpolation)也可写进多行注释中输出变量值。
例如:
/*
hello
world!
*/
// compile scss files to css
// it's ready to do it.
$pink: #f3e1e1;
html{
background-color: $pink;
}
$author: 'gdream@126.com';
/*!
Author: #{$author}.
*/
开发模式编译后:
/*
hello
world!
*/
html{
background-color: #f3e1e1;
}
/*!
Author: 'gdream@126.com'.
*/
压缩输出模式编译后:
html{
background-color: #f3e1e1;
}
/*!
Author: 'gdream@126.com'.
*/
2、变量
(1)定义
变量以美元符号开头,赋值方法与CSS属性的写法一样
$width:1600px;
$pen-size:3em;
(2)使用
直接使用变量的名称即可调用变量
#app{
height:$width;
font-size:$pen-size;
}
(3)作用域
变量支持块级作用域,嵌套规则内定义的变量只能在嵌套规则内使用(局部变量),不能在嵌套规则内定义的变量则可在任何地方使用(全局变量)。将局部变量转换为全局变量可以添加!global声明。
#foo {
$width: 5em !global;
width: $width;
}
#bar {
width: $width;
}
编译后:
#foo {
width: 5em;
}
#bar {
width: 5em;
}
3、数据类型
SassScript支持7中主要的数据类型:
- 数字,
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($value)
(1)字符串(Strings)
SassScript支持CSS的两种字符串类型:有引号字符串(quoted strings),和无引号字符串(unquoted strings)。
// 注:在编译CSS文件时不会改变其类型。只有一种情况例外,使用`#{ }`(interpolation)时,有引号字符串将被编译为无引号字符串,这样便于在mixin中引用选择器名。
(2)数字(Numbers)
SassScript支持两种数字类型:带单位数字和不带单位数字(可正可负可为零可浮点)。
$my-age:19
$your-age:19.5;
$height:130px;
// 注:单位和数字当做一个整体,进行算数运算。
(3)空值(Null)
只有一个取值null。
$value:null;
// 注:由于它代表空,所以不能够使用它与任何类型进行算数运算。
(4)布尔型(Booleans)
只有两个取值:true和false。
$a:true;
$b:false;
// 注:只有自身是false和null才会返回false,其他一切都将返回true。
(5)数组(Lists)
通过空格或者逗号分隔的一系列的值。事实上,独立的值也被视为数组—只包含一个值的数组。索引从1开始。
$list0:1px 2px 5px 6px;
$list1:1px 2px,5px 6px;
$list2:(1px 2px) (5px 6px);
- 数组中可以包含子数组,比如1px 2px,5px 6px是包含1px 2px与5px 6px两个数组的数组。如果内外两层数组使用相同的分隔方式,需要用圆括号包裹内层,所以也可以写成(1px 2px)(5px 6px)。变化是,之前的1px 2px,5px 6px使用逗号分割了两个子数组(comma-separated),而(1px 2px)(5px 6px)则使用空格分割(space-separated)。
- 当数组被编译为CSS时,Sass不会添加任何圆括号(CSS中没有这种写法)所以(1px 2px)(5px 6px)与1px 2px,5px 6px在编译后的CSS文件中是完全一样的,但是它们在Sass文件中却有不同的意义,前者是包含两个数组的数组,而后河是包含四个值的数组。
- 用()表示不包含任何值的空数组(在Sass3.3版之后也视为空的map)。空数组不可以直接编译成CSS,比如编译font-family:()Sass将会报错。如果数组中包含空数组或空值,编译时将被清除,比如1px 2px ()3px或1px 2px null 3px。
- 基于逗号分隔的数组允许保留结尾的逗号,这样做的意义是强调数组的结构关系,尤其是需要声明只包含单个值的数组时。例如(1,)表示只包含1 的数组,而(1 2 3 ,)表示包含1 2 3 这个以空格分隔的数组的数组。
(6)映射(Maps)
Maps必须被圆括号包围,可以映射任何类型键值对(任何类型,包括内嵌maps,不过不推荐这种内嵌方式)。
$map:(
key1:value1,
key2:value2,
key3:value3
)
(7)颜色(Colors)
CSS原有颜色类型,十六进制、RGB、RGBA、HSL、HSLA和色彩单词。
SCSS提供了内置Colors函数,从而更方便地使用颜色。
$color:rgba(#f3e1e1, 0.3);
body {
color: $color;
}
编译后:
body {
color: rgba(243, 225, 225, 0.3);
}
4、运算
(1)数字运算符
SassScript支持数字的加减乘除、取整等运算(+,—,*,/,% ),如果必要会在不同单位间转换值,如果要保留运算符号,则应该使用插值语法。
① 加号(+)
// 纯数字
$add1:1+2; //3
$add2:1+2px; //3px
$add3:1px+2; //3px
$add4:1px+2px; //3px
// 纯字符串
$add1:“a”+“b”; //“ab”
$add2:“a”+b; //“ab”
$add3:a+“b”; //ab
$add4:a+b; //ab
// 数字和字符串
$add1:1+a; //1a
$add2:a+1; //a1
$add3:"1"+a; //"1a"
$add4:1+"a"; //"1a"
$add5:"a"+1; //"a1"
$add6:a+"1"; //a1
$add7:1+"1"; //"11"
总结:
1、纯数字:只要有单位,结果必有单位
2、纯字符串:第一个字符串有无引号决定结果是否有引号
3、数字和字符串:第一位有引号,结果必为引号;第一位对应数字非数字且最后一位带有引号,则结果必为引号。
② 减号(—)
$add1:1-2; //-1
$add2:1-2px; //-1px
$add3:1px-2; //-1px
$add4:1px-2px; //-1px
$sub1:a-1; //a-1
$sub2:1-a; //1-a
$sub3:“a”-1; //"a"-1
$sub4:a-"1"; //a-"1"
总结:
每个字段必须前部分为数字,且两个字段只能一个后部分是字符(因此此时后缀被当单位看待了)。只要其中一个值首位不为数字的,结果就按顺序去除空格后拼接起来。
③ 乘号(*)
$num1:1*2; //2
$num2:1*2px; //2px
$num3:1px*2; //2px
$num4:1px*2px; //编译不通过
$num5:1*2abc; //2abc
总结:
每个字段必须前部分为数字,且两个字段只能一个后部分是字符(因为此时后缀被当单位看待了)。其余编译不通过。
④ 除号(/)
总结:
1、不会四舍五入,精确到小数点后5位。
2、每个字段必须前部分为数字,且当前者只是单纯数字无单位时,后者(被除数)后部分不能有字符。其余结果就按顺序去除空格后拼接起来。(因为此时后缀被当单位看待了)
⑤ %
总结:
值与%之间必须要有空格,否则会被看作字符串。
(2)关系运算符
大前提:两端必须为数字或前部分数字后部分字符
返回值:true 或 false
- >
$a:1>2; //false
- <
$a:1<2; //true
- >=
$a:1>=2; //false
- <=
$a:1<=2; //true
(3)相等运算符
作用范围:相等运算==,!=可用于所有数据类型
返回值:true 或 false
$a:1==1px; //true
$b:“a”==a; //true
总结:
前部分为不带引号数字时,对比的仅仅是数字部分;
反之,忽略引号,要求字符一一对应。
(4)布尔运算符
SassScript支持布尔型的and or 以及 not 运算。
$a:1 > 0 and 0 >= 5 ; //false
总结:
值与“and”、“or”、“not”之间必须要有空格,否则会被看作字符串
(5)颜色值运算
颜色值的运算是分段计算进行的,也就是分别计算红色,绿色,以及蓝色的值
- 颜色值与颜色值
p {
color:#010203 + #040506;
}
// 计算01 + 04 = 05 02 + 05 = 07 03 + 06 = 09,然后编译为
// p {
color:#050709;
}
- 颜色值与数字
p {
color:#010203 * 2;
}
// 计算 01 * 2 = 02 02 * 2 = 04 03 * 2 = 06
// p {
color:#020406;
}
- RGB和HSL
// 如果颜色包含alpha channel (rgba或hsla两种颜色值),必须拥有相等的alpha值才能进行运算,因为算术运算不会作用域alpha值。
p {
color:rgba(255,0,0,0.75)+ rgba(0,255,0,0.75);
}
// p {
color:rgba(255,255,0,0.75);
}
(6)运算优先级
0. ()
1. * 、 /、 %
2. +、 —
3. >、<、>=、<=
5、嵌套语法
<div id="app">
<span>我喜欢你</span>
<div class="font">
<a href="#"></a>
</div>
</div>
#app {
span {
color: red;
}
;
.font {
a {
color: blue;
}
}
}
编译后:
#app span {
color: red;
}
#app .font a {
color: blue;
}
6、杂货语法
(1)插值语法
通过 #{ } 插值语句可以在选择器、属性名和属性值中使用变量。
但大多数情况下,这样使用属性值可能还不如直接使用变量方便,但是使用#{ }可以避免Sass运行运算表达式,直接编译CSS。
$name: foo;
$attr:border;
p.#{$name} {
#{$attr}-color: $name;
}
编译后:
p.foo {
border-color: foo;
}
(2)& in SassScript
&为父选择器
a {
color: yellow;
&:hover {
color: green;
}
&:active {
color: blank;
}
}
(3)!default
可以在变量的结尾添加!default 给一个未通过!default 声明赋值的变量赋值,此时,如果变量已经被赋值,不会再被重新赋值,但是如果变量还没有被赋值,则会被赋予新的值。
$content: "First content";
$content: "Second content?" !default;
$new_content: "First time reference" !default;
#main {
content: $content;
new-content: $new_content;
}
编译后:
#main {
content: "First content";
new-content: "First time reference";
}
注意:变量是null空值时将视为被!default赋值。
(4)!global
将局部变量提升为全局变量
(5)!optional
- 如果@extend失败会受到错误提示。比如,这样写 a.important {@extend .notice},当没有.notice选择器时,将会报错,只有h1.notice包含.notice时也会报错,因为h1与a冲突,会生成新的选择器。
- 如果要求@extend不生成新选择器,可以通过!optional声明达到这个目的。
简言之:当@extend相关代码出现语法错误时,编译器可以能会给我们“乱”编译为CSS,我们加上这个参数可以在出现问题后不让他编译该部分代码。
7、@-Rules与指令
(1)@import
Sass拓展了@import的功能,允许其导入SCSS或SASS文件。被导入的文件将合并编译到同一个CSS文件中,另外,被导入的文件中所包含的变量或者混合指令(mixin)都可以在导入的文件中使用。
通常,@import寻找Sass文件并将其导入,但在以下情况下,@import仅作为普通的CSS语句,不会导入任何Sass文件。
- 文件拓展名是.css;
- 文件名以http://开头;
- 文件名是url();
- @import包含media queries。
如果不在上述情况内,文件的拓展名是.scss或.sass,则导入成功,没有指定拓展名,Sass将会试着寻找文件名相同,拓展名为.scss或.sass的文件并将其导入。
@import "foo.scss”;
@import “bar”;
// 以上两种方式均可
// 以下方式均不可行
@import “foo.css”;
@import “foo” screen;
@import “https://foo.com/bar”;
@import url(foo);
Sass允许同时导入多个文件,例如同时导入rounded-corners与text-shadow两个文件:
@import "rounded-corners”, "text-shadow";
导入文件也可以使用 # { } 插值语句,但不是通过变量动态导入Sass文件,只能作用域CSS的url()导入方式:
$family:unquote(“Droid+Sans”);
@import url(“http://fonts.googleapis.com/css?family=\#{$family}”);
// 编译为:
@import url(“http://fonts.googleapis.com/css?family=\Droid+Sans");
如果你有一个SCSSS或Sass文件需要引入,但是又不希望它被编译为一个CSS文件,这时就可以在文件名前面加一个下划线,就能避免被编译。这将告诉Sass不要把它编译成CSS文件。然后,就可以像往常一样引入这个文件了,而且还可以省略掉文件名前面的下划线。
除此之外,还支持嵌套@import,但是不可以在混合指令(mixin)或控制指令(control directives)中嵌套@import。
(2)@media
Sass中的@media指令与CSS中用法一样,只是增加了一点额外的功能:允许其在CSS规则中嵌套。如果@media嵌套在CSS规则内二,编译时,@media将被编译到文件的最外层,包含嵌套的父选择器。这个功能让@media用起来更方便,不需要重复使用选择器,也不会打乱CSS的书写流程 。
.sidebar {
width: 300px;
@media screen and (orientation: landscape) {
width: 500px;
}
}
//编译为:
.sidebar {
width: 300px;
@media screen and (orientation: landscape) {
width: 500px;
}
}
@media的queries允许互相嵌套使用,编译时,Sass自动添加and
@media screen {
.sidebar {
@media (orientation: landscape) {
width: 500px;
}
}
}
//编译为:
@media screen and (orientation: landscape) {
.sidebar {
width: 500px; }
}
@media甚至可以使用SassScript(比如变量,函数,以及运算符)代替条件的名称或者值
media: screen;
$feature: -webkit-min-device-pixel-ratio;
$value: 1.5;
@media #{$media} and ($feature: $value) {
.sidebar {
width: 500px;
}
}
// 编译为:
@media screen and (-webkit-min-device-pixel-ratio: 1.5) {
.sidebar {
width: 500px;
}
}
(3)*@extend
@extend即继承。在设计网页的时候常常遇到这种情况:一个元素使用的样式与另一个元素完全相同,但又添加了额外的样式。
总的来看:支持层叠继承、多继承、允许延伸任何定义给单个元素的选择器(但是允许不一定好用)
① 基本延伸
.error {
border: 1px #f00;
background-color: #fdd;
}
.seriousError {
@ extend .error;
border-width: 3px;
}
//上面代码的意思是将.error下的所有样式继承给.seriousError
//border-width:3px;是单独给.seriousError设定特殊样式
//这样使用seriousError的地方可以不再使用.error
@extend的作用是将重复使用的样式(.error)延伸(extend)给需要包含这个样式的特殊样式(.seriousError)
注意理解一下情况:
.error {
border: 1px #f00;
background-color: #fdd;
}
.error.intrusion {
background-image: url("/image/hacked.png");
}
.seriousError {
@extend .error;
border-width: 3px;
}
// .error, .seriousError {
border: 1px #f00;
background-color: #fdd; }
.error.intrusion, .seriousError.intrusion {
background-image: url("/image/hacked.png"); }
.seriousError {
border-width: 3px; }
当合并选择器时,@extend会很聪明的避免无所谓的重复,.seriousError.seriousError将编译为.seriousError,不能匹配任何元素的选择器也会删除。
② 延伸复杂的选择器:
Class选择器并不是唯一可以延伸(extend)的,Sass允许延伸任何定义给单个元素的选择器,比如.special.cool,a:hover或者a.user[href^=http://"]等。
③ 多重延伸:
同一个选择器可以延伸给多个选择器,它所包含的属性将继承给所有被延伸的选择器
④ 继续延伸:
当一个选择器延伸给第二个后,可以继续将第二个选择器延伸给第三个
⑤ *选择器列:
暂时不可以将选择器列(Selector Sequence),比如.foo .bar或.foo + .bar,延伸给其他元素,但是,却可以将其他元素延伸给选择器列。
尽量不使用合并选择器列,因为如果凭个人推理的话,会出现排列组合的情况,所以SASS编译器只会保留有用的组合形式,但依旧会存在排列组合的情况,有可能会留下隐患。
a、当两个列合并时,如果没有包含相同的选择器,将生成两个新选择器:第一列出现在第二列之前,或者第二列出现在第一列之前
#admin .tabbar a {
font-weight: bold;
}
#demo .overview .fakelink {
@extend a;
}
// 编译为:
#admin .tabbar a,
#admin .tabbar #demo .overview .fakelink,
#demo .overview #admin .tabbar .fakelink {
font-weight: bold;
}
b、如果两个列包含了相同的选择器,相同部分将会合并在一起,其他部分交替输出
#admin .tabbar a {
font-weight: bold;
}
#admin .overview .fakelink {
@extend a;
}
// 编译为
#admin .tabbar a,
#admin .tabbar .overview .fakelink,
#admin .overview .tabbar .fakelink {
font-weight: bold;
}
⑥ 在指令中延伸:
在指令汇中使用@extend时(比如在@media中)有一些限制:Sass不可以将@media层外的CSS规则延伸给指令层内的CSS。
⑦ %placeholder为选择器占位符,配合@extend-Only选择器使用
效果:只定义了样式,但不会对原有选择器匹配的元素生效
// example1:
%img {
color: red;
}
.path{
@extend %img;
}
// 编译后:
.path {
color: red;
}
// example2:
#context a%extreme {
color: blue;
font-weight: bold;
font-size: 2em;
}
// 编译后:
.notice {
@extend %extreme;
}
// 注:必须是"."和"#"选择器
(4)*@at-root
@at-root指令使一个或者多个规则在文档的根发出,而不是嵌套在其父选择器下。它可以与单个内联选择器一起使用。
且@at-root使多个规则跳出嵌套
@at-root默认情况下并不能使规则或者选择器跳出指令,通过使用without和with可以解决该问题
(5)@debug
用于调试,按标准错误输出流输出
$size: 9px;
.file{
@debug $size;
}
(6)@warn
用于警告,按标准错误输出流输出
(7)@error
用于报错,按标准错误输出流输出
序列 | @-rules | 作用 |
1 | @import | 导入sass或scss文件 |
2 | @media | 用于将样式规则设置为不同的媒体类型 |
3 | @extend | 以继承的方式共享选择器 |
4 | @at-root | 转到根节点 |
5 | @debug | 用于调试,按标准错误输出流输出 |
6 | @warn | 用于警告,按标准错误输出流输出 |
7 | @error | 用于报错,按标准错误输出流输出 |
8、控制指令
(1)if()
三元运算符
表达式:if(expression,value1,value2)
p {
color: if(1 + 1 = 2, green, yellow);
}
// 编译后:
p {
color: green;
}
(2)@if()
条件语句
- 当@if()的表达式返回值不是false或者null时,条件成立,输出{ }内的代码。
- @if声明后面可以跟多个@else if 声明,或者一个@else 声明。如果@if 声明失败,Sass将逐条执行@else if 声明,如果全部失败,最后执行@else声明。
a、单@if
p {
@if 1 + 1 == 2 {
color: red;
}
}
//编译后:
p {
color: red;
}
b、@if-@else
p {
@if 1 + 1 != 2 {
color: red;
} @else {
color: blue;
}
}
// 编译后:
p {
color: blue;
}
c、@if-@else if -@else
$age: 19;
p {
@if $age == 18 {
color: red;
} @else if $age == 19 {
color: blue;
} @else {
color: green;
}
}
// 编译后:
p {
color: blue;
}
(3)@for
循环语句
表达式:@for $var from <start> through <end> 或 @for $var from <start> to <end>
through和to的相同点与不同点:
- 相同点:两者均包含的值
- 不同点:through包含的值,但to不包含的值
@for $i from 1 through 3 {
.item-#{$i} {
width: 2em * $i;
}
}
// 编译后:
.item-1 {
width: 2em;
}
.item-2 {
width: 4em;
}
.item-3 {
width: 6em;
}
(4)@while
循环语句
表达式:@while expression
@while 指令重复输出格式知道表达式返回结果为false。这样可以实现比@for更复杂的循环,只是很少会用到。
$i: 6;
@while $i > 0 {
.item-#{$i} {
width: 2em * $i;
}
$i: $i - 2;
}
// 编译后:
.item-6 {
width: 12em;
}
.item-4 {
width: 8em;
}
.item-2 {
width: 4em;
}
(5)@each
循环语句
表达式:$var in $vars
$var可以是任何变量名
$vars只能是Lists或者Maps
a、一维列表
@each $animal in puma, sea-slug, egret, salamander {
.#{$animal}-icon {
background-image: url('/images/#{$animal}.png');
}
}
// 编译后:
.puma-icon {
background-image: url('/images/puma.png'); }
.sea-slug-icon {
background-image: url('/images/sea-slug.png'); }
.egret-icon {
background-image: url('/images/egret.png'); }
.salamander-icon {
background-image: url('/images/salamander.png'); }
b、二维列表
@each $animal, $color, $cursor in (puma, black, default),
(sea-slug, blue, pointer),
(egret, white, move) {
.#{$animal}-icon {
background-image: url('/images/#{$animal}.png');
border: 2px solid $color;
cursor: $cursor;
}
}
// 编译后:
.puma-icon {
background-image: url('/images/puma.png');
border: 2px solid black;
cursor: default; }
.sea-slug-icon {
background-image: url('/images/sea-slug.png');
border: 2px solid blue;
cursor: pointer; }
.egret-icon {
background-image: url('/images/egret.png');
border: 2px solid white;
cursor: move; }
c、Maps
@each $header, $size in (h1: 2em, h2: 1.5em, h3: 1.2em) {
#{$header} {
font-size: $size;
}
}
//编译后:
h1 {
font-size: 2em; }
h2 {
font-size: 1.5em; }
h3 {
font-size: 1.2em; }
9、混合指令
混合指令(Mixin)用于定义可重复使用的样式,避免了使用无语义的class。比如.float-left。混合指令可以包含所有的CSS规则,绝大部分Sass规则,甚至通过参数功能引入变量,输出多样化的样式。
注意:这不是函数!没有返回值!
(1)定义混合指令
混合指令的用法是在@mixin后添加名称与样式,以及需要的参数(可选)。
// 格式:
@mixin name {
// 样式...
}
@mixin large-text {
font: {
family: Arial;
size: 20px;
weight: bold;
}
color: #ff0000;
}
(2)引用混合样式
使用@include指令引用混合样式,格式是在其后添加混合名称,以及需要的参数(可选)。
// 格式
@include name;
// 注:无参数或参数都有默认值时,带不带括号都可以。
p {
@include large-text;
}
// 编译后:
p {
font-family: Arial;
font-size: 20px;
font-weight: bold;
color: #ff0000;
}
(3)参数
格式:按照变量的格式,通过逗号分隔,将参数写进Mixin名称后的圆括号里
支持默认值:支持多参数;支持不定参数;支持位置传参和关键词传参
a、位置传参
@mixin mp($width) {
margin: $width;
}
body {
@include mp(300px);
}
b、关键词传参
@mixin mp($width) {
margin: $width;
}
body {
@include mp($width: 300px);
}
c、参数默认值
@mixin mp($width: 500px) {
margin: $width;
}
body {
@include mp($width: 300px);
// or
@include mp(300px);
}
d、不定参数
官方:Variable Arguments
译文:参数变量
有时,不能确定混合指令需要使用多少参数。这时,可以使用参数变量_声明(写在参数的最后方)告诉Sass将这些参数视为值列表处理。
@mixin mar($value...) {
margin: $value;
}
(4)向混合样式中导入内容
在引用混合样式的时候,可以先将一段代码导入到混合指令中,然后再输出混合样式,额外导入的部分将出现在@content标志的地方。
可以看作参数的升级版
@mixin example {
html {
@content;
}
}
@include example{
background-color: red;
.logo {
width: 600px;
}
}
// 编译后:
html {
background-color: red;
}
html .logo {
width: 600px;
}
10、函数指令
(1)内置函数
a、字符串函数
索引第一个为1,最后一个为-1;切片两边均为闭区间
函数名和参数类型 | 函数作用 |
quote($string) | 添加引号 |
unquote($string) | 除去引号 |
to-lower-case($string) | 变为小写 |
to-upper-case($string) | 变为大写 |
str-length($string) | 返回$string的长度(汉字算一个) |
str-index($string,$subtring) | 返回$substring在$string的位置 |
str-inset($string,$subtring,$index) | 在$string的$index处插入$insert |
str-slice($string,$start-at,$end-at) | 截取$string的$start-at和$end-at之间的字符串 |
b、数字函数
函数名和参数类型 | 函数作用 |
percentage($number) | 转换为百分比形式 |
round($number) | 四舍五入为整数 |
ceil($number) | 数值向上取整 |
floor($number) | 数值向下取整 |
abs($number) | 获取绝对值 |
min($number...) | 获取最小值 |
max($number...) | 获取最大值 |
random($number?:number) | 不传入值:获得0-1的随机数;传入正整数n:获得0-n的随机整数(左开右闭) |
c、数组函数
函数名和参数类型 | 函数作用 |
length($list) | 获取数组长度 |
nth($list,n) | 获取指定下标的元素 |
set-nth($list,$n,$value) | 向$list的$n处插入$vaule |
join($list1, $list2, $separator) | 拼接$list1和list2;$separator为新list的分隔符,默认为auto,可选择comma、space |
append($list, $val, $separator) | 向$list的末尾添加$val;$separator为新list的分隔符,默认为auto,可选择comma、space |
index($list, $value) | 返回$value值在$list中的索引值 |
zip($lists…) | 将几个列表结合成一个多维的列表;要求每个的列表个数值必须是相同的 |
d、映射函数
函数名和参数类型 | 函数作用 |
map-get($map, $key) | 获取$map中$key对应的$value |
map-merge($map1, $map2) | 合并$map1和$map2,返回一个新$map |
map-remove($map, $key) | 从$map中删除$key,返回一个新$map |
map-keys($map) | 返回$map所有的$key |
map-values($map) | 返回$map所有的$value |
map-has-key($map, $key) | 判断$map中是否存在$key,返回对应的布尔值 |
keywords($args) | 返回一个函数的参数,并可以动态修改其值 |
e、颜色函数
- RGB函数
函数名和参数类型 | 函数作用 |
rgb($red, $green, $blue) | 返回一个16进制颜色值 |
rgba($red,$green,$blue,$alpha) | 返回一个rgba;$red,$green和$blue可被当作一个整体以颜色单词、hsl、rgb或16进制形式传入 |
red($color) | 从$color中获取其中红色值 |
green($color) | 从$color中获取其中绿色值 |
blue($color) | 从$color中获取其中蓝色值 |
mix($color1,$color2,$weight?) | 按照$weight比例,将$color1和$color2混合为一个新 |
- HSL函数
函数名和参数类型 | 函数作用 |
hsl($hue,$saturation,$lightness) | 通过色相(hue)、饱和度(saturation)和亮度(lightness)的值创建一个颜色 |
hsla($hue,$saturation,$lightness,$alpha) | 通过色相(hue)、饱和度(saturation)、亮度(lightness)和透明(alpha)的值创建一个颜色 |
saturation($color) | 从一个颜色中获取饱和度(saturation)值 |
lightness($color) | 从一个颜色中获取亮度(lightness)值 |
adjust-hue($color,$degrees) | 通过改变一个颜色的色相值,创建一个新的颜色 |
lighten($color,$amount) | 通过改变颜色的亮度值,让颜色变亮,创建一个新的颜色 |
darken($color,$amount) | 通过改变颜色的亮度值,让颜色变暗,创建一个新的颜色 |
hue($color) | 从一个颜色中获取亮度色相(hue)值 |
- Opacity函数
函数名和参数类型 | 函数作用 |
alpha($color)/opacity($color) | 获取颜色透明度值 |
rgba($color,$alpha) | 改变颜色的透明度 |
opacify($color, $amount) / fade-in($color, $amount) | 使颜色更不透明 |
transparentize($color, $amount) / fade-out($color, $amount) | 使颜色更加透明 |
f、Introspection函数
函数名和参数类型 | 函数作用 |
type-of($value) | 返回$value的类型 |
unit($number) | 返回$number的单位 |
unitless($number) | 判断$number是否带单位,返回对应的布尔值 |
comparable($number1, $number2) | 判断$number1和$number2是否可以做加、减和合并,返回对应的布尔值 |
(2)自定义函数
Sass支持自定义函数,并能在任何属性值或SassScript中使用
Params:与Mixin一致
支持返回值
基本格式:
@function fn-name($params...) { @return $params; }
@function fn-name($params...) {
@return nth($params, 1);
}
p {
height: fn-name(1px);
}
// 编译后:
p {
height: 1px;
}
11、细节与展望
(1)细节
a.@extend、@Mixin和@function的选择
minxins在网络传输中比@extend拥有更好的性能,尽管有些文件压缩时更大,但使用gzip压缩后,依然可以保证我们拥有更好的性能。
所以@extend尽量就不要使用了,而@Mixin和@function的差别在定义和使用上。
定义方式不同:@function需要调用@return输出结果。而@mixin则不需要。
使用方式不同:@mixin使用@include引用,而@function使用小括号执行函数。
(2)展望
以上内容算是“基础”部分,但是对于日常开发,是足够使用了。
如果想要进一步了解,就必须先去学习Ruby,使用Ruby相关模块进行更丰富的学习。