【譯】如何更好的編寫CSS

逆圖發表於2019-02-27

原文:How to get better at writing CSS

作者:Thomas Lombart

譯者: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

輪到你了。要保持好奇人們如何可以做的更好。你必須自己去搜尋,嘗試和創造,這樣才能更好的貼合你自己的需求。

將它們合在一起

你會發現下面的一些例子充分的展示了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;
  }
}
複製程式碼
樣例1
<!--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;
    }
  }
}
複製程式碼
樣例2

【譯者注:原文是在文章中插入了codepen。為了方便閱讀,直接對輸出結果進行了截圖。有興趣的讀者可以直接訪問這兩個地址:樣例1樣例2

組織CSS檔案:7-1模式

你堅持看到這兒了?優秀! 現在讓我們看看如何組織CSS檔案。這部分將真正幫助你提高工作效率,並能夠讓你立即找到必須要修改的CSS程式碼的位置。

為此,我們將瞭解7-1模式。

你可能會想這是個什麼玩意【譯者注:711便利店?233】。

相信我,這很簡單。你只須遵守下面2條規則:

  1. 將所有的區域性檔案寫入7個不同的資料夾中。
  2. 將它們全部匯入位於根級別的一個main.scss檔案中。

就是這樣。

7個資料夾

  • base:在這裡,把所有的腳手架程式碼都放進去。通過腳手架,我指的是每次啟動一個新專案時要寫的所有CSS程式碼。例如:排版規則、動畫、公用(公用類,我指的是margin-right-largetext-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個資料夾了!

接下來,你又兩個選擇:

  1. 你希望你的CSS程式碼組織遵循7-1模式,因此你保留了abstactcomponentslayoutbase
  2. 你更喜歡有一個大資料夾,把所有的區域性檔案和你的main.scss檔案放在一起。所以你會產生以下類似的東西:
sass/
  _animations.scss
  _base.scss
  _buttons.scss
  _header.scss
  ...
  _variables.scss
  main.scss
複製程式碼

這完全取決於你自己。

你把我說服了!但是我該怎麼用呢?我的意思是,瀏覽器並不支援SCSS,不是嗎?

說的好!現在到了我們的最後一步了。我們將學習如何將SCSS檔案編譯成CSS。

從SCSS到CSS

為此,你需要先安裝Node.jsNPM(或Yarn)

我們將使用一個名為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程式碼的準備。我希望你喜歡這篇文章。如果是這樣的話,請隨時在評論中給我反饋。那麼,下次再見啦!

相關文章