本文以 sass 語(yǔ)法點(diǎn)為主線展開(kāi),但語(yǔ)法細(xì)節(jié)不在此贅述,如有疑問(wèn)請(qǐng)移駕至 http://sass-lang.com 自行查閱。我所認(rèn)為的 sass 的優(yōu)勢(shì):結(jié)構(gòu)化(層級(jí)關(guān)系更清晰)、組件化(公用模塊的提取)、繼承(公用樣式的提?。Mx者能在瀏覽完此文后有所體會(huì)。
進(jìn)入正文前,先為大家推薦一枚神奇的網(wǎng)站:https://www.sassmeister.com/。
一、變量
變量默認(rèn)值
變量默認(rèn)值的價(jià)值在于進(jìn)行組件化開(kāi)發(fā)。
應(yīng)用場(chǎng)景
一個(gè)站點(diǎn)內(nèi)的公用模塊在不同頁(yè)面的展現(xiàn)形式會(huì)有些許不同,例如一個(gè)列表模塊中列表項(xiàng)的分隔方式在不同頁(yè)面存在差異。

傳統(tǒng)做法:
/* m-module-list.css */
.module-list li {
font-size: 14px;
line-height: 22px;
color: #666;
padding: 15px;
background-color: #FFF;
border-bottom: 1px solid #F0F0F0;
margin-bottom: none;
}
/* style.css */
@import 'm-module-list.css';
.module-list li {
border-bottom: none;
margin-bottom: 10px;
}
顯然,傳統(tǒng)做法會(huì)產(chǎn)生 冗余 代碼。對(duì) .module-list li 的 border-bottom 及 margin-bottom 定義了兩次(很好的體現(xiàn)了 css 層疊 的理念)。
使用變量默認(rèn)值:
/* m-module-list.scss */
$borderBottom: 1px solid #F0F0F0 !default;
$marginBottom: none !default;
.module-list {
li {
font-size: 14px;
line-height: 22px;
color: #666;
padding: 15px;
background-color: #FFF;
border-bottom: $borderBottom;
margin-bottom: $marginBottom;
}
}
/* style.scss */
$borderBottom: none;
$marginBottom: 10px;
@import 'm-module-list';
解析后的 css 代碼:
.module-list li {
font-size: 14px;
line-height: 22px;
color: #666;
padding: 15px;
background-color: #FFF;
border-bottom: none;
margin-bottom: 10px;
}
上述方法是存在缺陷的:定義 全局變量 很容易造成 污染 。但自 sass v3.4 便不存在這樣的問(wèn)題了,為什么這樣講?
先看一段示例:
$color: red;
p {
$color: yellow;
color: $color;
}
a {
color: $color;
}
sass v3.3 解析后的 css 代碼:
p {
color: yellow;
}
a {
color: yellow;
}
sass v3.4 解析后的 css 代碼:
p {
color: yellow;
}
a {
color: red;
}
自 sass v3.4 變量的解析遵循:底層作用域內(nèi)聲明的變量相當(dāng)于局部變量,不影響全局變量。
使用 javascript 解釋:
var a = 1;
(function () {
var a = 5;
})();
console.log(a); // -> 1
而 sass v3.3 及以前對(duì)變量的設(shè)計(jì)思路為:在底層作用域聲明變量相當(dāng)于修改全局變量,它處調(diào)用該變量時(shí)會(huì)使用覆蓋的新值。
使用 javascript 解釋:
var a = 1;
(function () {
a = 5;
})();
console.log(a); // -> 5
特殊變量
應(yīng)用于選擇器
應(yīng)用于屬性
特殊變量的應(yīng)用十分廣泛,在此不做特別介紹。請(qǐng)自行留意文中 #{$var} 這樣的書(shū)寫(xiě)方式,那就是所謂的特殊變量。
多值變量
- List 類型
應(yīng)用場(chǎng)景
由于存在圖片失效或尺寸不合規(guī)定的情況,我們通常需要為圖片添加默認(rèn)底色及占位。例如浮動(dòng)布局中元素尺寸的變化會(huì)擾亂呈現(xiàn)效果:

