這算是 element 源碼學(xué)習(xí)的番外篇旅急,因為 element 中使用了大量 sass 來寫樣式逢勾。而 UI 框架的核心其實就是樣式。所以坠非,抽空把 sass 學(xué)了一遍,寫了些小 demo 實踐果正,總結(jié)成此文炎码。
SASS 安裝和調(diào)試
簡單說下 sass 如何安裝和編譯調(diào)試。
參照官網(wǎng)秋泳,需要使用 gem 來安裝 sass潦闲。如果是windows用戶沒有 gem 需要先安裝 Ruby
$ gem install sass
如果有權(quán)限問題,需要加上 sudo
迫皱。
$ sudo gem install sass
最后歉闰,通過查詢 sass 版本號驗證是否安裝成功。
$ sass -v
編譯命令很簡單卓起,在項目目錄下編譯選中 .scss
和敬、.sass
文件即可。
$ sass hello.scss hello.css
如果是學(xué)習(xí) sass 這一個命令足矣戏阅,其他命令可參考sass 編譯
語法簡述
下面我用自己對 sass 語法的理解昼弟,配合上 demo 快速過一遍 sass 基礎(chǔ)語法。
sass 文件和 scss 文件區(qū)別
兩者其實都是 sass 可以識別的文件奕筐,唯一不同點是 .sass
文件不使用大括號和分號舱痘。如下~
// .scss
$default-color: #FFAACC;
.selected {
color: $default-color;
}
// .sass
$default-color: #FFAACC
.selected
color: $default-color
// .css
.selected {
color: #FFAACC;
}
官方文檔推薦使用 .scss
文件類型寫法,避免 .sass
文件的嚴格格式要求報錯离赫。
變量
通過 $
符號來定義 sass 變量芭逝,變量在樣式內(nèi)外都可定義,用于各個樣式中渊胸。定義的變量不會在編譯后的 CSS 文件中顯示旬盯。
$default-color: #FFAACC;
$border-color: #AAFFCC;
$default-border: 1px solid $border-color;
$extra-color: #BBDD00;
.selected {
$scoped-width: 60px;
width: $scoped-width;
color: $default-color;
border: $default-border;
}
編譯結(jié)果:
.selected {
width: 60px;
color: #FFAACC;
border: 1px solid #AAFFCC; }
另外注意的一個點是在定義變量時使用的 -
和 _
的效果是一樣的。即 $border-color
和 $border_color
指向的是同一個變量翎猛。
嵌套
為了避免一些代碼的重復(fù)瓢捉,引入了代碼的嵌套“斐桑看一個例子:
.selected {
color: #FFAA22;
h1 {
color: #FFDD77
}
div {
width: 50px;
height: 20px;
span {
color: #012DD6;
}
}
&:hover {
color: #FAFAFA;
}
}
得到的結(jié)果如下:
.selected {
color: #FFAA22; }
.selected h1 {
color: #FFDD77; }
.selected div {
width: 50px;
height: 20px; }
.selected div span {
color: #012DD6; }
.selected:hover {
color: #FAFAFA; }
從中可以看到泡态,嵌套可以將需要重復(fù)寫選擇器的過程嵌套到一個表達式中了。
父選擇器標(biāo)識符 &
從上面的例子中看到有這么一段 &:hover
而在編譯結(jié)果中得到的結(jié)果是 .selected:hover
迂卢,其實 &
標(biāo)識符就代表了父級選擇器某弦。就這么簡單桐汤,不理解的時候把父級選擇題替換 &
理解下就簡單了。
嵌套css
sass 中的嵌套是可以多個樣式同時嵌套的靶壮。 用法見demo怔毛。
.container .content {
h1, h2, h3 {margin-bottom: .8em}
}
編譯結(jié)果
.container .content h1, .container .content h2, .container .content h3 {
margin-bottom: .8em; }
子組合選擇器和同層選擇器
關(guān)于 >
、+
和 ~
這三個選擇器腾降,是 CSS3 中就有的拣度。在 SASS 中同樣適用。
簡單說下三個選擇器用途(參考 CSS 選擇器):
-
div>p
選取父元素是 <div> 元素的每個 <p> 元素 -
div+p
選擇 <div> 元素之后緊跟的每個 <p> 元素 -
p~ul
選擇前面有 <p> 元素的每個 <ul> 元素螃壤。
看個官網(wǎng)的例子:
article {
~ article { border-top: 1px dashed #ccc }
> section { background: #eee }
dl > {
dt { color: #333 }
dd { color: #555 }
}
nav + & { margin-top: 0 }
}
動手編譯出的結(jié)果如下:
article ~ article {
border-top: 1px dashed #ccc; }
article > section {
background: #eee; }
article dl > dt {
color: #333; }
article dl > dd {
color: #555; }
nav + article {
margin-top: 0; }
嵌套屬性
屬性嵌套說白了就是把 margin-bottom
這類有 -
符號隔開的屬性拆分開來便于查看和編寫抗果。
nav {
border: {
style: solid;
width: 1px;
color: #ccc;
}
}
這里把 border-style
等屬性進行了拆分,結(jié)果如下:
nav {
border-style: solid;
border-width: 1px;
border-color: #ccc; }
導(dǎo)入
sass 提供了 sass 文件導(dǎo)入功能奸晴≡┝螅可以做一些基礎(chǔ)樣式的復(fù)用。用法很簡單:
// var.scss
$default-color: #AABBCC;
.focused {
color: red;
margin: 5px;
}
// h1.scss
h1 {
color: #BBDDFF;
margin: 10px;
}
// demo.scss
@import "var01";
$default-color: #FFAADD !default;
.selected {
color: $default-color;
@import "h1";
}
以上代碼中將 var.scss
和 h1.scss
兩個文件導(dǎo)入到了 demo.scss
中寄啼,最終生成結(jié)果如下:
.focused {
color: red;
margin: 5px; }
.selected {
color: #AABBCC; }
.selected h1 {
color: #BBDDFF;
margin: 10px; }
從結(jié)果來說說導(dǎo)入的幾個注意點:
- 導(dǎo)入文件使用
@import
表達式來導(dǎo)入逮光,導(dǎo)入可以是外部導(dǎo)入也可是嵌套導(dǎo)入。上面例子中var
是外部導(dǎo)入墩划,而h1
是嵌套導(dǎo)入的涕刚。 -
$default-color: #FFAADD !default;
中的!default
是定義變量默認值的方式,如果導(dǎo)入文件中有同樣的值優(yōu)先使用導(dǎo)入的值乙帮,如果導(dǎo)入文件中沒有這個值副女,使用默認值。 - sass 中的
@import
與 css 中的@import
不同蚣旱,sass 中是編譯的時候就直接導(dǎo)入生成 css 文件了碑幅,而 css 中,只有執(zhí)行到@import
時塞绿,瀏覽器才會去下載 css 文件沟涨,會導(dǎo)致頁面加載變慢。
靜默注釋
就是在 sass 是否保留注釋內(nèi)容的語法异吻。保留注釋的方式為:在CSS語法允許的地方裹赴,以 /*...*/
的方式寫注釋就能在生成的 css 文件中看到。再來看一個例子:
// 不顯示
/* 顯示 */
.selected {
//不顯示
/* 顯示 */
color: #FFAADD; // 不顯示
margin:/* 不顯示 */ 10px; /* 顯示 */
/* 顯示 */border: 1px dashed /* 不顯示 */ #ccc;
}
// 不顯示
/* 顯示 */
編譯結(jié)果正如注釋所預(yù)測的诀浪。
混合器
混合器在 element 的樣式表中用的非常多棋返,是個很強大的功能±字恚混合器以 @mixin
來導(dǎo)出混合內(nèi)容睛竣,使用 @include
來導(dǎo)入混合內(nèi)容。
基本用法
我的理解是:@mixin
類似定義變量一樣定義個混合器(編譯的時候不顯示 @mixin
的內(nèi)容)求摇,@include
獲取混合器來替換 @include xxxx
的這行內(nèi)容射沟。
// mixin.scss
@mixin rounded-corners {
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
border-radius: 5px;
div {
width: 50px;
height: 20px;
}
}
.name {
span {
color: #FFAADD;
}
}
// include.scss
@import "mixin";
.notice {
background-color: green;
border: 2px solid #00aa00;
@include rounded-corners;
}
這里在官方 demo 上加了點代碼驗證問題殊者。得到結(jié)果如下:
.name span {
color: #FFAADD; }
.notice {
background-color: green;
border: 2px solid #00aa00;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
border-radius: 5px; }
.notice div {
width: 50px;
height: 20px; }
這個demo驗證了:1. @mixin
是一個類似變量的內(nèi)容。在 @import
導(dǎo)入的內(nèi)容中只顯示了 .name
樣式验夯。 2. @include
會替換 @include xxx
這段代碼猖吴。就算 @mixin
中有各種寫法都會應(yīng)用到 @include
中,如嵌套 CSS挥转。
混合器傳參
混合器可以接收 @include
表達式傳遞的參數(shù)海蔽。而且,參數(shù)可以設(shè)置默認值绑谣。
// mixin.scss
@mixin link-colors($normal: white, $hover: white, $visited: white) {
color: $normal;
&:hover { color: $hover; }
&:visited { color: $visited; }
}
// include.scss
@import "mixin";
// 寫法一党窜,按照默認順序傳遞參數(shù)
a {
@include link-colors(blue, red, green);
}
// 寫法二,按照參數(shù)名傳遞參數(shù)
b {
@include link-colors(
$normal: blue,
$visited: green,
$hover: red
);
}
編譯結(jié)果為:
a {
color: blue; }
a:hover {
color: red; }
a:visited {
color: green; }
b {
color: blue; }
b:hover {
color: red; }
b:visited {
color: green; }
如果說 @include
中不傳遞參數(shù) @include link-colors();
域仇,那么生成結(jié)果的 color 都為默認值 white刑然。
element 中的混合
在 element 源碼中用了不少混合寺擂,有一種寫法 sass 的快速入門中沒有提到暇务。就找一個簡單的 el-card 樣式來學(xué)習(xí)下來:
@import "mixins/mixins";
@import "common/var";
@include b(card) {
border-radius: $--card-border-radius;
border: 1px solid $--card-border-color;
background-color: $--color-white;
overflow: hidden;
box-shadow: $--box-shadow-light;
color: $--color-text-primary;
@include e(header) {
padding: #{$--card-padding - 2 $--card-padding};
border-bottom: 1px solid $--card-border-color;
box-sizing: border-box;
}
@include e(body) {
padding: $--card-padding;
}
}
從中可以看到所有的屬性都是使用了 @include
方式進行混合的。最終生成的 CSS 文件如下:
.el-card {
border-radius: 4px;
border: 1px solid #ebeef5;
background-color: #fff;
overflow: hidden;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
color: #303133; }
.el-card__header {
padding: 18px 20px;
border-bottom: 1px solid #ebeef5;
box-sizing: border-box; }
.el-card__body {
padding: 20px; }
先看下導(dǎo)入怔软,其中 var
文件是項目樣式變量統(tǒng)一保存的地方垦细;mixin
文件用于混合;再加上幾個 @include
表達式挡逼,答案一定是在 mixin
中的括改。我們就直接找到 @mixin b
和 @mixin e
兩個混合項。
@mixin b($block) {
$B: $namespace+'-'+$block !global; // 定義 B 變量:變量名 el-card
.#{$B} {
@content;
}
}
@mixin e($element) {
$E: $element !global;
$selector: &;
$currentSelector: "";
@each $unit in $element {
$currentSelector: #{$currentSelector + "." + $B + $element-separator + $unit + ","};
}
@if hitAllSpecialNestRule($selector) {
@at-root {
#{$selector} {
#{$currentSelector} {
@content;
}
}
}
} @else {
@at-root {
#{$currentSelector} {
@content;
}
}
}
}
發(fā)現(xiàn)有許多 sass 快速入門中沒有提到過的語法: @if
家坎,@else
等等嘱能,這里查閱具體文檔列出其功能:
- @if @else 這兩者和任何編程語言的 if ... else ... 的用法是一樣的,條件判斷虱疏。if 中條件為 true 進入邏輯惹骂,否則使用 else 邏輯。
- @at-root @at-root 指令導(dǎo)致一個或多個規(guī)則被限定輸出在文檔的根層級上做瞪,而不是被嵌套在其父選擇器下对粪。
- @content 樣式內(nèi)容塊可以傳遞到混入(mixin)包含樣式的位置。樣式內(nèi)容塊將出現(xiàn)在混入內(nèi)的任何 @content 指令的位置装蓬。這使得可以定義抽象 關(guān)聯(lián)到選擇器和指令的解析著拭。
- @each in 類似js用法,遍歷列表獲取每個value值牍帚。
-
#{...}
是插值語法儡遮,用于在選擇器和屬性名中使用 SassScript 變量,所以.#{$B}
表達式暗赶,如果$B
的值為 hello-world峦萎,那么表達式結(jié)果等于.hello-world
其實看完這些用法屡久,上面的代碼就很好理解了。具體關(guān)于 element 樣式學(xué)習(xí)的細節(jié)將在下篇博客中詳細學(xué)習(xí)爱榔。
繼承
個人感覺繼承就是幾個樣式類寫在一起被环。而且,繼承是可以嵌套的详幽。
.error {
border: 1px red;
background-color: #fdd;
}
.seriousError {
@extend .error;
border-width: 3px;
}
.error02 {
@extend .seriousError;
margin: 5px;
}
編譯結(jié)果為:
.error, .seriousError, .error02 {
border: 1px red;
background-color: #fdd; }
.seriousError, .error02 {
border-width: 3px; }
.error02 {
margin: 5px; }
下面引用下繼承的注意事項:
- 跟混合器相比筛欢,繼承生成的 css 代碼相對更少。因為繼承僅僅是重復(fù)選擇器唇聘,而不會重復(fù)屬性版姑,所以使用繼承往往比混合器生成的 css 體積更小。如果你非常關(guān)心你站點的速度迟郎,請牢記這一點剥险。
- 繼承遵從 css 層疊的規(guī)則。當(dāng)兩個不同的 css 規(guī)則應(yīng)用到同一個 html 元素上時宪肖,并且這兩個不同的 css 規(guī)則對同一屬性的修飾存在不同的值表制,css 層疊規(guī)則會決定應(yīng)用哪個樣式。相當(dāng)直觀:通常權(quán)重更高的選擇器勝出控乾,如果權(quán)重相同么介,定義在后邊的規(guī)則勝出。
所以蜕衡,其實繼承相比混合更簡單壤短。繼承只是選擇器的重復(fù),而混合是用一段代碼替換標(biāo)簽 @include
標(biāo)簽慨仿。
最后
由于 element 項目中使用了大量的 sass 樣式久脯,所以想了解 element 必須對 sass 有一定了解。本文簡單解決了 sass 是什么镰吆?基礎(chǔ)用法怎么用帘撰?兩個問題。更加深入的 sass 語法涉及的不多鼎姊,算是快速入門博客啦骡和。
在了解了 sass,能夠看懂 element 中的樣式表后相寇,就可以愉快的去學(xué)習(xí) element 源碼啦~
打個廣告
上海鏈家-鏈家上海研發(fā)中心需求大量前端慰于、后端、測試唤衫,需要內(nèi)推請將簡歷發(fā)送至 dingxiaojie001@ke.com婆赠。