這算是 element 源碼學習的番外篇,由於 element 中使用了大量 sass 來寫樣式。而 UI 框架的核心其實就是樣式。因此,抽空把 sass 學了一遍,寫了些小 demo 實踐,總結成此文。
簡單說下 sass 如何安裝和編譯調試。
參照官網,須要使用 gem 來安裝 sass。若是是windows用戶沒有 gem 須要先安裝 Rubycss
$ gem install sass
若是有權限問題,須要加上 sudo
。html
$ sudo gem install sass
最後,經過查詢 sass 版本號驗證是否安裝成功。web
$ sass -v
編譯命令很簡單,在項目目錄下編譯選中 .scss
、.sass
文件便可。shell
$ sass hello.scss hello.css
若是是學習 sass 這一個命令足矣,其餘命令可參考sass 編譯編程
下面我用本身對 sass 語法的理解,配合上 demo 快速過一遍 sass 基礎語法。windows
二者其實都是 sass 能夠識別的文件,惟一不一樣點是 .sass
文件不使用大括號和分號。以下~瀏覽器
// .scss $default-color: #FFAACC; .selected { color: $default-color; } // .sass $default-color: #FFAACC .selected color: $default-color // .css .selected { color: #FFAACC; }
官方文檔推薦使用 .scs
s 文件類型寫法,避免 .sass
文件的嚴格格式要求報錯。sass
經過 $
符號來定義 sass 變量,變量在樣式內外均可定義,用於各個樣式中。定義的變量不會在編譯後的 CSS 文件中顯示。ruby
$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; }
編譯結果:框架
.selected { width: 60px; color: #FFAACC; border: 1px solid #AAFFCC; }
另外注意的一個點是在定義變量時使用的 -
和 _
的效果是同樣的。即 $border-color
和 $border_color
指向的是同一個變量。
爲了不一些代碼的重複,引入了代碼的嵌套。看一個例子:
.selected { color: #FFAA22; h1 { color: #FFDD77 } div { width: 50px; height: 20px; span { color: #012DD6; } } &:hover { color: #FAFAFA; } }
獲得的結果以下:
.selected { color: #FFAA22; } .selected h1 { color: #FFDD77; } .selected div { width: 50px; height: 20px; } .selected div span { color: #012DD6; } .selected:hover { color: #FAFAFA; }
從中能夠看到,嵌套能夠將須要重複寫選擇器的過程嵌套到一個表達式中了。
從上面的例子中看到有這麼一段 &:hover
而在編譯結果中獲得的結果是 .selected:hover
,其實 &
標識符就表明了父級選擇器。就這麼簡單,不理解的時候把父級選擇題替換 &
理解下就簡單了。
sass 中的嵌套是能夠多個樣式同時嵌套的。 用法見demo。
.container .content { h1, h2, h3 {margin-bottom: .8em} }
編譯結果
.container .content h1, .container .content h2, .container .content h3 { margin-bottom: .8em; }
關於 >
、+
和 ~
這三個選擇器,是 CSS3 中就有的。在 SASS 中一樣適用。
簡單說下三個選擇器用途(參考 CSS 選擇器):
div>p
選取父元素是 <div> 元素的每一個 <p> 元素div+p
選擇 <div> 元素以後緊跟的每一個 <p> 元素p~ul
選擇前面有 <p> 元素的每一個 <ul> 元素。看個官網的例子:
article { ~ article { border-top: 1px dashed #ccc } > section { background: #eee } dl > { dt { color: #333 } dd { color: #555 } } nav + & { margin-top: 0 } }
動手編譯出的結果以下:
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
等屬性進行了拆分,結果以下:
nav { border-style: solid; border-width: 1px; border-color: #ccc; }
sass 提供了 sass 文件導入功能。能夠作一些基礎樣式的複用。用法很簡單:
// 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
兩個文件導入到了 demo.scss
中,最終生成結果以下:
.focused { color: red; margin: 5px; } .selected { color: #AABBCC; } .selected h1 { color: #BBDDFF; margin: 10px; }
從結果來講說導入的幾個注意點:
@import
表達式來導入,導入能夠是外部導入也但是嵌套導入。上面例子中 var
是外部導入,而 h1
是嵌套導入的。$default-color: #FFAADD !default;
中的 !default
是定義變量默認值的方式,若是導入文件中有一樣的值優先使用導入的值,若是導入文件中沒有這個值,使用默認值。@import
與 css 中的 @import
不一樣,sass 中是編譯的時候就直接導入生成 css 文件了,而 css 中,只有執行到 @import
時,瀏覽器纔會去下載 css 文件,會致使頁面加載變慢。就是在 sass 是否保留註釋內容的語法。保留註釋的方式爲:在CSS語法容許的地方,以 /*...*/
的方式寫註釋就能在生成的 css 文件中看到。再來看一個例子:
// 不顯示 /* 顯示 */ .selected { //不顯示 /* 顯示 */ color: #FFAADD; // 不顯示 margin:/* 不顯示 */ 10px; /* 顯示 */ /* 顯示 */border: 1px dashed /* 不顯示 */ #ccc; } // 不顯示 /* 顯示 */
編譯結果正如註釋所預測的。
混合器在 element 的樣式表中用的很是多,是個很強大的功能。混合器以 @mixin
來導出混合內容,使用 @include
來導入混合內容。
個人理解是:@mixin
相似定義變量同樣定義個混合器(編譯的時候不顯示 @mixin
的內容),@include
獲取混合器來替換 @include xxxx
的這行內容。
// 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 上加了點代碼驗證問題。獲得結果以下:
.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
是一個相似變量的內容。在 @import
導入的內容中只顯示了 .name
樣式。 2. @include
會替換 @include xxx
這段代碼。就算 @mixin
中有各類寫法都會應用到 @include
中,如嵌套 CSS。
混合器能夠接收 @include
表達式傳遞的參數。並且,參數能夠設置默認值。
// mixin.scss @mixin link-colors($normal: white, $hover: white, $visited: white) { color: $normal; &:hover { color: $hover; } &:visited { color: $visited; } } // include.scss @import "mixin"; // 寫法一,按照默認順序傳遞參數 a { @include link-colors(blue, red, green); } // 寫法二,按照參數名傳遞參數 b { @include link-colors( $normal: blue, $visited: green, $hover: red ); }
編譯結果爲:
a { color: blue; } a:hover { color: red; } a:visited { color: green; } b { color: blue; } b:hover { color: red; } b:visited { color: green; }
若是說 @include
中不傳遞參數 @include link-colors();
,那麼生成結果的 color 都爲默認值 white。
在 element 源碼中用了很多混合,有一種寫法 sass 的快速入門中沒有提到。就找一個簡單的 el-card 樣式來學習下來:
@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; }
先看下導入,其中 var
文件是項目樣式變量統一保存的地方;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; } } } }
發現有許多 sass 快速入門中沒有提到過的語法: @if
,@else
等等,這裏查閱具體文檔列出其功能:
#{...}
是插值語法,用於在選擇器和屬性名中使用 SassScript 變量,因此 .#{$B}
表達式,若是 $B
的值爲 hello-world,那麼表達式結果等於 .hello-world
其實看完這些用法,上面的代碼就很好理解了。具體關於 element 樣式學習的細節將在下篇博客中詳細學習。
我的感受繼承就是幾個樣式類寫在一塊兒。並且,繼承是能夠嵌套的。
.error { border: 1px red; background-color: #fdd; } .seriousError { @extend .error; border-width: 3px; } .error02 { @extend .seriousError; margin: 5px; }
編譯結果爲:
.error, .seriousError, .error02 { border: 1px red; background-color: #fdd; } .seriousError, .error02 { border-width: 3px; } .error02 { margin: 5px; }
下面引用下繼承的注意事項:
- 跟混合器相比,繼承生成的 css 代碼相對更少。由於繼承僅僅是重複選擇器,而不會重複屬性,因此使用繼承每每比混合器生成的 css 體積更小。若是你很是關心你站點的速度,請牢記這一點。
- 繼承聽從 css 層疊的規則。當兩個不一樣的 css 規則應用到同一個 html 元素上時,而且這兩個不一樣的 css 規則對同一屬性的修飾存在不一樣的值,css 層疊規則會決定應用哪一個樣式。至關直觀:一般權重更高的選擇器勝出,若是權重相同,定義在後邊的規則勝出。
因此,其實繼承相比混合更簡單。繼承只是選擇器的重複,而混合是用一段代碼替換標籤 @include
標籤。
因爲 element 項目中使用了大量的 sass 樣式,因此想了解 element 必須對 sass 有必定了解。本文簡單解決了 sass 是什麼?基礎用法怎麼用?兩個問題。更加深刻的 sass 語法涉及的很少,算是快速入門博客啦。在瞭解了 sass,可以看懂 element 中的樣式表後,就能夠愉快的去學習 element 源碼啦~