當(dāng)然,上述問(wèn)題可以通過(guò)為左側(cè)元素清除浮動(dòng)或延時(shí)加載圖片等方法解決。在此,我們僅講述為圖片添加占位這一方法,效果如下:

在不同的業(yè)務(wù)場(chǎng)景下,占位圖風(fēng)格各異。例如我司的常規(guī)需求、活動(dòng)類需求、專題類需求所啟用的占位圖就在顏色及底紋上存在差異。
我們可以定義 3 種圖片類型 default、activity、special 存儲(chǔ)在 List 類型變量 $thumbType 中,這樣書(shū)寫(xiě)語(yǔ)義清晰、利于拓展、精簡(jiǎn)代碼。
相關(guān)代碼:
$thumbType: default, activity, special;
@each $type in $thumbType {
%#{$type}-thumb {
background: url("../img/#{$type}-nothumb.jpg") no-repeat 0 0;
background-size: 100% auto;
padding-bottom: 100%;
height: 0;
overflow: hidden;
}
}
.section1 .thumb {
@extend %default-thumb;
}
.section2 .thumb {
@extend %activity-thumb;
}
.section3 .thumb {
@extend %special-thumb;
}
解析后的 css 代碼:
.section1 .thumb {
background: url("../img/default-nothumb.jpg") no-repeat 0 0;
background-size: 100% auto;
padding-bottom: 100%;
height: 0;
overflow: hidden;
}
.section2 .thumb {
background: url("../img/activity-nothumb.jpg") no-repeat 0 0;
background-size: 100% auto;
padding-bottom: 100%;
height: 0;
overflow: hidden;
}
.section3 .thumb {
background: url("../img/special-nothumb.jpg") no-repeat 0 0;
background-size: 100% auto;
padding-bottom: 100%;
height: 0;
overflow: hidden;
}
- Map 類型
應(yīng)用場(chǎng)景
通常,一個(gè)站點(diǎn)含多套配色方案,以按鈕的配色為例:主色、輔助色、弱色。每套配色又由多種狀態(tài)色組成:常態(tài)色、點(diǎn)擊色、失效色。

