什麼是CSS預處理器?
CSS 預處理器定義了一種新的語言,其基本思想是,用一種專門的編程語言,爲 CSS 增加了一些編程的特性,將 CSS 作爲目標生成文件,然後開發者就只要使用這種語言進行編碼工作。
通俗的說,“CSS 預處理器用一種專門的編程語言,進行 Web 頁面樣式設計,然後再編譯成正常的 CSS 文件,以供項目使用。CSS 預處理器爲 CSS 增加一些編程的特性,無需考慮瀏覽器的兼容性問題”,例如你可以在 CSS 中使用變量、簡單的邏輯程序、函數等等在編程語言中的一些基本特性,可以讓 CSS 更加簡潔、適應性更強、可讀性更佳,更易於代碼的維護等諸多好處。
其它 CSS 預處理器語言:
Sass(SCSS)
LESS
Stylus
Turbine
Swithch CSS
CSS Cacheer
DT CSS
這次分享將着重爲大家介紹 CSS 預處理器中的 Sass。
什麼是Sass
Sass 官網上是這樣描述 Sass 的:
Sass 是一門高於 CSS 的元語言,它能用來清晰地、結構化地描述文件樣式,有着比普通 CSS 更加強大的功能。 Sass 能夠提供更簡潔、更優雅的語法,同時提供多種功能來創建可維護和管理的樣式表。
Sass 前世今生:
Sass 是最早的 CSS 預處理語言,有比 LESS 更爲強大的功能,不過其一開始的縮進式語法(Sass 老版本語法,後面課程會詳細介紹 )並不能被大衆接受,不過由於其強大的功能和 Ruby on Rails 的大力推動,還是有很多開發者選擇了 Sass。
Sass 是採用 Ruby 語言編寫的一款 CSS 預處理語言,它誕生於2007年,是最大的成熟的 CSS 預處理語言。最初它是爲了配合 HAML(一種縮進式 HTML 預編譯器)而設計的,因此有着和 HTML 一樣的縮進式風格。
爲什麼早期不如 LESS 普及?
雖然縮進式風格可以有效縮減代碼量,強制規範編碼風格,但它一方面並不爲大多數程序接受,另一方面無法兼容已有的 CSS 代碼。這也是 Sass 雖然出現得最早,但遠不如 LESS 普及的原因。
Sass 和 SCSS 有什麼區別
Sass 和 SCSS 其實是同一種東西,我們平時都稱之爲 Sass,兩者之間不同之處有以下兩點:
- 文件擴展名不同,Sass 是以“.sass”後綴爲擴展名,而 SCSS 是以“.scss”後綴爲擴展名
- 語法書寫方式不同,Sass 是以嚴格的縮進式語法規則來書寫,不帶大括號( {} )和分號( ; ),而 SCSS 的語法書寫和我們的 CSS 語法書寫方式非常類似。
先來看一個示例:
Sass語法:
$font-stack: Helevetica, sans-serif //定義變量
$primary-color: #333 //定義變量
body
font: 100/5 $font-stack
color: $primary-color
SCSS語法
$font-stack: Helevetica, sans-serif
$primary-color: #333
body {
font: 100/5 $font-stack
color: $primary-color
}
編譯出來的CSS
body{
font: 100% Helvetica, sans-serif;
color: #333
}
Sass/SCSS 和純 CSS 寫法差很多嗎?
寫法差很多嗎?這是很多初學者會問的一個問題。那麼藉此機會簡單瞭解一下。
Sass 和 CSS 寫法有差別:
Sass 和 CSS 寫法的確存在一定的差異,由於 Sass 是基於 Ruby 寫出來,所以其延續了 Ruby 的書寫規範。在書寫 Sass 時不帶有大括號和分號,其主要是依靠嚴格的縮進方式來控制的
SCSS和CSS寫法無差別:
SCSS和CSS寫法無差別,這也是Sass後來越來越受大衆喜歡的原因之一。簡單點說,把你現有的“.css”文件直接修改成“.scss”即可使用。
注意:“.sass”只能使用Sass老語法規則(縮進規則),“.scss”使用的是Sass的新語法規則,也就是SCSS語法規則(類似CSS語法規則)
Sass聲明變量
在有些編程語言中,聲明變量都是使用關鍵詞“var”開頭,但是在Sass不使用這個關鍵詞,而是使用大家都喜歡的美元符號“$”開頭。
$width: 300px;
$爲變量聲明符,width爲變量名稱,300爲變量值。- 如果在聲明變量後面加上
!default
則表示默認值。
定義之後就可以在全局範圍內使用:
普通變量:
$fontSize: 12px;
body{
font-size:$fontSize;
}
編譯後的代碼:
body{
font-size:12px;
}
默認變量:
sass 的默認變量僅需要在值後面加上 !default 即可。
$baseLineHeight:1.5 !default;
body{
line-height: $baseLineHeight;
}
編譯後的CSS代碼:
body{
line-height:1.5;
}
sass 的默認變量一般是用來設置默認值,然後根據需求來覆蓋的,覆蓋的方式也很簡單,只需要在默認變量之前重新聲明下變量即可。
$baseLineHeight: 2;
$baseLineHeight: 1.5 !default;
body{
line-height: $baseLineHeight;
}
編譯後的css代碼:
body{
line-height:2;
}
變量的調用
在 Sass 中聲明瞭變量之後,就可以在需要的地方調用變量。調用變量的方法也非常的簡單。
比如在定義了變量
$brand-primary : darken(#428bca, 6.5%) !default; // #337ab7
$btn-primary-color: #fff !default;
$btn-primary-bg : $brand-primary !default;
$btn-primary-border : darken($btn-primary-bg, 5%) !default;
在按鈕 button 中調用,可以按下面的方式調用
.btn-primary {
background-color: $btn-primary-bg;
color: $btn-primary-color;
border: 1px solid $btn-primary-border;
}
編譯出來的CSS:
.btn-primary {
background-color: #337ab7;
color: #fff;
border: 1px solid #2e6da4;
}
全局變量和局部變量
Sass 中變量的作用域在過去幾年已經發生了一些改變。直到最近,規則集和其他範圍內聲明變量的作用域才默認爲本地。如果已經存在同名的全局變量,從 3.4 版本開始,Sass 已經可以正確處理作用域的概念,並通過創建一個新的局部變量來代替。
先來看一下代碼例子:
//SCSS
$color: orange !default; //定義全局變量(在選擇器、函數、混合宏...的外面定義的變量爲全局變量)
.block {
color: $color; //調用全局變量
}
em {
$color: red; //定義局部變量
a {
color: $color; //調用局部變量
}
}
span {
color: $color; //調用全局變量
}
css 的結果:
//CSS
.block {
color: orange;
}
em a {
color: red;
}
span {
color: orange;
}
全局變量的影子
當在局部範圍(選擇器內、函數內、混合宏內…)聲明一個已經存在於全局範圍內的變量時,局部變量就成爲了全局變量的影子。基本上,局部變量只會在局部範圍內覆蓋全局變量。
上面例子中的 em 選擇器內的變量 $color 就是一個全局變量的影子。
//SCSS
$color: orange !default;//定義全局變量
.block {
color: $color;//調用全局變量
}
em {
$color: red;//定義局部變量(全局變量 $color 的影子)
a {
color: $color;//調用局部變量
}
}
什麼時候聲明變量?
我的建議,創建變量只適用於感覺確有必要的情況下。只有滿足所有下述標準時方可創建新變量:
- 該值至少重複出現了兩次
- 該值至少可能會被更新一次
基本上,沒有理由聲明一個永遠不需要更新或者只在單一地方使用變量。
Sass的加減乘除運算:
程序中的運算是常見的一件事情,但在 CSS 中能做運算的,到目前爲止僅有 calc() 函數可行。但在 Sass 中,運算只是其基本特性之一。在 Sass 中可以做各種數學計算。
加法
加法運算是 Sass 中運算中的一種,在變量或屬性中都可以做加法運算。如:
.box {
width: 20px + 8in;
}
編譯出來的 CSS:
.box {
width: 788px;
}
但對於攜帶不同類型的單位時,在 Sass 中計算會報錯,如下例所示:
.box {
width: 20px + 1em;
}
減法
Sass 的減法運算和加法運算類似,我們通過一個簡單的示例來做闡述:
$full-width: 960px;
$sidebar-width: 200px;
.content {
width: $full-width - $sidebar-width;
}
編譯出來的 CSS 如下:
.content {
width: 760px;
}
同樣的,運算時碰到不同類型的單位時,編譯也會報錯,如:
$full-width: 960px;
.content {
width: $full-width - 1em;
}
編譯的時候,編譯器報“Incompatible units: ‘em’ and ‘px’.”錯誤。
乘法
Sass 中的乘法運算和前面介紹的加法與減法運算還略有不同。雖然他也能夠支持多種單位(比如 em ,px , %),但當一個單位同時聲明兩個值時會有問題。比如下面的示例:
.box {
width:10px * 2px;
}
編譯的時候報“20px*px isn’t a valid CSS value.”錯誤信息。
如果進行乘法運算時,兩個值單位相同時,只需要爲一個數值提供單位即可。上面的示例可以修改成:
.box {
width: 10px * 2;
}
編譯出來的 CSS:
.box {
width: 20px;
}
Sass 的乘法運算和加法、減法運算一樣,在運算中有不同類型的單位時,也將會報錯。如下面的示例:
.box {
width: 20px * 2em;
}
編譯時報“40em*px isn’t a valid CSS value.”錯誤信息。
除法
Sass 的乘法運算規則也適用於除法運算。不過除法運算還有一個特殊之處。衆所周知“/”符號在 CSS 中已做爲一種符號使用。因此在 Sass 中做除法運算時,直接使用“/”符號做爲除號時,將不會生效,編譯時既得不到我們需要的效果,也不會報錯。一起先來看一個簡單的示例:
.box {
width: 100px / 2;
}
編譯出來的 CSS 如下:
.box {
width: 100px / 2;
}
這樣的結果對於大家來說沒有任何意義。要修正這個問題,只需要給運算的外面添加一個小括號( )即可:
.box {
width: (100px / 2);
}
編譯出來的 CSS 如下:
.box {
width: 50px;
}
除了上面情況帶有小括號,“/”符號會當作除法運算符之外,如果“/”符號在已有的數學表達式中時,也會被認作除法符號。如下面示例:
.box {
width: 100px / 2 + 2in;
}
編譯出來的CSS:
.box {
width: 242px;
}
另外,在 Sass 除法運算中,當用變量進行除法運算時,“/”符號也會自動被識別成除法,如下例所示:
$width: 1000px;
$nums: 10;
.item {
width: $width / 10;
}
.list {
width: $width / $nums;
}
編譯出來的CSS:
.item {
width: 100px;
}
.list {
width: 100px;
}
綜合上述,”/ ”符號被當作除法運算符時有以下幾種情況:
-
如果數值或它的任意部分是存儲在一個變量中或是函數的返回值。
-
如果數值被圓括號包圍。
-
如果數值是另一個數學表達式的一部分。
如下所示:
//SCSS
p {
font: 10px/8px; // 純 CSS,不是除法運算
$width: 1000px;
width: $width/2; // 使用了變量,是除法運算
width: round(1.5)/2; // 使用了函數,是除法運算
height: (500px/2); // 使用了圓括號,是除法運算
margin-left: 5px + 8px/2px; // 使用了加(+)號,是除法運算
}
編譯出來的CSS
p {
font: 10px/8px;
width: 500px;
height: 250px;
margin-left: 9px;
}
Sass 的除法運算還有一個情況。我們先回憶一下,在乘法運算時,如果兩個值帶有相同單位時,做乘法運算時,出來的結果並不是我們需要的結果。但在除法運算時,如果兩個值帶有相同的單位值時,除法運算之後會得到一個不帶單位的數值。如下所示:
.box {
width: (1000px / 100px);
}
編譯出來的CSS如下:
.box {
width: 10;
}
變量運算
在 Sass 中除了可以使用數值進行運算之外,還可以使用變量進行計算,其實在前面章節的示例中也或多或少的向大家展示了。在 Sass 中使用變量進行計算,這使得 Sass 的數學運算功能變得更加實用。一起來看一個簡單的示例:
$content-width: 720px;
$sidebar-width: 220px;
$gutter: 20px;
.container {
width: $content-width + $sidebar-width + $gutter;
margin: 0 auto;
}
編譯出來的CSS
.container {
width: 960px;
margin: 0 auto;
Sass的嵌套功能
Sass 中還提供了選擇器嵌套功能,但這也並不意味着你在 Sass 中的嵌套是無節制的,因爲你嵌套的層級越深,編譯出來的 CSS 代碼的選擇器層級將越深,這往往是大家不願意看到的一點。這個特性現在正被衆多開發者濫用。
選擇器嵌套爲樣式表的作者提供了一個通過局部選擇器相互嵌套實現全局選擇的方法,Sass 的嵌套分爲三種:
選擇器嵌套、屬性嵌套和僞類嵌套
選擇器嵌套
假設我們有一段這樣的結構:
<header>
<nav>
<a href=“##”>Home</a>
<a href=“##”>About</a>
<a href=“##”>Blog</a>
</nav>
<header>
想選中 header 中的 a 標籤,在寫 CSS 會這樣寫:
nav a {
color:red;
}
header nav a {
color:green;
}
那麼在 Sass 中,就可以使用選擇器的嵌套來實現:
nav {
a {
color: red;
header & {
color:green;
}
}
}
屬性嵌套
假設我們有一段這樣的結構:
<header>
<nav>
<a href=“##”>Home</a>
<a href=“##”>About</a>
<a href=“##”>Blog</a>
</nav>
<header>
想選中 header 中的 a 標籤,在寫 CSS 會這樣寫:
nav a {
color:red;
}
header nav a {
color:green;
}
那麼在 Sass 中,就可以使用選擇器的嵌套來實現:
nav {
a {
color: red;
header & {
color:green;
}
}
}
僞類嵌套
其實僞類嵌套和屬性嵌套非常類似,只不過他需要藉助&
符號一起配合使用。我們就拿經典的“clearfix”爲例吧:
.clearfix{
&:before,
&:after {
content:"";
display: table;
}
&:after {
clear:both;
overflow: hidden;
}
}
編譯出來的 CSS:
clearfix:before, .clearfix:after {
content: "";
display: table;
}
.clearfix:after {
clear: both;
overflow: hidden;
}
混合宏
如果你的整個網站中有幾處小樣式類似,比如顏色,字體等,在 Sass 可以使用變量來統一處理,那麼這種選擇還是不錯的。但當你的樣式變得越來越複雜,需要重複使用大段的樣式時,使用變量就無法達到我們目了。這個時候 Sass 中的混合宏就會變得非常有意義。
聲明混合宏
-
不帶參數混合宏:
在 Sass 中,使用“@mixin”來聲明一個混合宏。如:
@mixin border-radius{
-webkit-border-radius: 5px;
border-radius: 5px;
}
其中 @mixin 是用來聲明混合宏的關鍵詞,有點類似 CSS 中的 @media、@font-face 一樣。border-radius 是混合宏的名稱。大括號裏面是複用的樣式代碼。
-
帶參數混合宏:
除了聲明一個不帶參數的混合宏之外,還可以在定義混合宏時帶有參數,如:
@mixin border-radius($radius:5px){
-webkit-border-radius: $radius;
border-radius: $radius;
}
-
複雜的混合宏:
上面是一個簡單的定義混合宏的方法,當然, Sass 中的混合宏還提供更爲複雜的,你可以在大括號裏面寫上帶有邏輯關係,幫助更好的做你想做的事情,如:
@mixin box-shadow($shadow...) {
@if length($shadow) >= 1 {
@include prefixer(box-shadow, $shadow);
} @else{
$shadow:0 0 4px rgba(0,0,0,.3);
@include prefixer(box-shadow, $shadow);
}
}
這個 box-shadow 的混合宏,帶有多個參數,這個時候可以使用“ … ”來替代。簡單的解釋一下,當 $shadow 的參數數量值大於或等於“ 1 ”時,表示有多個陰影值,反之調用默認的參數值“ 0 0 4px rgba(0,0,0,.3) ”。
調用混合宏
在 Sass 中通過 @mixin 關鍵詞聲明瞭一個混合宏,那麼在實際調用中,其匹配了一個關鍵詞“@include”來調用聲明好的混合宏。例如在你的樣式中定義了一個圓角的混合宏“border-radius”:
@mixin border-radius{
-webkit-border-radius: 3px;
border-radius: 3px;
}
在一個按鈕中要調用定義好的混合宏“border-radius”,可以這樣使用:
button {
@include border-radius;
}
這個時候編譯出來的 CSS:
button {
-webkit-border-radius: 3px;
border-radius: 3px;
}
混合宏的參數–傳一個不帶值的參數
在混合宏中,可以傳一個不帶任何值的參數,比如:
@mixin border-radius($radius){
-webkit-border-radius: $radius;
border-radius: $radius;
}
在混合宏“border-radius”中定義了一個不帶任何值的參數“$radius”。
在調用的時候可以給這個混合宏傳一個參數值:
.box {
@include border-radius(3px);
}
這裏表示給混合宏傳遞了一個“border-radius”的值爲“3px”。
編譯出來的 CSS:
.box {
-webkit-border-radius: 3px;
border-radius: 3px;
}
混合宏的參數–傳一個帶值的參數
在 Sass 的混合宏中,還可以給混合宏的參數傳一個默認值,例如:
@mixin border-radius($radius:3px){
-webkit-border-radius: $radius;
border-radius: $radius;
}
在混合宏“border-radius”傳了一個參數“$radius”,而且給這個參數賦予了一個默認值“3px”。
在調用類似這樣的混合宏時,會多有一個機會,假設你的頁面中的圓角很多地方都是“3px”的圓角,那麼這個時候只需要調用默認的混合宏“border-radius”:
.btn {
@include border-radius;
}
編譯出來的 CSS:
.btn {
-webkit-border-radius: 3px;
border-radius: 3px;
}
但有的時候,頁面中有些元素的圓角值不一樣,那麼可以隨機給混合宏傳值,如:
.box {
@include border-radius(50%);
}
編譯出來的 CSS:
.box {
-webkit-border-radius: 50%;
border-radius: 50%;
}
混合宏的參數–傳多個參數
Sass 混合宏除了能傳一個參數之外,還可以傳多個參數,如:
@mixin center($width,$height){
width: $width;
height: $height;
position: absolute;
top: 50%;
left: 50%;
margin-top: -($height) / 2;
margin-left: -($width) / 2;
}
在混合宏“center”就傳了多個參數。在實際調用和其調用其他混合宏是一樣的:
.box-center {
@include center(500px,300px);
}
編譯出來 CSS:
.box-center {
width: 500px;
height: 300px;
position: absolute;
top: 50%;
left: 50%;
margin-top: -150px;
margin-left: -250px;
}
有一個特別的參數“…”。當混合宏傳的參數過多之時,可以使用參數來替代,如:
@mixin box-shadow($shadows...){
@if length($shadows) >= 1 {
-webkit-box-shadow: $shadows;
box-shadow: $shadows;
} @else {
$shadows: 0 0 2px rgba(#000,.25);
-webkit-box-shadow: $shadow;
box-shadow: $shadow;
}
}
在實際調用中:
.box {
@include box-shadow(0 0 1px rgba(#000,.5),0 0 2px rgba(#000,.2));
}
編譯出來的CSS:
.box {
-webkit-box-shadow: 0 0 1px rgba(0, 0, 0, 0.5), 0 0 2px rgba(0, 0, 0, 0.2);
box-shadow: 0 0 1px rgba(0, 0, 0, 0.5), 0 0 2px rgba(0, 0, 0, 0.2);
}