目前公司多端项目开发中使用的 js/css文件结构如下:
如果你也是第一次接触这种,你会好奇的发现它的.css文件命名方式有点不同,要想搞清楚这个命名,主要了解两个东西,一个是 CSS Modules, 通过该链接我们了解到 CSS Modules
就是以模块化的方式来管理 CSS
,它可以避免 CSS
样式全局污染的问题,因为使用CSS Module
编译后的class
类名会变成一个唯一的字符串, 它是采用 css-loader
默认的哈希算法[hash:base64]
来生成的唯一值。另一个需要了解的就是 .scss
,它是什么后缀呢,搜索一下就知道它是 Sass 格式的后缀,本文主要记录一下Sass的入门知识。
Sass
的缩排语法,对于写惯css
前端的web
开发者来说很不直观,也不能将css
代码加入到Sass
里面,因此Sass
语法进行了改良,Sass 3
就变成了Scss(Sassy CSS)
。SCSS
是CSS
语法的扩展。即每一个有效的CSS
也是一个有效的SCSS
语句,与原来的语法兼容,只是用{}
取代了原来的缩进。因此我们有时看到的是
.sass
有时是.scss
, 其实它俩是一样的,只不过一个是SASS
的后缀, 一个是SCSS
的后缀,都是同一个东西,区别有点像iPhone和iPhone Plus。
主要是为了 提高开发效率 和 提高代码可维护性!在大型的 web 应用开发中我们一般会编写大量的样式代码,Sass 在 CSS 的基础上提供了变量、嵌套 (nesting)、混合 (mixins) 、函数、指令等功能,使得我们可以更高效地编写样式,同时你还可以像编写 JS 一样来灵活地控制你的样式代码,这给 CSS 的开发带来了极大的便利!
首先要知道两个类库: node-sass
和 dart-sass
,这两个都是Sass
的实现 ,本身 Sass
是使用 Ruby
语言写的,但是它提供了很多接口以方便其他语言来集成和封装,node-sass
和 dart-sass
就是基于 LibSass
( Sass 的 C 版本) 封装而来的。
它们和 LibSass 的关系就是橘子和橘子汁的关系:
由于很少有人用dart
来开发前端项目,所以前端一般都是用 node-sass
这个库
安装 node-sass
一般使用 npm 或者 yarn 来安装:npm install node-sass
安装过程会去下载,如果下载失败,可能需要配置 npm 的源为淘宝镜像:
npm install -g mirror-config-china --registry=http://registry.npm.taobao.org
前端的项目是使用 Webpack 来构建,那么我们还需要使用 sass-loader
来编译项目中的 Sass ,所以我们需要在 Webpack 的配置中配置 sass-loader
,配置如下:
// webpack.config.js
module.exports = {
...
module: {
rules: [{
test: /\.scss$/,
use: [{
loader: "style-loader" // 将 JS 字符串生成为 style 节点
}, {
loader: "css-loader" // 将 CSS 转化成 CommonJS 模块
}, {
loader: "sass-loader" // 将 Sass 编译成 CSS
}]
}]
}
};
执行如下命令安装 sass-loader :
npm install sass-loader --save-dev
Sass使得你可以在父选择器的样式中直接编写子元素的样式,然后在一个子元素的样式中再去编写孙元素的样式,可以一层一层的嵌套着去写样式。
用编写一个导航的样式来举例,假定我们的导航 nav 下面有 ul 标签,ul 标签下又有 li 标签,li 标签下呢又有 a 标签,下面我使用 Sass 来处理导航中的样式:
nav {
width:200px;
background:white;
ul {
width:100%;
background:red;
li {
width:100%;
background:blue;
a {
color:green;
font-size:20px;
}
}
}
}
由于Sass编译后会转换生成CSS,可以通过这个网站 在线Sass转CSS 来在线查看转换后的结果。
上面的Sass 代码最终转换 CSS 代码如下:
nav {
width: 200px;
background: white;
}
nav ul {
width: 100%;
background: red;
}
nav ul li {
width: 100%;
background: blue;
}
nav ul li a {
color: green;
font-size: 20px;
}
写起来是不是方便很多,但要注意:嵌套的越深,那么编译生成的 CSS 的语句就越多,同时消耗的资源也会越多。
由逗号分隔的选择器列表会被 Sass 组合到一个选择器列表中:
.alert, .warning {
ul, p {
margin-right: 0;
margin-left: 0;
padding-bottom: 0;
}
}
转换后的CSS:
.alert ul, .alert p, .warning ul, .warning p {
margin-right: 0;
margin-left: 0;
padding-bottom: 0;
}
嵌套使用带有选择符的选择器,我们可以将选择符放在外部选择器的末尾,或者内部选择器的开始位置:
ul > {
li {
list-style-type: none;
}
}
h2 {
+ p {
border-top: 1px solid gray;
}
}
p {
~ {
span {
opacity: 0.8;
}
}
}
转换后的CSS:
ul > li {
list-style-type: none;
}
h2 + p {
border-top: 1px solid gray;
}
p ~ span {
opacity: 0.8;
}
当你使用嵌套的时候,可能你会需要使用到嵌套外层的父选择器,比如为一个元素 添加伪类 (hover、active、before、after) 的时候,可以用 & 代表嵌套规则外层的父选择器。
a {
&:hover {
color:red;
}
&:active {
color:blue;
}
&:before {
content:'';
}
&:after {
content:'';
}
span {
&:hover {
color:green;
}
}
}
转换后的CSS:
a:hover {
color: red;
}
a:active {
color: blue;
}
a:before {
content: "";
}
a:after {
content: "";
}
a span:hover {
color: green;
}
向外部选择器添加后缀还是使用 & 符号
.box {
width:100px;
&-head {
width:100%;
&-title {
color:red;
}
}
&-body {
width:100%;
}
&-footer {
width:100%;
}
}
转换后的CSS:
.box {
width: 100px;
}
.box-head {
width: 100%;
}
.box-head-title {
color: red;
}
.box-body {
width: 100%;
}
.box-footer {
width: 100%;
}
在 Sass 中占位符以 % 开头,必须通过 @extend
指令调用,如果单独使用的话是不会编译到 CSS 中的,@extend 指令后面会介绍。
%placeholder {
width:100px;
height:100px;
color:red;
&:hover {
color:blue;
}
}
.btn {
@extend %placeholder;
font-size: 18px;
}
.btn2 {
@extend %placeholder;
font-size: 16px;
}
转换后的CSS:
.btn2, .btn {
width: 100px;
height: 100px;
color: red;
}
.btn2:hover, .btn:hover {
color: blue;
}
.btn {
font-size: 18px;
}
.btn2 {
font-size: 16px;
}
属性嵌套指是 CSS 属性具有相同的命名空间 (namespace),比如定义字体样式的属性: font-size ; font-weight ; font-family
; 具有相同的前缀 font
,再比如定义边框样式的属性:border-radius ; border-color
; 具有相同的前缀 border
等等。
Sass 允许将属性嵌套在命名空间中,同时命名空间也可以具有自己的属性值
.box {
border: {
radius: 5px;
color:red;
}
font: {
family:'YaHei';
size:18px;
weight:600;
}
margin: auto {
bottom: 10px;
top: 10px;
};
}
转换后的CSS:
.box {
border-radius: 5px;
border-color: red;
font-family: "YaHei";
font-size: 18px;
font-weight: 600;
margin: auto;
margin-bottom: 10px;
margin-top: 10px;
}
Sass中可以定义变量来表示属性值,以便提高复用,方便修改。
举个例子,假如我们项目中很多地方要设置一个字体颜色为红色,那么我们完全可以把这个颜色抽出来作为一个变量,然后在所有需要设置字体颜色的地方引用这个变量。这样有一个好处就是,假如产品大大说要修改所有字体颜色的时候,我们就不需要每处都去修改了,直接更改变量的值就 OK 了。
定义变量以 $
开头: $variable
$variable: red;
.title {
color: $variable;
}
h1 {
color: $variable;
}
转换后的CSS:
.title {
color: red;
}
h1 {
color: red;
}
Sass 变量的值,支持原来任何 CSS 的属性值都可以作为 Sass 变量的值
$font-family: "YaHei"、"Myriad Pro"; // 字体的属性值
$color: red; // 颜色的属性值
$width: 20px; // 宽度的属性值
$border: 1px solid #000000; // border的属性值
$use-flex-grow: 1; // flex-grow的属性值
变量值的类型可以是:
没有什么特殊要求,只要是语义化,方便理解就行,如定义变量名为 $theme-color
,页面中的主要边框颜色,定义为 $main-border-color
等等,也可以根据公司团队的规范要求。
在 Sass 中,使用中划线 “-” 和下划线 “_” 这两种方式是兼容的,也就是说你用中划线声明的变量,也可以使用下划线去引用,比如我定义了变量 $theme-color
,我在引用的时候也可以写成 $theme_color
。
$main-bg-color: blue;
$main-border: 1px solid #cccccc;
$main-font-size: 18px;
$error-text-color: red;
$body-color: $main-bg-color;
body {
background-color:$body-color;
}
.content {
font-size:$main-font-size;
background-color:$main-bg-color;
border:$main-border;
}
.error {
font-size:$main-font-size;
color:$error-text-color;
}
$body-color 这个变量,可以发现,在声明变量时,变量的值也可以引用其他变量
转换后的CSS:
body {
background-color: blue;
}
.content {
font-size: 18px;
background-color: blue;
border: 1px solid #cccccc;
}
.error {
font-size: 18px;
color: red;
}
与JS一样,变量作用域也分为全局和局部,在局部作用域当中,即便同名,全局变量也不受影响
$main-color: red;
h1 {
$main-color: green; // 局部变量
color:$main-color;
}
h2 {
color:$main-color;
}
转换后的CSS:
h1 {
color: green;
}
h2 {
color: red;
}
如果局部的变量想修改或覆盖全局变量,使用 !global 标识符:
$main-color: red;
h1 {
$main-color: green!global;
color:$main-color;
}
h2 {
color:$main-color;
}
这样编译之后两个都会是green
一般来说我们反复的声明一个重名变量,那么最后一个声明的变量值会覆盖上面所有的,比如像下面这样:
$main-color: red;
$main-color: green;
h1 {
color:$main-color;
}
最后编译的时候会使用最后一次声明的变量值,也就是 green , 但是有一种情况:在实际的项目开发中,假如需要你来写一段公共的 Sass 代码给其他开发者使用,那么如果你的代码中声明了 $main-color 这个变量,那么其他开发者在自己页面也声明了 $main-color 这个变量,并且他是在导入你的这段代码之前声明的,那么他的就会被覆盖掉,这是不行的!
可以使用 !default 标识符来解决:
$main-color: red; // 假如这个是其他开发者自己声明的
$main-color: green!default; // 假如这个是你的代码片段声明的
h1 {
color:$main-color;
}
转换后的CSS:
h1 {
color: red;
}
如果其他开发者没有声明这个变量,就会使用 green 这个用户自己定义的变量值。
实际项目中会抽取一般都会抽离出 1~n 个文件来专门声明 Sass 变量(抽离出几个文件视项目大小而定)
我们一般会在 styles 目录下新建一个 variables.scss 文件来管理声明的全局变量
在 Sass 中,数字类型支持普通数字,科学计数法,还支持带单位的写法,如 8px 这种,即 Number 类型可能有单位也可能没有单位,而且这是非常常用的。
$main-height: 80px; // 带有单位的 Number 类型
$main-flex-grow: 1; // 不带单位的 Number 类型
$main-num: 5e3; // 使用科学计数法的数字
$main-max-height: 2 * 80px; // 运算
.box {
height: $main-height;
flex-grow: $main-flex-grow;
width: $main-num;
max-height: $main-max-height;
}
转换后的CSS:
.box {
height: 80px;
flex-grow: 1;
width: 5000;
max-height: 160px;
}
Boolean 类型无非就两个值,true 和 false ,当然除了直接写的 true 和 false 外,也可以是一些等式、关系运算、或内置函数的结果,不过这些结果最终还是 true 或 false 。一般来说 Boolean 类型都会结合 Sass 判断或者函数来使用,真正直接写在样式中基本是没有的,所以这里你只要知道这个类型就可以。
在 Sass 中支持 带引号 和 不带引号 两种方式的字符串,比如 “a” 或者 a ,还支持转义符 **
$string-one: 'Yahei'; // 带引号的字符串
$string-two: Yahei; // 不带引号的字符串
$string-three: '\"yahei'; // 使用转义符的字符串
.box {
font:$string-one;
font-family: $string-two;
font: $string-three;
}
转换后的CSS:
.box {
font: "Yahei";
font-family: Yahei;
font: '"yahei';
}
$color-one: #ffffff;
$color-two: red;
$color-three: rgb(204, 102, 153);
$color-four: rgba(107, 113, 127, 0.8);
.box {
color: $color-one;
background-color: $color-two;
border-color: $color-three;
color: $color-four;
}
转换后的CSS:
.box {
color: #ffffff;
background-color: red;
border-color: #cc6699;
color: rgba(107, 113, 127, 0.8);
}
Lists 类型就是数组,列表中包含一系列的值,在 Sass 中列表的元素可以使用逗号或者空格来分隔
$font-list: 'Georgia','Serif'; // 通过逗号分隔元素
$border-list: 1px 2px 3px 4px; // 通过空格分隔元素
$padding-list: 3px,3px 4px 4px; // 混用(不建议)
$textStyleMap: (
'font-family': 'Georgia',
'font-weight': 600,
'font-size': 18px,
'text-align': center
);
p {
font-family: map-get($textStyleMap, 'font-family');
font-weight: map-get($textStyleMap, 'font-weight');
font-size: map-get($textStyleMap, 'font-size');
text-align: map-get($textStyleMap, 'text-align');
}
转换后的CSS:
p {
font-family: "Georgia";
font-weight: 600;
font-size: 18px;
text-align: center;
}
在 Sass 中它表示缺少值,通常由函数返回。如果说在列表中有 null ,那么在生成 CSS 的时候会忽略该空值。
小结:
p {
width: 10px + 20px; // 加法运算 (不能使用不兼容的单位)
height: 500px +50; // 加法运算无单位的数字可以与有单位的一起使用
max-width: 800px - 100px; // 减法
max-height: 400px * 2; // 乘法,一个数值带单位即可
font-size: 30px % 4; // 模运算
}
转换后的CSS:
p {
width: 30px;
height: 550px;
max-width: 700px;
max-height: 800px;
font-size: 2px;
}
需要注意的地方:
上面最后一条,是因为减法运算符 - 不仅仅表示减法,还能表示负数
例如:
p {
width: 10px - 5px; // 前后都有空格
width: 10px-5px; // 前后都没有空格
width:10px -5px; // 只有前面有空格
}
转换后的CSS:
p {
width: 5px;
width: 5px;
width: 10px -5px;
}
跟通常意义上的四则运算中的圆括号一样,可以来控制运算顺序,Sass里一般除法中比较有用。
在 CSS 中,你要知道 / 这个标识符并不是代表除法的,一些 CSS 的属性值是支持使用 / 来分隔的,所以在 Sass 中直接使用 / 也是会当成分隔符来处理。但是呢,在以下情况下,Sass 将会把 / 视为除法运算:
$one: 20px / 2;
$two: 10px;
p {
width: 200px + 100px / 10; // 值是另外一个运算表达式的一部分
font-size: $one; // 前后的值存储在变量中或由函数返回
border-width: $two / 5; // 前后的值存储在变量中或由函数返回
height: (800px / 2); // 被圆括号所包裹
max-width: 800px / 2; // 会被当作分隔符来处理,而不是除法运算
}
转换后的CSS:
p {
width: 210px;
font-size: 10px;
border-width: 2px;
height: 400px;
max-width: 800px/2;
}
还有一种情况是:假如我在两个变量之间使用 /
标识符,而且我又不想对这两个变量进行除法运算,我只是想对这两个变量的值进行分隔而已,那该怎么办呢?那我们需要使用插值 #{}
来将两个变量包裹住即可:
$one: 20px;
$two: 10;
p {
width: $one / $two; // 没有使用插值,会对变量值进行除法运算
height: #{$one} / #{$two}; // 使用插值,不会进行除法运算
}
转换后的CSS:
p {
width: 2px;
height: 20px/10;
}
很少直接用,看例子:
p {
width: 10px > 5px; // 大于
width: 10 < 5px; // 小于
width: 10 >= 5; // 大于等于
width: 5 <= 5; // 小于等于
width: 5 == 5; // 等于
}
转换后的CSS:
p {
width: true;
width: false;
width: true;
width: true;
width: true;
}
在 Sass 中使用相等运算符去做比较的时候,对于数字类型,数字具有相同的值和相同的单位,或者在单位之间转换时它们的值相等,则它们是相等的;对于字符串类型,具有相同内容的未加引号和带引号的字符串被认为是相等的;对于颜色类型,具有相同的红色、绿色、蓝色和alpha值,则颜色是相等的。
很少用
body {
color: #020304 + #050203;
}
转换后的CSS:
body {
color: #070507;
}
其实是分段计算的,也就是 02 + 05 、03 + 02 、04 + 03
在 Sass 中字符串运算规则:
其实只有第一种 + 运算是真正的运算,/ 和 - 只不过是拼接到一起而已。
p {
color: r + 'ed'; // 带引号的在加号右侧,返回一个不带引号的字符串
color: 'r' + ed; // 带引号的在加号左侧,返回一个带引号的字符串
color:r + ed; // 返回一个不带引号的字符串
color: r/ed; // 返回一个使用 / 分隔的字符串
color: r-ed; // 返回一个使用 - 分隔的字符串
}
转换后的CSS:
p {
color: red;
color: "red";
color: red;
color: r/ed;
color: r-ed;
}
很少用
{
a: true and true;
b: true or false;
c: true and false;
d: not false;
}
转换后的CSS:
{
a: true;
b: true;
c: false;
d: true;
}
实战应用:
我们在做 rem 布局的时候经常会设置一个根元素的字体大小,然后其余所有的像素可能都根据这个去计算,所以为了便于维护,把这个根元素的大小抽离出来作为一个变量,然后在每个元素的样式中对这个变量进行运算就可以了,同时我们还可以在动画中运用一些运算
$root: 28;
html {
font-size: $root+px;
}
p {
width: (460rem / $root);
height: (320rem / $root);
}
@keyframes sacle {
0% {
width: (800px - $root);
}
50% {
width: 800px - $root * 2;
}
100% {
width: (800px / $root);
}
}
转换后的CSS:
html {
font-size: 28px;
}
p {
width: 16.4285714286rem;
height: 11.4285714286rem;
}
@keyframes sacle {
0% {
width: 772px;
}
50% {
width: 744px;
}
100% {
width: 28.5714285714px;
}
}
在项目中,可以把 $root 这个变量抽出来到专门维护变量的文件中,然后供项目中所有的页面做运算使用。
插值指在特定的区域插入一段表达式或者一个变量,以此来实现内容动态变换的需求, 语法:#{$name}
,其中$name
是一个变量。其实有点像 ES6的字符串模板功能。
$name: item;
.ul-#{$name} { // 使用插值
width: 200px;
.li-#{$name} { // 使用插值
width: 100%;
}
}
.box-#{$name} { // 使用插值
height:100px;
.#{$name} { // 使用插值
height:100%;
}
}
转换后的CSS:
.ul-item {
width: 200px;
}
.ul-item .li-item {
width: 100%;
}
.box-item {
height: 100px;
}
.box-item .item {
height: 100%;
}
这样改名字的时候就方便了,只需要修改插值的名字,不用一个一个的去改了。。。
$name: color;
$position: top;
body {
background-#{$name}: red;
border-#{$name}: blue;
padding-#{$position}: 5px;
margin-#{$position}: 10px;
#{$position}: 20px;
}
转换后的CSS:
body {
background-color: red;
border-color: blue;
padding-top: 5px;
margin-top: 10px;
top: 20px;
}
$one: 20px;
$two: 2;
$family: "UaTy";
div {
margin: $one / $two; // 除法运算
margin: #{$one} / #{$two}; // 分隔
font-family: "MyFo #{$family}"; // 带引号的字符串会转换为不带引号
width: calc(100% - $one * 2 *$two); // calc函数中内容会被当作字符串处理
width: calc(100% - #{$one * 2 *$two}); // calc函数中插值的内容会进行运算
}
转换后的CSS:
div {
margin: 10px;
margin: 20px/2;
font-family: "MyFo UaTy";
background-image: url(http://xxx.xxx.xxx/a.jpg);
width: calc(100% - $one * 2 *$two);
width: calc(100% - 80px);
}
需要注意的是,我们对两个变量使用 / 标识符的时候,如果你不想对这两个变量进行除法运算而是进行分隔,那么就可以使用插值避免运算。
不举例了,谁会在注释中使用这个。。。想不通
我们先来看一段 Sass 函数的代码来直观感受一下:
$list: [1,2,4,5];
$string: 'string';
$substring: 'str';
.box {
font-size:length($list); // 列表函数
font: quote($string); // 字符串函数
font: str-index($string, $substring); // 字符串函数
color: adjust-hue(#6b717f, 60deg); // 颜色函数
border-width: ceil(4.2); // 数字函数
width: percentage(.7); // 数字函数
font: type-of(#676767); // Introspection函数
}
转换后的CSS:
.box {
font-size: 4;
font: "string";
font: 1;
color: #796b7f;
border-width: 5;
width: 70%;
font: color;
}
在实际开发中并不会这么写,这里把它们作为属性值只是为了直观的展示。
string.quote(aaa) //=> "aaa" 加引号
unquote("bbb") //=> bbb 去引号
str-index("abcde", "a") //=> 1 查找字符索引
str-index("abcde", "c") //=> 3
str-insert("abcde", "j", 1) //=> "jabcde" 指定位置插入字符串
str-insert("abcde", "j", 4) //=> "abcjde"
str-insert("abcde", "j", 100) //=> "abcdej"
str-insert("abcde", "j", -20) //=> "jabcde"
str-length("abcde") //=> 5 获取字符串长度
str-slice("abcde", 1, 2) //=> "ab" 从指定位置开始截取指定长度的字符串
str-slice("abcde", 2, 4) //=> "bcd"
to-upper-case("abcde") //=> "ABCDE" 转为大写
to-upper-case("Abc") //=> "ABC" 转为大写
to-lower-case("ABC") //=> "abc" 转为小写
to-lower-case("Abc") //=> "abc" 转为小写
unique-id() //=> urgdjis 生成唯一字符串标识
math.$e //=> 2.7182818285 返回数学常数 e 的值
math.$pi //=> 3.1415926536 返回数学常数 π 的值
ceil(4.2) //=> 5 向上取整
floor(4.8) //=> 4 向下取整
round(4.3) //=> 4 四舍五入取近似值
round(4.7) //=> 5 四舍五入取近似值
abs(-10px) //=> 10px 取绝对值
math.cos(100deg) //=> -0.1736481777 返回余弦值,单位必须与deg兼容或无单位
math.sin(100deg) //=> 0.984807753 返回正弦值,单位必须与deg兼容或无单位
math.tan(100deg) //=> -5.6712818196 返回正切值,单位必须与deg兼容或无单位
math.acos(0.5) //=> 60deg 返回反余弦值,传入的参数不可带单位
math.asin(0.5) //=> 30deg 返回反正弦值,传入的参数不可带单位
math.atan(10) //=> 84.2894068625deg 返回反正切值,传入的参数不可带单位
math.log(10) //=> 2.302585093 对数函数
math.log(10, 10) //=> 1
math.pow(10, 2) //=> 100 幂运算
math.sqrt(100) //=> 10 求平方根
math.max(8, 4) //=> 8 返回二者的最大的值
math.min(8, 4) //=> 4 返回二者的最小的值
ndom() //=> 返回一个 0~1 之间的随机数
percentage(0.2) //=> 20% 将无单位的小数转换为百分比数
comparable(10px, 10) //=> true 判断两个数值的单位是否兼容
comparable(10px, 10px) //=> true
comparable(10px, 10em) //=> false
unitless(100) //=> true 判断传入的数值是否没有单位
unitless(100px) //=> false
unit(8) //=> ""
unit(8px) //=> "px" 返回传入数值的单位
unit(8em) //=> "em"
append(10 11 12, 13) //=> 10 11 12 13 向一个列表的末尾插入元素
append((10,11,12), 13) //=> 10, 11, 12, 13
join(5 6, 7 8) //=> 5 6 7 8 连接两个列表
join((5,6), (7,8)) //=> 5, 6, 7, 8
join(5 6, 7 8, $bracketed: true) //=> [5 6 7 8]
index(a b solid, b) //=> 2 返回 $value 在列表 $list 中的索引
index(a b solid, solid) //=> 3
length(a b solid) //=> 3 返回列表的长度
length("") //=> 1
list-separator(a b) //=> space
list-separator((a,b)) //=> comma 返回列表的分隔符
nth(a b c d, 2) //=> b 通过索引在列表中取元素
if(true, 18px, 16px) //=> 18px 三目运算
if(true, 18px, 16px) //=> 16px
$val_map: ("a": 1, "b": 2, "c": 3); // 定义 maps 类型的数据
map-get($val_map, "a") //=> 1
map-get($val_map, "b") //=> 2
$val_map: ("a": 1, "b": 2, "c": 3); // 定义 maps 类型的数据
map-has-key($val_map, "b") //=> true
map-has-key($val_map, "e") //=> false
$val_map: ("a": 1, "b": 2, "c": 3); // 定义 maps 类型的数据
map-keys($val_map) //=> "a","b","c"
$val_map1: ("a": 1, "b": 2);
$val_map2: ("c": 3, "d": 4);
map-merge($val_map1, $val_map2)
// => 返回的数据
// (
// "a": 1,
// "b": 2,
// "c": 3,
// "d": 4
// )
$val_map: ("a": 1, "b": 2, "c": 3); // 定义 maps 类型的数据
map-remove($val_map, "a", "b") //=> ("c": 3)
$val_map: ("a": 1, "b": 2, "c": 3); // 定义 maps 类型的数据
map-values($val_map) //=> 1,2,3
blue(#BA55D3) //=> 211 获取RGB通道色值
red(#BA55D3) //=> 186
green(#BA55D3) //=> 85
saturate(#BA55D3, 20%) //=> #c740e8 调整饱和度
scale-color(#BA55D3, $red: 15%) //=> #c455d3 调整红色通道
scale-color(#BA55D3, $blue: 15%) //=> #ba55da 调整蓝色通道
scale-color(#BA55D3, $lightness: -10%, $saturation: 10%) //=> #b338d2 调整亮度和饱和度
scale-color(#BA55D3, $alpha: -30%) //=> rgba(186, 85, 211, 0.7) 调整不透明度
实战应用:
一般来说我们的项目中会有一个 function.scss
文件来单独维护各种各样的函数
// 截取字符串的后半部分
@function middleStr($str) {
$leng: str-length($str);
$start: $leng / 2;
@return str-slice($str, $start, $leng);
}
// 判断class长度范围
@function classLong($class, $max) {
$leng: str-length($class);
@if $leng > $max {
@return true;
} @else {
@return false;
}
}
// 大小写转换
@function upperOrLower($str, $type) {
@if type-of($str) == "string" {
@if $type == "upper" {
@return to-upper-case($str);
} @else {
@return to-lower-case($str)
}
}
}
什么是 @-Rules 呢?其实就是以 @ 开头的一些规则,在 CSS 中有很多 @-Rules 是你经常用的,比如 @media 、@font-face 等等;在 Sass 中除了支持 CSS 所有的 @-Rules 外,Sass 还提供了一些扩展的 @ 规则。
用于导入sass文件,官方建议使用 @use
来替代 @import
也用于导入sass文件,主要用于跨文件导入时中间转发
我在 src/a.scss
中定义了一个 mixin:
// src/a.scss
@mixin bor {
width: 100px;
height: 100px;
}
然后在 b.scss
中使用 @forward
来导入它:
// b.scss
@forward 'src/a';
现在,我是想在和 b.scss
同级的 c.scss
文件中使用 a.scss
中的 mixin
,那么在 c.scss
中我们可以不直接导入 a.scss,我们通过导入 b.scss 也可以实现:
// c.scss
@use "b";
li {
// 应用 a.scss 文件中的 mixin
@include b.bor;
}
@mixin 是混合器指令,@include 是用来引用混合指令的
函数指令,用来定义函数
继承指令
调试信息相关,@error
和 @warn
差不多,都可以打印信息,区别是 @error
会停止函数运行,而@warn
不会停止函数运行,只打印信息。@debug
来打印表达式的值以及文件名和行号等信息。
@function my($str) {
@if $str != 'a' || $str != 'b' {
// 此处会抛出错误信息并停止函数的运行
@error "This is a error!"
}
}
@function my($str) {
@if $str != 'a' || $str != 'b' {
// 此处不会停止函数的运行
@warn "This is a message!"
}
}
用来取消嵌套规则
.a {
width: 300px;
.b {
width: 200px;
}
.c {
width: 100px;
// 取消嵌套规则
@at-root .f {
width: 20px;
}
}
// 取消嵌套规则
@at-root .e {
width: 50px;
}
}
转换后的CSS:
.a {
width: 300px;
}
.a .b {
width: 200px;
}
.a .c {
width: 100px;
}
.f {
width: 20px;
}
.e {
width: 50px;
}
注意其中的 .f 和 .e 并没有应用嵌套规则
包括 @if 、@each、@for 和 @while等,后面会介绍
@if
指令格式为: @if 表达式 { … } , 在 @if
后跟一个表达式,如果表达式为 true
则执行 {}
里的代码逻辑,@else
和 @else if
以此类推,功能跟原生开发语言一样。
@mixin avatar($size, $circle: 1) {
height: $size;
@if $circle == 1 {
width: $size / 2;
} @else if $circle == 2 {
width: $size / 5;
} @else {
width: $size;
}
}
.a { @include avatar(100px); }
.b { @include avatar(100px, $circle: 2); }
.c { @include avatar(100px, $circle: 3); }
转换后的CSS:
.a {
height: 100px;
width: 50px;
}
.b {
height: 100px;
width: 20px;
}
.c {
height: 100px;
width: 100px;
}
@each
指令的语法为: @each $variable
in expression
{ … } ,一般用来循环一个列表或 Map ,其中 expression
是一个列表或者返回一个列表的表达式,$variable
是列表中的每一项,{}
中是每次循环都会执行的代码.
$borders: 2px, 3px, 5px;
@each $bor in $borders {
.border-#{$bor} {
border:$bor solid;
}
}
转换后的CSS:
.border-2px {
border: 2px solid;
}
.border-3px {
border: 3px solid;
}
.border-5px {
border: 5px solid;
}
这样生成不同粗细大小的边框样式是不是方便了很多
for循环指令,语法是:
@for $variable from [start] to [end] { … }
或者
@for $variable from [start] through [end] { … }
,
其中variable
都是每次循环时的索引变量,start
都表示开始的边界,end
都表示结束的边界;二者区别是 through
包含 start
与 en
,而 to
包含 start
但不包含 end
。
through的写法:
$base-color: #036;
// 范围是 1 ~ 3
@for $i from 1 through 3 {
ul:nth-child(3n + #{$i}) {
background-color: lighten($base-color, $i * 5%);
}
}
// 范围是 4 ~ 6
@for $i from 4 through 6 {
ul:nth-child(3n + #{$i}) {
background-color: lighten($base-color, $i * 5%);
}
}
转换后的CSS:
// 1 ~ 3 范围生成的
ul:nth-child(3n+1) {
background-color: #004080;
}
ul:nth-child(3n+2) {
background-color: #004d99;
}
ul:nth-child(3n+3) {
background-color: #0059b3;
}
// 4 ~ 6 范围生成的
ul:nth-child(3n+4) {
background-color: #0066cc;
}
ul:nth-child(3n+5) {
background-color: #0073e6;
}
ul:nth-child(3n+6) {
background-color: #0080ff;
}
看到转换后的 CSS 是不是感觉使用 @for 指令写起来简直飞快,下面是使用 to 写法:
$base-color: #036;
@for $i from 1 to 3 {
ul:nth-child(3n + #{$i}) {
background-color: lighten($base-color, $i * 5%);
}
}
转换后的CSS:
ul:nth-child(3n+1) {
background-color: #004080;
}
ul:nth-child(3n+2) {
background-color: #004d99;
}
to是包前不包后的,跟正常的for循环写法一样
@while 指令的语法 @while expression { … }
,当表达式 expression
结果为 true
时就执行 {}
里的代码,直到 false
时跳出循环。
$num: 4;
@while $num >= 1 {
.box-#{$num} {
font-weight: 100 * $num;
}
$num: $num - 1;
}
转换后的CSS:
.box-4 {
font-weight: 400;
}
.box-3 {
font-weight: 300;
}
.box-2 {
font-weight: 200;
}
.box-1 {
font-weight: 100;
}
这个也很方便
实战应用:
需求将视口分为 12 等份,然后根据不同的 class 类名来为其宽度设置不同的百分比:
@for $i from 0 through 12 {
.width-#{$i} {
width: (1 / 12 * $i) * 100%;
}
}
这样就能一下子得到 .width-0 到 .width-12 的CSS选择器,同时它们的样式分别是对应的百分比:
.width-0 {
width: 0%;
}
.width-1 {
width: 8.3333333333%;
}
.width-2 {
width: 16.6666666667%;
}
.width-3 {
width: 25%;
}
.width-4 {
width: 33.3333333333%;
}
.width-5 {
width: 41.6666666667%;
}
.width-6 {
width: 50%;
}
.width-7 {
width: 58.3333333333%;
}
.width-8 {
width: 66.6666666667%;
}
.width-9 {
width: 75%;
}
.width-10 {
width: 83.3333333333%;
}
.width-11 {
width: 91.6666666667%;
}
.width-12 {
width: 100%;
}
语法:@function name(arguments…){}
,@function
是定义函数的指令,name
是函数名,arguments
是参数列表,也可以没有参数。其中函数名将连字符和下划线视为相同,也就是说 a_b 和 a-b 是同一个函数。
使用@function
定义函数
// 定义函数
@function a() {
@return "a"
}
// 使用函数
.p {
font: a();
}
函数只要定义了参数就必须传入这些参数,但是你可以定义默认值使参数成为可选的:
// 有默认值的参数
@function a($arg: 1) {
@return $arg;
}
// 无默认值的参数
@function b($arg) {
@return $arg;
}
.p {
font: a();
font: b(4);
}
转换后的CSS:
.p {
font: 1;
font: 4;
}
函数指令将最后一个参数以 … 结尾也可以接收任意数量的参数:
@function fonts($familys...) {
@return $familys;
}
.p {
font: fonts("one", "two", "three")
}
转换后的CSS:
.p {
font: "one", "two", "three";
}
@return
指令表示作为函数调用结果的值,即函数的返回值。在 Sass 中 @return 指令只能在 @function 中使用,并且每个 @function 都必须以 @return 结尾! 在 @function 的逻辑代码中,如遇到 @return
会立即结束函数并返回其结果,这在一些 @if
判断的情况下很有用。
@function a($str: "a") {
@if $str == "a" {
@return 10px;
} @else if $str == "b" {
@return 20px;
} @else if $str == "c" {
@return 30px;
} @else {
@return 40px;
}
}
p {
padding: a();
width: a("f");
height: a("c");
margin: a("b");
}
转换后的CSS:
p {
padding: 10px;
width: 40px;
height: 30px;
margin: 20px;
}
实战应用:
在实际的项目中使用函数指令是必不可少的,我们会定义很多函数来帮助我们解决逻辑问题,一般我们会独立抽出来一个 function.scss
文件来管理整个项目中的函数指令,一般这些函数都是根据你的项目特性以及样式需要封装出来的。
混合器指令可以定义重复使用的样式,避免编写过多重复的样式代码,它将帮你更合理的维护样式代码。
语法:@mixin name { … }
或者 @mixin name(
,第一种是不传参的指令,第二种是传参的指令。混合器本身其实是一个函数定义。
使用 @mixin
定义,而使用 @include
进行引用混合器
// 不接收参数的混合指令
@mixin border {
border: {
width: 1px;
color: #cccccc;
style: solid;
}
}
// 接收参数的混合指令
@mixin font($size: 12px, $weight: 100) {
font: {
family: "Myfont";
weight: $weight;
size: $size;
}
}
.box {
// 引用混合指令
@include border;
}
.item {
// 引用混合指令并传参
@include font(20px, 500);
}
转换后的CSS:
.box {
border-width: 1px;
border-color: #cccccc;
border-style: solid;
}
.item {
font-family: "Myfont";
font-weight: 500;
font-size: 20px;
}
可以跟函数一样传参数,但是这些参数只要声明了就必须传入,如果你想让某个参数成为可选的,你需要为这个参数赋一个默认值:
// 没有赋默认值的参数
@mixin font-one($size, $weight) {
font: {
family: "Myfont";
weight: $weight;
size: $size;
}
}
// 赋默认值的参数
@mixin font($size: 12px, $weight: 100) {
font: {
family: "Myfont";
weight: $weight;
size: $size;
}
}
除了默认值,在传参的时候还可以按名称传入参数:
@mixin font($size: 12px, $weight: 100) {
font: {
family: "Myfont";
weight: $weight;
size: $size;
}
}
.item {
// 按名称传入参数
@include font-one(20px, $weight: 800);
}
有时候 @mixin 接收的参数个数你可能不不清楚有多少个,那么你可以将最后一个参数以 … 结尾,那么所有额外的参数都将传给该参数,然后在 @mixin 里来获取所有参数:
@mixin fonts($s, $familys...) {
font:{
size: $s;
family: $familys;
}
}
.p {
@include fonts(12px, "one", "two", "three")
}
生成的CSS代码:
.p {
font-size: 12px;
font-family: "one", "two", "three";
}
@mixin 指令除了可以接收参数外,还可以接收样式块,在 @mixin 中可以使用 @content
来声明接收的内容块,内容块是通过 {}
的方式传入的,然后会注入到 @content
所在的位置。
@mixin hover {
&:hover {
@content;
}
}
.button {
border: 1px solid black;
@include hover {
border-width: 2px;
}
}
转换成的CSS代码:
.button {
border: 1px solid black;
}
.button:hover {
border-width: 2px;
}
实战应用:
在项目中建立专门的 mixin.scss
文件来管理全局的 @mixin
指令:
@mixin border($width: 1px, $color: #cccccc, $style: solid) {
border: {
width: $width;
color: $color;
style: $style;
}
}
@mixin font($size: 12px, $weight: 100, $familys...) {
$family: "Times";
@if length($familys) > 0 {
$family: $familys;
}
font: {
size:$size;
weight: $weight;
family: $family;
}
}
@mixin btn($type: "main") {
border-radius: 4px;
@if $type == "small" {
width: 60px;
height: 20px;
background-color: #e5e5e5;
color: #ffffff;
&:hover {
background-color: #4AA1FF;
}
} @else if $type == "disable" {
width: 80px;
height: 30px;
background-color: #CCCCCC;
color: #ffffff;
} @else {
width: 80px;
height: 30px;
background-color: #e5e5e5;
color: #ffffff;
&:hover {
background-color: #4AA1FF;
}
}
}
定义的全局的 @mixin 有关于 border 样式的,有关于 font 样式的,还有一个我们自己封装的 button 样式,这样在项目的任何需要写这些样式的地方直接应用这些指令就可以了,而不需要编写大量的 CSS 样式:
// 使用 border 混合指令
.normal-border {
@include border;
}
.error-border {
@include border(2px, red, solid);
}
// 使用 font 混合指令
.main {
@include font(24px);
.item {
@include font(16px, 600, "serif", "Roman", "Times");
}
}
// 使用 button 混合指令
.btn {
&-main {
@include btn();
}
&-disable{
@include btn("disable");
}
&-small{
@include btn("small");
}
}
语法:@extend selector
也就是在 @extend
后面跟一个选择器,表示继承这个选择器的样式。
.a {
width: 10px;
}
.b {
@extend .a;
height: 10px;
color: red;
}
转换成的CSS代码:
.a, .b {
width: 10px;
}
.b {
height: 10px;
color: red;
}
注意这里转换后的结果,.a, .b
与前面介绍的 Sass嵌套生成的结果 .a .b
的区别多了个逗号,前者表示所有选择器为.a
的标签和所有选择器为.b
的标签,同时具备该样式,后者表示后代选择器,即选中.a
标签里面的.b
的标签。
复杂的例子:
.a {
width: 100px;
height: 200px;
background-color: orange;
&:hover {
background-color: green;
}
.link {
width: 50%;
height: 50%;
color: red;
&:active {
color: blue;
}
i {
font-size: 18px;
font-weight: 600;
}
}
}
.b {
@extend .a;
width: 400px;
height: 200px;
}
转换成的CSS代码:
.a, .b {
width: 100px;
height: 200px;
background-color: orange;
}
.a:hover, .b:hover {
background-color: green;
}
.a .link, .b .link {
width: 50%;
height: 50%;
color: red;
}
.a .link:active, .b .link:active {
color: blue;
}
.a .link i, .b .link i {
font-size: 18px;
font-weight: 600;
}
.b {
width: 400px;
height: 200px;
}
从上面转换成 CSS 的代码我们可以看出,引用相同样式的部分都以逗号做了分隔,在 CSS 中使用逗号的含义你应该很了解,继承 @extend 就可以为你自动创建这些组合,提取相同的样式,所以如果有选择器使用了相同的样式,请使用继承的方式来实现!
Sass中的选择器除了有CSS的 id
或 class
选择器以外,还有 以 % 开头的占位符选择器,但是在 Sass 中你单独使用这种选择器是不会转换为 CSS 的,因为它只能通过 @extend
来使用的。
%placeholder {
box-sizing: border-box;
border-top: 1px #666666 solid;
width: 100%;
&:hover { border: 2px #999999 solid; }
&:active {color: blue;}
}
.buttons {
@extend %placeholder;
color: #4285f4;
}
.btn {
@extend %placeholder;
}
转换成的CSS代码:
.btn, .buttons {
box-sizing: border-box;
border-top: 1px #666666 solid;
width: 100%;
}
.btn:hover, .buttons:hover {
border: 2px solid;
}
.btn:active, .buttons:active {
color: blue;
}
.buttons {
color: #4285f4;
}
如果你需要在 @media
中使用继承,一定要注意使用方式!如果你在外部定义样式,然后在 @media 内部继承外部的样式,Sass 是会报错的。我们首先举个错误的例子看下:
.error {
border: 1px red solid;
background-color: red;
}
@media screen and (max-width: 600px) {
.btn-error {
@extend .error;
}
}
这样的写法在 Sass 中是会报错的,也不会编译成功。 Sass 规定继承只能在给定的媒体上下文中使用,所以正确的写法如下:
@media screen and (max-width: 600px) {
.error {
border: 1px red solid;
background-color: red;
}
.btn-error {
@extend .error;
}
}
转换成的CSS代码:
@media screen and (max-width: 600px) {
.error, .btn-error {
border: 1px red solid;
background-color: red;
}
}
实战应用:
我们注意到@extend
和 @mixin
都可以用来封装和复用样式,那么什么时候使用 @mixin
,什么时候使用 @extend
呢?假如你需要使用参数来配置样式的时候,也就是需要传参数的时候,毫无疑问使用 @mixin
。但如果你只是需要复用一部分样式,那么还是使用继承会更方便些。
Sass 的导入和 CSS 中的导入语法类似,只不过在 Sass 中可以导入用逗号分隔的多个文件, 我们举个例子看下:
@import 'a.scss', 'b.scss';
上面的代码意思是导入 a.scss 和 b.scss 文件,那么导入后 a 和 b 中的任何mixin 、函数和变量都是可以使用的。
我们知道在 CSS 中也有 @import
语句,在以下几种情况 Sass 会认为 @import
是 CSS 语句:
如果导入的扩展名是 .scss
或 .sass
那么肯定用的是 Sass 提供的 @import
。如果导入文件没有指定文件扩展名,那么 Sass 会尝试寻找文件名相同的扩展名为 .sass 或 .scss 的文件。
Sass 允许我们自行提供文件的加载路径,在我们导入文件的时候,Sass 总是会相对于当前文件进行解析,如果没有加载到则会使用加载路径。假如我们将加载路径设置为 node_modules/public/sass
,那么我们使用如下的导入方式:
@import 'a';
假如当前目录下没有 a.scss 文件,那么 Sass 就会去加载 node_modules/public/sass/a.scss
,这就是使用了加载路径,不过这种方式我们在项目中极少应用,你只需要了解即可。
Sass中可以仅导入 Sass 或 Scss 文件,而不将它们编译为 CSS,那么应该怎么做呢?假如我要导入一个 my.scss
文件,我不希望将它编译为 CSS ,那么需要使用下划线开头的文件名,也就是说要改名为 _my.scss
,然后使用如下导入代码:
@import 'my';
另外需要注意的是:不可以同时存在带有下划线和不带下划线的同名文件!
在 Sass 中索引文件是指_index.scss
文件,那它有什么用呢?假如我有一个 my
目录,这个目录下有两个文件,一个是 a.scss
一个是 _index.scss
,那么我使用如下文件导入代码:
@import 'my';
那么这样导入的就是 _index.scss
文件,也就是说 _index.scss 是这个目录下的默认文件
,跟我们导入目录下的index.html
index.js
是一样的道理。
Sass 也可以直接导入一个 CSS 文件,要注意的是,在导入的 CSS 文件中不允许有任何 Sass 的特性和语法,如果有的话将会报错!导入的 CSS 文件会按照原有的样子呈现。
Sass 允许在样式表中嵌入 @import
,使用这种方式的话,以下划线开头的文件内容将会被直接插入到使用 @import
的位置
// _a.scss
. item {
width: 100px;
height: 200px;
}
在 style.scss 中导入上面的 _a.scss 文件:
// style.scss
.box {
@import '_a.scss';
}
转换成的CSS代码:
.box {
.item {
width: 100px;
height: 200px;
}
}
这种用法很少用。
Sass 官方团队不鼓励使用 @import 导入,并且在未来几年将逐步淘汰它,并最终将 @import 从 Sass 中完全删除。官方推荐@use
替代@import。二者语法是一样的:
@use 'my/a.scss';
@use 'my/b';
官方想淘汰@import
的原因之一是它导入的变量、函数等都是全局可以访问的,开发者很难去维护这些定义的东西,如可能造成命名冲突等。
实战应用:
在实际项目中多数还是使用 @import 来进行导入文件:
在 Sass 中有 4 种输出格式:
嵌套格式:
.box {
width: 100px; }
.box2 {
width: 200px;
height: 100px; }
.box2 p {
color: red; }
展开格式:
.box {
width: 100px;
}
.box2 {
width: 200px;
height: 100px;
}
.box2 p {
color: red;
}
.box2 .main {
width: 100%;
heigth: auto;
}
紧凑格式:
.box { width: 100px; }
.box2 { width: 200px; height: 100px; }
.box2 p { color: red; }
.box2 .main { width: 100%;heigth: auto; }
压缩格式:
.box{width:100px;}.box2{width:200px;height:100px;}.box2 p{color:red;}.box2 .main{width:100%;heigth:auto;}
一般线上生成环境使用的是压缩格式。
输出格式的设置:
在前端项目里使用 Sass 一般都会安装 node-sass
这个依赖包,node-sass
的设置选项中有一个 outputStyle
可以用于设置输出格式,示例如下:
var sass = require('node-sass');
sass.render({
file: '/path/to/myFile.scss',
includePaths: [ 'lib/', 'mod/' ],
// 设置输出格式
outputStyle: 'compressed'
}, function(error, result) {
console.log(error.status);
}
});
在前端的项目中我们一般会使用 webpack
作为构建工具,所以我们可以在 sass-loader
中来设置 sass
的输出格式:
// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.s[ac]ss$/i,
use: [
'style-loader',
'css-loader',
{
loader: 'sass-loader',
options: {
sourceMap: true,
sassOptions: {
outputStyle: 'compressed'
},
},
},
],
},
],
},
};
可以像java代码中那样加注释,单行注释使用 //
多行注释使用 /**/
, Sass的注释是不会被编译到CSS中的,所以可以放心大胆的写。
// 单行注释
.box1{
width:100px
}
/*
* 多行注释
* 多行注释
* /
.box2{
width:100px
}
除了.scss
后缀文件还经常看的.less
后缀的文件,Less
是什么呢?跟Sass
是什么关系?
Less
也是一种css
预处理器,Sass
是对css
的扩展,Less
可以理解为Sass
的简化版本, 总体使用体验差不多,但是二者实现方式不同。Less
既可以在客户端上运行 (支持IE 6+, Webkit, Firefox
),也可在服务端运行 (借助 Node.js
)。
编译环境不一样
Sass
是在服务端处理的,以前是Ruby
,现在是Dart-Sass
或Node-Sass
,而Less
是需要引入less.js
来处理Less
代码输出CSS
到浏览器,也可以在开发环节使用Less
,然后编译成css
文件,直接放到项目中,也有Less.app、SimpleLess、CodeKit.app
这样的工具,也有在线编译地址。
输出设置不同,Less
没有输出设置,Sass
提供4种输出设置
Less 不支持条件语句,Sass 支持条件语句,Sass
可以使用if{} else{}, for{}
循环等等。
定义变量方式不同, Less
用@
,Sass
用$
Sass 和 Less 的工具库不同
Sass有工具库
Compass
, 简单说,Sass和Compass的关系有点像Javascript和jQuery的关系,Compass是Sass的工具库。在它的基础上,封装了一系列有用的模块和模板,补充强化了Sass的功能。
Less有UI组件库Bootstrap
,Bootstrap是web前端开发中一个比较有名的前端UI组件库,Bootstrap的样式文件部分源码就是采用Less语法编写。
Less和Sass在下面的使用上是相同的:
所以掌握了Sass的语法,学习Less基本上是不费力的,因为使用上几乎一样
Sass官网:https://sass-lang.com/
Less官网:https://less.bootcss.com/
虽然很多前端项目还是在使用 node-sass
,但是由于node-sass
底层依赖 libsass
,导致很多用户下载安装特别困难,尤其是 windows
用户,还要必须安装python2
和Visual Studio
才能编译成功。所以官方已经主推将node-sass
迁移到 dart-sass
,并且 新特性将会 dart-sass
上面实现。
详细请看:
按照官方的说法,Dart Sass 主要是用来运行在 Dart-VM 上,运行速度很快,也就是你需要安装 Dart SDK, 使用Dart语言来开发前端项目,显然这目前还不是国内开发者的首选。但是官方说 Dart Sass 也可以被编译为纯 JavaScript 并在 npm
上作为 sass
软件包发布使用,但是我感觉应该还是不会特别快,毕竟不是Dart运行环境。
参考:http://www.imooc.com/wiki/sasslesson