原文:How to get better at writing CSS
譯者:JeLewine
廢話不多說,我們們就開門見山吧:想寫出優質的CSS程式碼將會是非常痛苦的。很多開發者都不想做CSS開發。我可以做你想做的一切,但是,除了CSS!
當我在構建應用時,CSS是我挺討厭的部分。但你無法擺脫它,對吧?我的意思是,正是因為我們如此的專注於使用者體驗和設計,所以現在我們才不能跳過這一部分。
在開始一個專案時,一切都很正常。你有一些CSS選擇器:.title
input
#app
,這看起來非常的簡單。
但是當你的應用變得越來越大時,它就開始變的越來越糟糕了。你對CSS選擇器感到困惑。你發現你寫的像div#app
.list
li.item a
諸如此類的東西,自己在一遍又一遍地在重複相同的程式碼。你把所有程式碼都放在檔案末尾,因為你根本就不在乎。CSS像一坨shit。然後你要狗帶了:500行的CSS完全沒法維護。
我今天有一個小目標:讓你更好的去編寫CSS。我想讓你回首看看自己的舊專案併發出感慨:oh,boy,我怎麼能寫這麼一坨東西?
好吧,你可能會想,你說的有道理。但是CSS框架呢?這就是他們的用法,不是嗎?這就是我們編寫好CSS程式碼的方法。
是的沒錯,不過這樣還是會有一些缺點:
- 它往往會帶來平凡的設計
- 想要定製或跳出CSS框架會變的困難
- 在使用它們之前,你必須先學習它們
不過畢竟,你已經開始在看這篇文章了。這一定是有原因的,不是嗎?所以,不用多說了,讓我們開始學習如何更好的編寫CSS吧。
注意:這不是關於如何設計優雅應用程式的文章。它是關於學習如何編寫和組織可維護的CSS程式碼的。
SCSS
在這篇文章裡我將會用SCSS作為例子。
SCSS是一個CSS的前處理器。簡單來說,它是一個CSS的超集:他為CSS新增了一些很酷的功能,例如變數,巢狀,匯入和mixins。
我將先談談我們立即會使用到哪些功能。
變數
通過SCSS,你可以使用變數了。它帶來的主要好處就是可複用性。我們假設你的應用有一組顏色。你的主色調是藍色。
所以你的應用到處都是藍色:按鈕的背景顏色,標題的顏色,連結。藍色無處不在。
突然之間,你不喜歡藍色。你更喜歡綠色了。
- 沒有變數:更改所有使用了藍色的地方
- 使用變數:只需更改變數
// 宣告變數
$primary-color: #0099ff;
// 引入變數
h1 {
color: $primary-color;
}
複製程式碼
巢狀
你還可以使用SCSS來巢狀程式碼。看一下下面的例子:
h1 {
font-size: 5rem;
color: blue;
}
h1 span {
color: green;
}
複製程式碼
可以變成下面這樣:
h1 {
font-size: 5rem;
color: blue;
span {
color: green;
}
}
複製程式碼
更具有可讀性,不是嗎?使用巢狀來編寫複雜選擇器所花費的時間更少。
區域性檔案和引入
出於可維護性和可讀性方面的考慮,我們不可能將所有程式碼儲存在一個大檔案中。在試驗或構建小型應用程式時,這麼做也許可以滿足你的需求,但在更專業的情況下…請不要這麼做。不過幸運的是,SCSS允許我們這樣做。
您可以通過使用前置下劃線命名檔案的方式來建立區域性檔案:_animations.scss
,_base.scss
,_variables.scss
等。
至於引入,我們可以使用@import
命令。例如,下面這樣是你可以做的:
// _animations.scss
@keyframes appear {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
// header.scss
@import "animations";
h1 {
animation: appear 0.5s ease-out;
}
複製程式碼
看到這裡,你可能會認為這裡是不是搞錯了。應該是_animations.scss
而不是animations
。
不。當你用這種方式命名時,scss可以很聰明的知道你正在討論一個區域性檔案。
以上就是我們所需要了解到的變數,巢狀,區域性檔案和引入。SCSS還有一些其他功能,像是mixins,繼承指令(@for
,@if
,…)之類的,不過我今天不會在這裡介紹他們了。
如果你想了解更多的資訊,可以檢視他們文件。他們寫的很不錯,非常容易理解。
【譯者注:這是scss中文文件的地址】
組織CSS程式碼:BEM方法論
我已經記不清有多少次在我的CSS課程裡用到這些名稱了。你懂的:.button
,.page-1
,.page-2
,.custom-input
。
我們其實經常不知道該如何去命名。然而這是非常重要的。如果你正在構建一個應用程式,並且由於某些原因決定將其擱置幾個月,該怎麼辦?或者更糟糕的是,如果有人要交接該專案怎麼辦?如果你的CSS程式碼沒有一個正確命名,那麼很難一目瞭然地知道你在說什麼。
BEM幫我們解決了這個問題。BEM是一種命名約定,代表著塊元素修飾符【譯者注:原文為Block Element Modifier。在中文前端圈內發現大部分文章都將block直譯為”塊”,其實譯者個人覺得翻譯為”模組”可能會讓人更好理解一點。不過本文還是選擇和已有譯法保持一致】。
這種方法可以使我們的程式碼結構化,更加模組化和可複用。現在讓我來解釋什麼是塊,元素和修飾符。
塊
我們可以把“塊”視為元件。你還記得小時候玩的樂高積木嗎?【譯者注:小時候沒玩過,現在我也玩不起…】ok,讓我們回到過去。
你會如何建造一個簡單的房子?你需要一個窗戶,一個屋頂,一扇門,一些牆壁,就是這樣。那些是我們的塊。他們各自有各自的作用。
**命名:**塊名稱:.block
樣例:.card
,.form
,.post
,.user-navigation
元素
現在,你將如何用你的樂高去搭一個窗戶呢?這發現其中也許有一些看起很像邊框,當你把四個邊框組裝在一起時,一個窗戶就搭好啦。那就是我們的元素。它們是“塊”的一部分,它們是構建“塊”的必要條件。但是,當它們離開塊時就沒有用了。
**命名:**塊名稱 + _
+ 元素名:.block_element
樣例:.post_author
,.post_date
,.post_text
修飾符
現在你已經搭起了一個窗戶,不過也許你想要的是一個綠色的或小的。這些就是修飾符。它們是“塊”或“元素”上的標誌,它們用於改變行為和表現等。
**命名:**塊名稱或元素名 + -
+ 修飾名:.block_element-modifier
, .block-modifier
樣例:.post-important
,.post_btn-disabled
一些筆記
- 當您使用BEM時,你為類命名,也只能是為類命名。沒有ID,沒有標籤。只有類。
- 塊/元素可以巢狀到其他塊/元素中,但它們必須要能完全獨立。記住這個詞:獨立。因此,請不要因為你想將按鈕放在標題下就將
margin
寫在按鈕上,否則您的按鈕將與您的標題完全繫結。請改用其他公用類來代替這個操作。 - 是的,你的HTML檔案將會過載。但不要擔心,與BEM帶給您帶來的好處相比,這是一個小小的缺點。
一個例子
下面是一個對你的小練習。轉到你最喜歡或最常用的網站,並嘗試使用BEM。
例如,下面就是我在Google商店中的想象:
輪到你了。要保持好奇人們如何可以做的更好。你必須自己去搜尋,嘗試和創造,這樣才能更好的貼合你自己的需求。
將它們合在一起
你會發現下面的一些例子充分的展示了BEM的功力。
<!--html-->
<div class="post">
<span class="post__author">Thomas</span>
<span class="post__date">3 minutes ago</span>
<p class="post__text">
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Laboriosam sit voluptatem aut quis quisquam veniam delectus sequi maxime ullam, inventore blanditiis quia commodi maiores fuga, facere quaerat doloremque in. Nisi!
</p>
</div>
<div class="post mt-large post--important">
<span class="post__author">Thomas</span>
<span class="post__date">2 hours ago</span>
<p class="post__text">
Voluptatem incidunt autem consequatur neque vitae aliquam, adipisci voluptatum. Ipsum excepturi dolores exercitationem rem ab similique consequatur nesciunt, tempora aut vel unde.
</p>
</div>
<!--SCSS-->
.post {
display: inline-block;
padding: 1rem;
background-color: #ccc;
border: 1px solid #222;
border-radius: 5px;
&--important {
background-color: yellow;
}
&__author {
font-size: 1.2rem;
font-weight: bold;
color: blue;
}
&__date {
float: right;
}
&__text {
line-height: 2rem;
font-size: 1.3rem;
}
}
複製程式碼
<!--html-->
<div>
<button class="btn">
Click me
</button>
<button class="btn btn--danger">
Danger
</button>
<button class="btn btn--success">
Success
</button>
<button class="btn btn--small">
Small
</button>
<button class="btn btn--big">
Big
</button>
<button class="btn btn--border">
Border
</button>
</div>
<!--SCSS-->
.colors {
font-size: 1.5rem;
font-family: sans-serif;
}
.btn {
background-color: #FF6B93;
color: #fff;
text-transform: uppercase;
padding: 1.5rem 2.5rem;
border-radius: 4px;
transition: all .2s;
font-size: 1.3rem;
border: none;
letter-spacing: 2px;
cursor: pointer;
&:hover {
background-color: #D15879;
}
&:focus {
outline: none;
}
&--danger {
background-color: #FF3B1A;
&:hover {
background-color: #D43116;
}
}
&--success {
background-color: #00D123;
&:hover {
background-color: #00AB1D;
}
}
&--small {
padding: 1rem 2rem;
font-size: 1rem;
}
&--big {
padding: 1.8rem 4.5rem;
font-size: 1.7rem;
}
&--border {
background-color: #fff;
color: #FF6B93;
border: 1px solid #FF6B93;
&:hover {
background-color: #FF6B93;
color: #fff;
}
}
}
複製程式碼
【譯者注:原文是在文章中插入了codepen。為了方便閱讀,直接對輸出結果進行了截圖。有興趣的讀者可以直接訪問這兩個地址:樣例1,樣例2】
組織CSS檔案:7-1模式
你堅持看到這兒了?優秀! 現在讓我們看看如何組織CSS檔案。這部分將真正幫助你提高工作效率,並能夠讓你立即找到必須要修改的CSS程式碼的位置。
為此,我們將瞭解7-1模式。
你可能會想這是個什麼玩意【譯者注:711便利店?233】。
相信我,這很簡單。你只須遵守下面2條規則:
- 將所有的區域性檔案寫入7個不同的資料夾中。
- 將它們全部匯入位於根級別的一個
main.scss
檔案中。
就是這樣。
7個資料夾
base
:在這裡,把所有的腳手架程式碼都放進去。通過腳手架,我指的是每次啟動一個新專案時要寫的所有CSS程式碼。例如:排版規則、動畫、公用(公用類,我指的是margin-right-large
,text-center
,……之類的類)。components
:這裡的名稱是明確的。此資料夾包含用於構建頁面的所有元件,如按鈕,表單,swipers,彈出視窗等。layout
:用於佈局頁面的不同部分。也就是說,頁首,頁尾,導航,自己的網格等等。pages
:你有時可能會有一個頁面會具有一些自己特定的樣式。將它們與那些通用的樣式分開,然後將它們放在pages資料夾中。themes
:如果你的應用有不同的主題(黑暗模式,管理員模式等),請將它們放在此資料夾中。abstracts
:將所有函式與變數和mixin一起放在這裡。vendors
:現在有什麼專案是沒有依賴外部庫的?在vendor資料夾中放入所有不依賴於你的檔案。你可能希望在此處新增Font Awesome檔案,Bootstrap和類似的東西。
主檔案
在這裡匯入你所有的partials。
@import abstracts/variables;
@import abstracts/functions;
@import base/reset;
@import base/typography;
@import base/utilities;
@import components/button;
@import components/form;
@import components/user-navigation;
@import layout/header;
@import layout/footer;
...
複製程式碼
是的。這看起很龐大。不過我知道你會這麼想,這種架構適用於更大的專案,而不是小的。這裡有一個適用於較小專案的版本。
首先,你不需要vendors
資料夾。只需將所有外部CSS程式碼放置在標頭檔案中的連結標籤中即可。然後你可以跳過themes
資料夾,因為你的應用可能只有一個主題。最後,你的頁面不會有很多特定的樣式,所以你也可以跳過pages
這個頁面。太好了,只剩下4個資料夾了!
接下來,你又兩個選擇:
- 你希望你的CSS程式碼組織遵循7-1模式,因此你保留了
abstact
、components
、layout
和base
。 - 你更喜歡有一個大資料夾,把所有的區域性檔案和你的
main.scss
檔案放在一起。所以你會產生以下類似的東西:
sass/
_animations.scss
_base.scss
_buttons.scss
_header.scss
...
_variables.scss
main.scss
複製程式碼
這完全取決於你自己。
你把我說服了!但是我該怎麼用呢?我的意思是,瀏覽器並不支援SCSS,不是嗎?
說的好!現在到了我們的最後一步了。我們將學習如何將SCSS檔案編譯成CSS。
從SCSS到CSS
我們將使用一個名為node-sass
的包,它能夠幫我們將.scss
檔案編譯為.css
檔案。
它的CLI(命令列介面)相當容易使用:
node-sass <input> <output> [options]
複製程式碼
node-sass
提供了多種選項,不過我們只需要兩個就夠了:
-w
: 觀察目錄或檔案。這意味著node-sass能夠觀察到程式碼中的任何更改。一旦更改發生時,它會自動編譯為CSS。 這在開發時非常有用。--output-style
:CSS檔案的輸出模式是什麼。它可以是以下值之一:nested
|expanded
|compact
|compressed
。我們將使用它來構建你的CSS檔案。
如果你是一個有好奇心的人(我希望你是,開發人員應該保持好奇!),可以到這裡檢視完整的文件。
現在我們已經知道了我們將使用哪些工具。接下來的事就非常簡單了。只要跟著下面的步驟走:
- 建立你的專案:
mkdir my-app && cd my-app
- 初始化:
npm init
- 新增
node-sass
庫:npm install node-sass --save-dev
- 建立你的資料夾,你的
index.html
和你的main.scss
檔案:
touch index.html
mkdir -p sass/{abstracts,base,components,layout} css
cd sass && touch main.scss
複製程式碼
- 修改在
package.json
中你的指令碼命令:
{
...
"scripts": {
"watch:scss": "node-sass sass/main.scss css/style.css -w",
"build:scss": "node-sass sass/main.scss css/style.css --output
style compressed"
},
...
}
複製程式碼
- 將包括那些已編譯的CSS檔案的引用連結新增到你的
index.html
檔案的head
標籤中:
<!DOCTYPE html>
<html lang=”en”>
<head>
<meta charset=”UTF-8">
<meta name=”viewport” content=”width=device-width, initial-scale=1.0">
<meta http-equiv=”X-UA-Compatible” content=”ie=edge”>
<link rel=”stylesheet” href=”css/style.css”>
<title>My app</title>
</head>
<body>
<h1 class=”heading”>My app</h1>
</body>
</html>
複製程式碼
就這樣,已經可以跑起來了!當你開始coding並在瀏覽器中開啟index.html
時,記得執行npm run watch:scss
。如果你想要壓縮你的css檔案,跑一下npm run build:scss
就好了。
新增熱更新
你可能在開發中更希望通過熱更新來提高效率,而不是每次都要手動過載index.html
檔案。
只要跟著以下幾個簡單的步驟:
- 安裝
live-server
包:npm install -g live-server
。注意:這是一個全域性包 - 新增
npm-run-all
包到你的專案依賴中:npm install npm-run-all --save-dev
。它能夠讓你同時執行多個指令碼命令。 - 新增下面的命令到
package.json
中:
{
...
"scripts": {
"dev": "npm-run-all --parallel liveserver watch:scss ",
"liveserver": "live-server",
"watch:scss": "node-sass sass/main.scss css/style.css -w",
"build:scss": "node-sass sass/main.scss css/style.css --output-style compressed"
},
...
複製程式碼
現在,當你執行npm run dev
時,你可以立即看到你的修改,而且無需手動過載任何內容。太棒了,不是嗎?
不過你知道更棒的是什麼嗎?為了方便你快速上手,我為此建了一個repo。
如果你想要知道我是如何將這些技巧應用到我的專案中的,可以檢視這個repo。這裡是演示結果。我希望你可以通過這個例子擁有更深的理解。
這就是今天要說的一切!現在,你已經做好了編寫可維護,模組化和可複用的CSS程式碼的準備。我希望你喜歡這篇文章。如果是這樣的話,請隨時在評論中給我反饋。那麼,下次再見啦!