我們可以將這些色值按照一定的規(guī)則儲(chǔ)存在 Map 類型變量 中,這樣做的優(yōu)勢(shì)為:
結(jié)構(gòu)及語(yǔ)義清晰,增強(qiáng)了可讀性且易于修改。
添加新的配色方案相當(dāng)于添加配置項(xiàng),無(wú)需撰寫(xiě)大量代碼。
相關(guān)代碼:
$btnColor: (
main: (
normal: (
font: #C53336,
border: #C53336,
background: #FFF
),
active: (
font: #FFF,
border: #C53336,
background: #C53336
),
disabled: (
font: #999,
border: #F5F5F5,
background: #F5F5F5
)
),
weak: (
normal: (
font: #333,
border: #666,
background: #FFF
),
active: (
font: #FFF,
border: #666,
background: #666
),
disabled: (
font: #999,
border: #CCC,
background: #FFF
)
)
);
@mixin btnColor ($font, $border, $background) {
color: $font;
border-color: $border;
background-color: $background;
}
@each $type, $status in $btnColor {
%btn-#{$type} {
$normal: map-get($status, normal);
$active: map-get($status, active);
$disabled: map-get($status, disabled);
@include btnColor(map-values($normal)...);
&:active {
@include btnColor(map-values($active)...);
}
&.disabled {
@include btnColor(map-values($disabled)...);
}
}
}
a.btn-main {
@extend %btn-main;
}
a.btn-weak {
@extend %btn-weak;
}
解析后的 css 代碼:
a.btn-main {
color: #C53336;
border-color: #C53336;
background-color: #FFF;
}
a.btn-main:active {
color: #FFF;
border-color: #C53336;
background-color: #C53336;
}
a.disabled.btn-main {
color: #999;
border-color: #F5F5F5;
background-color: #F5F5F5;
}
a.btn-weak {
color: #333;
border-color: #666;
background-color: #FFF;
}
a.btn-weak:active {
color: #FFF;
border-color: #666;
background-color: #666;
}
a.disabled.btn-weak {
color: #999;
border-color: #CCC;
background-color: #FFF;
}
二、嵌套
嵌套可增強(qiáng)文件的結(jié)構(gòu)性及可讀性,但嵌套層級(jí)過(guò)多卻是大忌,@at-root 可解決該問(wèn)題。
@at-root
@at-root 可防止選擇器的優(yōu)先級(jí)過(guò)高。
先看一段很糟糕的代碼,嵌套層級(jí)過(guò)多。層級(jí)關(guān)系的展現(xiàn)雖清晰,卻莫名加高了選擇器的 優(yōu)先級(jí) 。那么在重置樣式的時(shí)候便需要加更高的優(yōu)先級(jí),由此惡性循環(huán)。
.parent {
.child1 {
width: 20px;
.child1-1 {
width: 20px;
.child1-1-1 {
width: 20px;
}
}
}
}
解析后的 css 代碼:
.parent .child1 {
width: 20px;
}
.parent .child1 .child1-1 {
width: 20px;
}
.parent .child1 .child1-1 .child1-1-1 {
width: 20px;
}
顯然,.parent .child1 .child1-1 .child1-1-1 的優(yōu)先級(jí)很高卻完全沒(méi)必要,我們需要做的便是降級(jí)。
.parent {
.child1 {
width: 20px;
@at-root .child1-1 {
width: 20px;
@at-root .child1-1-1 {
width: 20px;
}
}
}
}
解析后的 css 代碼:
.parent .child1 {
width: 20px;
}
.child1-1 {
width: 20px;
}
.child1-1-1 {
width: 20px;
}
其實(shí)這并不是我想要的,我想要的是:
.parent .child1 {
width: 20px;
}
.parent .child1-1 {
width: 20px;
}
.parent .child1-1-1 {
width: 20px;
}
顯然 @at-root 無(wú)法控制跳出的級(jí)數(shù),無(wú)奈。
@at-root 的另一應(yīng)用場(chǎng)景便是 @keyframes。動(dòng)畫(huà)的專屬性較強(qiáng),嵌套的寫(xiě)法能清晰的標(biāo)明其被應(yīng)用之處。在做功能刪除時(shí)只需直接干掉一整段代碼,無(wú)需查找對(duì)應(yīng)的 @keyframes 順便思考其影響范圍,省時(shí)高效。
示例代碼:
.demo {
animation: motion 1s infinite;
@at-root {
@keyframes motion {
0% {background-color: red;}
100% {background-color: yellow;}
}
}
}
解析后的 css 代碼:
.demo {
animation: motion 1s infinite;
}
@keyframes motion {
0% {background-color: red;}
100% {background-color: yellow;}
}
其實(shí)上述是 sass v3.3 之前的做法,自 sass v3.4 這樣書(shū)寫(xiě)即可:
.demo {
animation: motion 1s infinite;
@keyframes motion {
0% {background-color: red;}
100% {background-color: yellow;}
}
}
@keyframes 會(huì)自動(dòng)跳出父級(jí)的限制。
三、繼承
@mixin + @include
可傳遞參數(shù),可設(shè)置參數(shù)默認(rèn)值。
應(yīng)用場(chǎng)景
相信大家都很反感在使用 transition、transform 這類 css3 屬性時(shí)需要巴拉巴拉添加一堆前綴。
有了 sass 我們便可以定義一個(gè)自動(dòng)添加前綴的方法啦!引用時(shí),只需傳入屬性名及屬性值,非常方便。且欲添加新的所須兼容的瀏覽器時(shí),只需在 $compatibleBrowser 中添加配置項(xiàng)。若是使用傳統(tǒng)做法,想象下某天老板要我們兼容 ms 了,你是要把全站代碼修改一遍?
相關(guān)代碼:
$compatibleBrowser: webkit, moz, o;
@mixin addPrefix ($property, $value) {
@each $prefix in $compatibleBrowser {
-#{$prefix}-#{$property}: $value;
}
#{$property}: $value;
}
.demo {
background-color: red;
@include addPrefix(transition, background-color 2s);
&:hover {
background-color: yellow;
}
}
解析后的 css 代碼:
.demo {
background-color: red;
-webkit-transition: background-color 2s;
-moz-transition: background-color 2s;
-o-transition: background-color 2s;
transition: background-color 2s;
}
.demo:hover {
background-color: yellow;
}
% + @extend
用于定義通用樣式最為合適。
應(yīng)用場(chǎng)景
通常,我們會(huì)創(chuàng)建這樣一個(gè)文件 common.css 來(lái)定義一些通用樣式,引用時(shí)在對(duì)應(yīng)元素的 html 標(biāo)簽上添加相應(yīng)的 class 即可。
而 sass 的做法如下:
%horizontal-scroll {
white-space: nowrap;
overflow-x: scroll;
li {
display: inline-block;
vertical-align: middle;
}
&::-webkit-scrollbar {
width: 0;
height: 0;
opacity: 0;
}
}
section.horizontal-scroll {
@extend %horizontal-scroll;
}
解析后的 css 代碼:
section.horizontal-scroll {
white-space: nowrap;
overflow-x: scroll;
}
section.horizontal-scroll li {
display: inline-block;
vertical-align: middle;
}
section.horizontal-scroll::-webkit-scrollbar {
width: 0;
height: 0;
opacity: 0;
}
這樣做的優(yōu)勢(shì)為:
css 樣式與 html 結(jié)構(gòu)解耦。
去除冗余 css 代碼。
第一條優(yōu)勢(shì)顯而易見(jiàn),下面來(lái)為大家解釋第二條:在代碼被壓縮上線時(shí),傳統(tǒng)做法會(huì)使得未被引用的通用樣式一同被上線,而 sass 在被解析為 css 時(shí)會(huì)去除由 % 定義的未被引用的通用樣式。
四、函數(shù)
產(chǎn)生值,非行為。
不要與 javascript 中的函數(shù)混淆。調(diào)用時(shí)并非執(zhí)行了某段操作,而是返回了經(jīng)過(guò)某些操作后產(chǎn)生的值,其實(shí)類似于有 return 值的 javascript 函數(shù)。
五、語(yǔ)句
三目判斷
書(shū)寫(xiě)形式:
- if(條件, 條件為真所取值, 條件為假所取值)
莫名覺(jué)得會(huì)很常用,與 javascript 中的 ? : 作用相同。
@if
應(yīng)用場(chǎng)景
定義多行省略時(shí)(以 3 行為例),變更顯示行數(shù)只需修改 line-clamp 屬性值,代碼如下:
.ellipsis-row3 {
overflow: hidden;
display: -webkit-box;
text-overflow: -o-ellipsis-lastline;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
}
而定義單行省略只需如下 3 行:
.ellipsis-row1 {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
兩段代碼差異較大,而我們又想將多行與單行的情況融合在一個(gè)通用樣式內(nèi)。此時(shí),可以使用 if 語(yǔ)句將單行省略單獨(dú)定義。
相關(guān)代碼:
@for $lineCount from 1 through 3 {
%ellipsis-row#{$lineCount} {
overflow: hidden;
@if $lineCount == 1 {
white-space: nowrap;
text-overflow: ellipsis;
} @else {
display: -webkit-box;
text-overflow: -o-ellipsis-lastline;
-webkit-box-orient: vertical;
-webkit-line-clamp: $lineCount;
}
}
}
.section1 p {
@extend %ellipsis-row1;
}
.section2 p {
@extend %ellipsis-row2;
}
.section3 p {
@extend %ellipsis-row3;
}
解析后的 css 代碼:
.section1 p {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.section2 p {
overflow: hidden;
display: -webkit-box;
text-overflow: -o-ellipsis-lastline;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
}
.section3 p {
overflow: hidden;
display: -webkit-box;
text-overflow: -o-ellipsis-lastline;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
}
@for
for 循環(huán)的書(shū)寫(xiě)形式有兩種:
@for $var from start through end
@for $var from start to end
第一種在循環(huán)遍歷時(shí)會(huì)對(duì)第 end 項(xiàng)進(jìn)行操作,第二種則不會(huì)。本人認(rèn)為習(xí)慣使用一種即可,不然易混淆。
應(yīng)用場(chǎng)景
我司喜好做 “固定模板” 需求:運(yùn)營(yíng)同學(xué)會(huì)將一張圖片裁切成 n 個(gè)區(qū)域,點(diǎn)擊每一區(qū)域的行為有所不同。比如一張美女的面部圖,點(diǎn)擊其眼睛時(shí)會(huì)推薦一些雙眼皮項(xiàng)目,點(diǎn)擊其鼻子時(shí)會(huì)推薦一些鼻綜合項(xiàng)目等等(我司是做微整形交易平臺(tái)的)。
區(qū)域劃分是有一定規(guī)則的,如下圖:當(dāng)前行僅含一張圖片時(shí)圖片寬度為 100%,兩張時(shí)為 50%,... n 張時(shí)為 (100 / n)%。

相關(guān)代碼:
%clear-float {
&:after {
content: "";
display: block;
height: 0;
clear: both;
visibility: hidden;
}
}
%adapt-image {
display: block;
width: 100%;
}
%static-template {
div {
@extend %clear-float;
a {
float: left;
img {
@extend %adapt-image;
}
}
}
@for $itemCount from 1 through 3 {
.count#{$itemCount} {
a {
width: 100%/$itemCount;
}
}
}
}
section.static-template {
@extend %static-template;
}
解析后的 css 代碼:
section.static-template div:after {
content: "";
display: block;
height: 0;
clear: both;
visibility: hidden;
}
section.static-template div a img {
display: block;
width: 100%;
}
section.static-template div a {
float: left;
}
section.static-template .count1 a {
width: 100%;
}
section.static-template .count2 a {
width: 50%;
}
section.static-template .count3 a {
width: 33.33333333%;
}
上述其實(shí)是 多列布局 的一個(gè)實(shí)例,多列布局的應(yīng)用很廣泛,比如導(dǎo)航欄:

