LESS 和 SCSS 都属于 CSS 预处理器的范畴,也就是 CSS 的超集,但是两者的语法、如何使用和具体的功能实现还是有差异的。
下面我试着以代码示例的方式给大家演示一下两者的几个常见区别。
声明和使用变量
LESS 采用 @ 符号,SCSS 采用 $ 符号。
在下面的示例中,我们首先在规则外声明了一个名为 link-color 的变量,然后在名为 #main 的规则内声明一个名为 width 的变量,接着把 width 变量赋值给了 CSS 的 width 属性。
LESS:
| @link-color: #428bca; #main { @width: 5em; width: @width; }
|
SCSS:
| $link-color: #428bca; #main { $width: 5em; width: $width; }
|
变量插值(Variable Interpolation)
LESS 采用 @{xxxx} 的形式,SCSS 采用 ${xxxx} 的形式。
示例一:使用变量插值作为 CSS 选择器
LESS:
| @my-selector: banner;
.@{my-selector} { font-weight: bold; line-height: 40px; margin: 0 auto; }
|
SCSS:
| $my-selector: banner;
.#{$my-selector} { font-weight: bold; line-height: 40px; margin: 0 auto; }
|
Mixins 的定义、使用及参数
定义一个 Mixin
LESS 使用 dot 符号(也就是句点)来定义一个 Mixin,并且可以把任意的 CSS 规则作为 Mixin 使用;SCSS 使用 **@mixin ** 指令来定义一个 Mixin。
示例 – 来自 BootStrap 的 alert-variant Mixin 的定义
LESS
| .alert-variant(@background; @border; @text-color) { background-color: @background; border-color: @border; color: @text-color; }
|
SCSS:
| @mixin alert-variant($background, $border, $text-color) { background-color: $background; border-color: $border; color: $text-color; }
|
使用 Mixin
LESS 仍是使用 dot 符号(句点),如果 Mixin 没有参数的话可以省略后面的圆括号;SCSS 使用 **@include ** 指令来引入一个 Mixin。
示例 – 引入一个名为 center-block 的 Mixin。
LESS:
| .center-block() { display: block; margin-left: auto; margin-right: auto; }
.a { .center-block; }
|
SCSS:
| @mixin center-block() { display: block; margin-left: auto; margin-right: auto; }
.a { @include center-block; }
|
参数形式
如果存在多个参数的话,LESS 使用**分号**
分隔;SCSS 使用**逗号**
分隔。两者都支持为参数设置默**认值**
。
LESS:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
| @state-success-text: #3c763d; @state-success-bg: #dff0d8; @state-success-border: darken(spin(@state-success-bg, -10), 5%);
@state-info-text: #31708f; @state-info-bg: #d9edf7; @state-info-border: darken(spin(@state-info-bg, -10), 7%);
@state-warning-text: #8a6d3b; @state-warning-bg: #fcf8e3; @state-warning-border: darken(spin(@state-warning-bg, -10), 5%);
@state-danger-text: #a94442; @state-danger-bg: #f2dede; @state-danger-border: darken(spin(@state-danger-bg, -10), 5%);
.box-shadow(@shadow) { -webkit-box-shadow: @shadow; box-shadow: @shadow; }
.form-control-validation(@text-color: #555; @border-color: #ccc; @background-color: #f5f5f5) { .help-block, .control-label, .radio, .checkbox, .radio-inline, .checkbox-inline, &.radio label, &.checkbox label, &.radio-inline label, &.checkbox-inline label { color: @text-color; } .form-control { border-color: @border-color; .box-shadow(inset 0 1px 1px rgba(0,0,0,0.075)); &:focus { border-color: darken(@border-color, 10%); @shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px lighten(@border-color, 20%); .box-shadow(@shadow); } } .input-group-addon { color: @text-color; border-color: @border-color; background-color: @background-color; } .form-control-feedback { color: @text-color; } }
.has-success { .form-control-validation(@state-success-text; @state-success-text; @state-success-bg); } .has-warning { .form-control-validation(@state-warning-text; @state-warning-text; @state-warning-bg); } .has-error { .form-control-validation(@state-danger-text; @state-danger-text; @state-danger-bg); }
|
SCSS:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
| $state-success-text: #3c763d; $state-success-bg: #dff0d8; $state-success-border: darken(adjust_hue($state-success-bg, -10), 5%);
$state-info-text: #31708f; $state-info-bg: #d9edf7; $state-info-border: darken(adjust_hue($state-info-bg, -10), 7%);
$state-warning-text: #8a6d3b; $state-warning-bg: #fcf8e3; $state-warning-border: darken(adjust_hue($state-warning-bg, -10), 5%);
$state-danger-text: #a94442; $state-danger-bg: #f2dede; $state-danger-border: darken(adjust_hue($state-danger-bg, -10), 5%);
@mixin box-shadow($shadow) { -webkit-box-shadow: $shadow; box-shadow: $shadow; }
@mixin form-control-validation( $text-color: #555, $border-color: #ccc, $background-color: #f5f5f5 ) { .help-block, .control-label, .radio, .checkbox, .radio-inline, .checkbox-inline, &.radio label, &.checkbox label, &.radio-inline label, &.checkbox-inline label { color: $text-color; } .form-control { border-color: $border-color; @include box-shadow( inset 0 1px 1px rgba(0, 0, 0, 0.075) ); &:focus { border-color: darken($border-color, 10%); $shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px lighten($border-color, 20%); @include box-shadow($shadow); } } // Set validation states also for addons .input-group-addon { color: $text-color; border-color: $border-color; background-color: $background-color; } .form-control-feedback { color: $text-color; } }
.has-success { @include form-control-validation( $state-success-text, $state-success-text, $state-success-bg ); } .has-warning { @include form-control-validation( $state-warning-text, $state-warning-text, $state-warning-bg ); } .has-error { @include form-control-validation( $state-danger-text, $state-danger-text, $state-danger-bg ); }
|
函数的使用
字符串函数 (CSS 转义)
LESS 使用 e 或者**<font style="color:#2F54EB;">~"xxx"</font>**
** ** 这种语法进行 CSS 转义;SCSS 本身并没有提供 CSS 转义的函数,中要达到相同的效果可以使用变量插值(Variable Interpolation)**<font style="color:#2F54EB;">#{xxx}</font>\*\*
实现。
示例 – CSS 转义
LESS:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| @input-border-focus: #66afe9;
.box-shadow(@shadow) { -webkit-box-shadow: @shadow; box-shadow: @shadow; }
.form-control-focus(@color: @input-border-focus) { @color-rgba: rgba(red(@color), green(@color), blue(@color), 0.6); &:focus { border-color: @color; outline: 0; .box-shadow(~"inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px @{color-rgba}"); } }
.form-control { .form-control-focus(); }
|
SCSS:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| $input-border-focus: #66afe9;
@mixin box-shadow($shadow) { -webkit-box-shadow: $shadow; box-shadow: $shadow; }
@mixin form-control-focus($color: $input-border-focus) { $color-rgba: rgba(red($color), green($color), blue($color), .6); &:focus { border-color: $color; outline: 0; @include box-shadow(#{inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px $color-rgba}); } }
.form-control { @include form-control-focus(); }
|
颜色函数
调节色相,LESS 使用名为 **spin()**
的函数;SCSS 使用名为 **adjust_hue()**
的函数。
示例 – 调节色相
LESS:
| @state-success-border: darken(spin(@state-success-bg, -10), 5%);
|
SCSS:
| $state-success-border: darken(adjust_hue($state-success-bg, -10), 5%);
|
数学函数
LESS 提供了一些 SCSS 中并不具备的数学函数,在 SCSS 中只能通过自定义函数实现,然后通过 node-sass 的接口传递给编译器。
示例 – 数学函数
SCSS:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| @mixin ie-rotate($rotation) { -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=@{rotation})"; }
@mixin ie-rotate-via-degrees($degrees) { $radians: parseInt("#{$degrees}") * PI() * 2 / 360; $costheta: cos("#{$radians}"); $sintheta: sin("#{$radians}"); $negsintheta: "#{$sintheta}"*-1; -ms-filter: "progid:DXImageTransform.Microsoft.Matrix(sizingMethod='auto expand', M11=@{costheta}, M12=@{negsintheta}, M21=@{sintheta}, M22=@{costheta})"; zoom: 1;
:root & { filter: none; } }
@mixin cross-rotate($degrees) { @include rotate($degrees); @include ie-rotate-via-degrees($degrees); }
@mixin placeholder($color: $input-placeholder-color) { &::-moz-placeholder { color: $color; opacity: 1; } &:-ms-input-placeholder { color: $color; } &::-webkit-input-placeholder { color: $color; } }
|
上述 Math 实现所需的 JS 文件:
| module.exports = { 'parseInt($str)': function (str) { return parseInt(str, 10); }, 'Math.sin($degree)': function (degree) { return Math.sin(degree); }, 'Math.cos($degree)': function (degree) { return Math.cos(degree); }, 'Math.PI': Math.PI }
|
有关函数的区别还有:
- LESS 的 fade() 函数在 SCSS 中只能使用 rgba() 之类的实现,因为 SCSS 也没有这个函数。
像 @media, @import 这些带 @ 符号的在 CSS 中都称为 At-rules。
值的一提的是 LESS 和 SCSS 对@import 实现的区别。
LESS 的 @import 对文件扩展名的处理:
- 如果扩展名为 .css,将文件识别为 CSS 文件
- 其他任何扩展名都将被作为 LESS 文件处理
- 没有扩展名会被附加一个 .less 的扩展名并且作为 LESS 文件处理
SCSS 的 @import 实现对文件扩展名的处理:
- 默认情况下,SCSS 的 @import 实现会试图寻找一个 Sass 文件进行导入。
- 但是在下列情况出现时,@import 会直接被编译为 CSS 的 @import at-rule
- 文件扩展名是 .css
- 文件以 http:// 开头
- 文件名是一个 url()
- @import 具有媒体查询
- SCSS 按约定认为下划线开始的文件是内联文件,不会被编译为单独的 CSS 文件输出。
示例 – 使用 @import
LESS:
| @import "foo"; @import "bar.less"; @import "foo.php"; @import "foo.css";
|
SCSS:
| @import "foo"; @import "foo.scss";
|
其他区别
引用父选择器 & 符号的使用
LESS 和 SCSS 均使用 **&**
符号表示父选择器,但是 SCSS 的 & 符号只能出现在一个组合选择器的开始位置,LESS 则没有这个限制。
LESS:
| .bg-variant(@color) { background-color: @color; a&:hover, a&:focus { background-color: darken(@color, 10%); } }
|
SCSS:
| a { font-weight: bold; text-decoration: none; &:hover { text-decoration: underline; } body.firefox & { font-weight: normal; } }
|
SCSS 不支持 LESS 中的 CSS Guard 功能,比如 if, when …,在 SCSS 中需要换种方式实现。
LESS 示例:
| .my-optional-style() when (@my-option = true) { button { color: white; } } .my-optional-style();
|
Note:SCSS 需要换一种写法实现同样的功能。
SCSS 支持 !default,一般是用在基础 Rule 的声明中,告诉使用者这是可以被覆盖的。
SCSS 示例:
| $primary: $blue !default; $secondary: $gray-600 !default;
|
有关 extend
SCSS 不像 LESS 一样默认可以把 rule 作为 Mixin 使用,但是 SCSS 有类似的 @extend 指令;而 LESS 的 extend 语法看起来则像是伪类一样。
LESS:
| .error { border: 1px #f00; background-color: #fdd; } .seriousError { @extend .error; border-width: 3px; }
|
SCSS :
| .error { border: 1px #f00; background-color: #fdd; } .seriousError { @extend .error; border-width: 3px; }
|
集成 JavaScript 功能的方式
LESS 使用 @functions 指令,可以把 js 代码直接放到 **~ **
xxx**
**中间即可;SCSS 可以把 JS 代码放到一个单独的文件中,然后使用 node-sass 编译的时候指定参数传给 node-sass。
LESS 示例: ant-design/tinyColor.less
SCSS 示例:kant/Math.js
编译命令: node-sass --output-style expanded --source-map true --precision 6 --functions components/style/custom.js components/button/style/index.scss components/button/style/index.css
最后两个:
- LESS 支持 lazy evaluation,但是 SCSS 不支持,所以在 LESS 中可以先使用再定义,但是在 SCSS 中一定要先定义再使用。
- SCSS 是不支持 Mixin 重载的, 也就是说 LESS 可以有同名但是参数个数不同的几个 Mixins, SCSS 同样名字的 Mixin 只能有一个.