@each
each 可循環(huán)遍歷兩種數(shù)據(jù)類型:
@each $var in list
@each $var in map
具體實(shí)例請(qǐng)向上翻至 多值變量 。
2017/11/06 續(xù)更
Sass 安裝
Sass 依賴于 Ruby 環(huán)境,若未安裝 Ruby 請(qǐng)移駕此處下載。安裝過(guò)程請(qǐng)勾選 Add Ruby executables to your PATH 確保添加環(huán)境變量。
若你具備翻墻技能請(qǐng)直接:
gem install sass
下面介紹如何不翻墻安裝 Sass:
配置 gem sources
# 移除 https://rubygems.org/
gem sources --remove https://rubygems.org/
# 添加 https://gems.ruby-china.org/
gem sources -a https://gems.ruby-china.org/
# 查看 sources 確保僅有 https://gems.ruby-china.org/
gem sources -l
下載 sass.gem
安裝 sass.gem
gem install [sass.gem 路徑]/sass.gem
作者:呆戀小喵
相關(guān)文章:通過(guò) sass-resources-loader 全局注冊(cè) Sass 變量
我的后花園:https://sunmengyuan.github.io/garden/
我的 github:https://github.com/sunmengyuan
原文鏈接:https://sunmengyuan.github.io/garden/2017/05/17/sass-application.html