[譯] 關於現代 Web 應用程序樣式的探討

關於現代 Web 應用程序樣式的探討

歡迎你和咱們一塊兒經過本文深度探索現代應用中樣式的不一樣組織方法,這些不一樣的方法一般會包含複雜的接口和設計模式。咱們將會一塊兒探討 BEM(Block Element Modfier,塊元素編輯器)、預處理器、CSS-in-JS(即在組件內部使用 JavaScript 對 CSS 進行了抽象,能夠對其聲明和加以維護。) 甚至是設計系統,而後找出更適合你的方案。css


若是你在搜尋如何爲網絡應用編寫樣式,通常你會瀏覽不少不一樣的方法和庫,這其中有一些甚至會更新很是快。包括塊級元素修飾符(BEM);譬如 Less 和 SCSS 這樣的預處理器;CSS-in-JS 庫,包括 JSS 和 styled-components;以及最近出現的設計系統。你會在不一樣的文章、博客、教程、討論,固然還有 Twitter 上的爭論中瀏覽這些內容。html

那麼你如何在這之中作出選擇呢?爲何會存在這麼多種不一樣的方法?若是你已經熟悉適應了一種方法,爲何還要考慮遷移到其餘的方法呢?前端

在本篇文章中,我會帶你一塊兒瞭解我曾使用於生產環境應用的工具,以及我搭建的網站,我會根據個人實際經歷,對比不一樣方法的特性,而不是單純的總結這些方法的 readme 文件。我這趟關於樣式的旅行途徑 BEM、SCSS、styled-components 和最特別的設計系統;可是注意,即便你使用的是不一樣的庫,但它們萬變不離其宗,基本的原則和方法都是同樣的。android

過去的 CSS

當網站剛開始火起來的時候,CSS 只是用來爲網站添加一些時髦的設計,以此吸引用戶的眼球,就像繁華街道邊上的霓虹燈廣告牌:ios

左側是 Microsoft 的第一個網站,右邊是 21 世紀早期的 MTV 網站。git

它並不用於佈局、改變大小,或者其餘咱們平常就會用 CSS 完成基本需求,只做爲一個能讓網站更好看而且顯眼的可選項。但隨着 CSS 加入了更多的特性,新版的瀏覽器也隨之支持更多功能和特性,然後網站標準和用戶界面也加入了進來 —— CSS 成爲了網站開發的重要部分。github

很難找到沒有至少要幾百行的自定樣式或者 CSS 框架的網站(固然至少這些網站要看上去是緊跟潮流、沒有過期的):web

Wired 的現代響應式網站,來自 InVision 的響應式網站設計實例。編程

接下來發生的事情很好猜了。用戶界面的複雜度持續增長,因此 CSS 的應用也跟着上升;可是 CSS 的書寫卻沒有任何指導,同時 CSS 又變得很複雜,因而樣式問題就變得很是複雜,讓人頭疼。開發者都有本身的一套方法來處理樣式問題,用全部這些想辦法讓網頁看上去和設計稿要求的一致。後端

這反過來致使了不少常規性的問題,而這些問題都要開發者來處理,好比在項目中管理大型團隊,或者長時間維護一個沒有清晰指導的項目。甚至是如今,這些事情發生的最主要緣由是,CSS 仍舊常常被認爲是不重要的部分,並不值得人們關注它,這是很可悲的。

CSS 並不容易掌握

當團隊負責大型項目的時候,卻並不爲 CSS 的維護和管理構建任何內容,此時團隊可能會面臨的常規問題包括:

  • 缺乏代碼結構和標準,致使可靠性大幅降低;
  • 維護成本隨項目增大而增長;
  • 因爲缺少可靠性致使的優先級問題。

若是你曾經用過 Bootstrap,你必定注意到,你是沒法覆蓋默認的樣式的,也許你也嘗試過添加 !important 或者特殊選擇器的方法來解決。想象一個超大項目的樣式表,表裏會有不少類,以及每一個元素的樣式。此時使用 Bootstrap 是個很不錯的選擇,由於它有很好的文檔,同時 它的目標就是做爲樣式框架應用。可是對於大多數項目內的樣式表而言,並不屬於這種狀況,那麼你極可能會迷失在級聯樣式中。

在不少項目中,一個文件中可能包含幾千行 CSS 代碼,若是你看到哪一個文件有註釋,那你可真是很是幸運了,由於大多數文件根本沒有。你也可能會看到不少寫在最後的 !important,來讓特定的樣式覆蓋其餘的。

!important 語法並不能拯救糟糕的 CSS 代碼。

你可能面臨一些特定的問題,可是不知道它們是如何運做的。下面讓咱們一塊兒來看一下。

假設這兩個樣式都指向右邊的圖片,它們中的哪一個會生效呢?

選擇器的權重都是多少呢?這些選擇器包括內聯樣式,ID、屬性和元素選擇器。長話短說,它們的權重排序是:

0 開始;內聯樣式能夠加 1,000;每一個 id 選擇器能夠加 100;每一個屬性或者類、僞類選擇器能夠加 10;每一個元素名選擇器或者僞元素選擇器能夠加 1

一般狀況下,這是計算以及代表哪一個樣式能夠工做的最簡單的方法,但請注意真正的表示方法應形如:(0,0,0,0)。這其中第一個數字表明內聯樣式,第二個表明 ID,以此類推。每一個選擇器均可以是大於 9 的數字,只有高權重的選擇器相等的時候,才須要對比低權重的選擇器。

舉個例子,好比上文的示例:

因此你明白爲何第二個樣式真正生效了嗎?很明顯,id 選擇器的權重要比元素選擇器高。這也就是爲何有時候你的 CSS 樣式看上去沒有生效的緣由。你能夠在 Vitaly Friedman 的文章中閱讀更多細節:「關於 CSS 權重,你應該知道的」。

代碼庫越大,類的數量也就越多。新的類可能會生效,或者基於權重原理覆蓋掉其餘樣式,因此你就可以發現隨着類的數量增多,代碼維護會變得很是困難。初次以外,和咱們使用其餘語言同樣,咱們還要處理代碼結構和可維護性。咱們可使用原子設計,組件,模版引擎等等;它們對於 CSS 也同等須要,因此咱們有不一樣的方法來解決這些問題。

塊級元素修飾符(BEM)

「BEM 是一種設計方法論,它可以幫助你在前端開發中,建立可複用的組件以及可共享的代碼。」

—— getbem.com

BEM 的核心思想是,在應用的概念以外建立能夠複用的獨立的組件。更深刻地說,它的設計過程和原子設計很相似:將事物模塊化,並將其做爲可複用的組件。

我選擇將 BEM 做爲管理樣式第一課的緣由是,它的方式和 React 很是相似(我對 React 很是熟悉了),它們都將應用分解爲能夠複用的組件。

使用 BEM

BEM 其實就是一種指導思想:它不是一個新的框架,也不是一種新的語言,它只是使用了一種命名規範的 CSS,能夠將代碼組織得更好。聽從 BEM 的方法論,你能夠在 CSS 中實現你已經使用過的模式,但倒是以更有調理的方式實現的。同時由於 BEM 不須要額外的工具配置和任何複雜的操做,你也能夠很輕鬆的爲你已經寫好的代碼庫進行漸進式的升級。

優點

  • BEM 的核心是管理可重用的組件,防止隨機全局樣式覆蓋其餘的樣式。因此最後咱們能獲得更好預測的代碼,可以解決不少因權重而覆蓋了樣式這方面的問題。
  • 學習成本不高;就是咱們熟悉的 CSS 以及幾個可以提升可維護性的指導思想。只須要使用 CSS 自己就能夠將代碼模型化,很是簡單。

缺點

  • 雖然可以提升複用性和可維護性,可是 BEM 的命名原則也有反作用,那就是會讓類的命名很是困難,消耗時間。
  • 組件嵌套層數越多,類名就越長而且難以讀懂。深層嵌套或者孫子級元素選擇器經常會面臨這樣的問題。
<div class="card__body">
  <p class="card__body__content">Lorem ipsum lorem</p>
  <div class="card__body__links">
    <!-- 孫子級元素 -->
    <a href="#" class="card__body__links__link--active">Link</a>
  </div>
</div>
複製代碼

上文內容只是對 BEM 的概覽,並簡單介紹了它是如何解決咱們在 CSS 中遇到的問題的。若是你想要更深刻的瞭解,能夠閱讀發佈在 Smashing 雜誌的文章:「BEM For Beginners」。

Sassy CSS(SCSS)

坦白說,SCSS 就是 CSS 高級版。它爲 CSS 添加了變量、嵌套選擇器、可複用的 mixin 功能,以及 import 功能,這讓 CSS 更加像一個編程語言了。於我而言,SCSS 也很容易上手(若是你尚未接觸過 SCSS,能夠看一看它的文檔),而且一旦掌握了那些附加的特性,我就很是樂意使用它們,由於它們讓代碼編寫變得很是方便。SCSS 是一個預處理器,這也就意味着編譯的結果仍是普通的 CSS 文件;你惟一須要作的就是在構建過程當中配置好編譯工具。

超級好用的特性

  • Import 功能讓你能將樣式表分解到多個文件中去,你能夠按照組件/章來分配,也能夠是其餘任何可讀性高的方法。
// main.scss
@import "_variables.scss";
@import "_mixins.scss";

@import "_global.scss";
@import "_navbar.scss";
@import "_hero.scss";
複製代碼
  • Mixin 功能循環變量 可以幫助你複用代碼,並讓書寫 CSS 的過程更加簡便。
@mixin flex-center($direction) {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: $direction;
}

.box {
  @include flex-center(row);
}
複製代碼

關於 SCSS 的 mixin 功能:在這裏能夠查看更多 SCSS 的便捷特性。

  • 嵌套選擇器大大提升了代碼的可閱讀性,由於它和 HTML 元素的結構一致了:都是嵌套的模式。這種方法可以讓你一眼看出樣式的層級關係。

SCSS 和 BEM 一塊兒使用

將不一樣組件的代碼分組到不一樣的代碼塊中是能夠實現的,SCSS 同 BEM 一塊兒使用能夠大大提升可讀性,而且能夠輕鬆編寫出 BEM。

對比於右邊的多層級代碼,左邊這段代碼相對小巧簡單得多。

若是你想深刻了解它是如何運做的,能夠讀一讀 Victor Jeman 的「BEM with Sass」教程。

Styled-Components

它是使用最普遍的 CSS-in-JS 類型倉庫之一。不吹不黑,它對我而言真的很是實用,它的不少特性都知足了個人需求。花時間搜索不一樣的庫並找到最適合你的,這真的很值得。

我認爲將 styled-components 和普通 CSS 對比來看是一個很好的學習方式。下面是如何應用 styled-components 以及它解決了什麼問題的一個概覽:

styled-components 沒有爲元素添加類,它讓每一個有類名的元素都成爲了一個組件。代碼看上去要比須要長類名的 BEM 整潔不少。

有趣的是,styled-components 的原理實際上是爲每一個指定元素添加相關的類。這實質上就是咱們在樣式表中作的事(注意這和內聯樣式無關)。

import styled from 'styled-components';
    
const Button = styled.button`
  background-color: palevioletred;
  color: papayawhip;
`;

// Output
<style>
  .dRUXBm {
    background-color: palevioletred;
    color: papayawhip;
  }
</style>

<button class="dRUXBm" />
複製代碼

styled-components 原理:在 Max Stoiber 的文章「Writing your styles in JS ≠ writing inline styles」中,你能夠閱讀更多關於內聯樣式和 CSS-in-JS 的內容。

爲何 Styled-Components 是 CSS-In-JS 中應用最爲普遍的庫之一呢?

關於樣式問題,咱們只須要用普通的 CSS 語法來使用模版庫。因此你可使用 JavaScript 的所有功能來處理樣式問題:能夠將條件、屬性做爲參數傳入(和 React 的方法相似),而且實際上這些功能也全均可以經過 JavaScript 來實現。

SCSS 有變量、mixin、嵌套以及其餘特性,而 styled-components 的功能有增無減,它變得更增強大。它的方法基本是基於組件的,因此第一眼看可能會被它嚇住,由於它和傳統的 CSS 很不同。可是一旦你熟悉了它的原則和技術,你將會意識到,全部 SCSS 能作的 styled-components 都能作到,甚至更多。而這時你只須要使用 JavaScript。

const getDimensions = size => {
  switch(size) {
    case 'small': return 32;
    case 'large': return 64;
    default: return 48;
  }
}

const Avatar = styled.img`
  border-radius: 50%;
  width: ${props => getDimensions(props.size)}px;
  height: ${props => getDimensions(props.size)}px;
`;

const AvatarComponent = ({ src }) => (
  <Avatar src={src} size="large" />
);
複製代碼

styled-components 模版庫讓你能直接使用 JS 實現不一樣條件下的樣式以及更多功能。

另外一個須要說明的是,styled-components 和當前模塊化的網頁很是完美的契合了。每一個 React 組件都有本身的功能,它可使用 JavaScript、JSX 模版,如今又有了 CSS-in-JS 來指定樣式:這個組件能夠本身實現全部的功能,在內部就能夠處理一切組件相關的事物了。

不用我提醒,這就是咱們尋找了好久的權重問題的解決方案。BEM 只是一個指導思想,強制規定了元素和樣式基於組件的結構,但它依舊有賴於類,styled-components 則增強了它。

我以爲 styled-components 的幾個附加特性很是實用:主題,它能夠配置全局屬性或者變量,這些屬性和變量能夠被傳遞到每個組件中;自動添加前綴;以及自動清理沒有使用過的代碼。另外超高的支持度和活躍的社區也只是 styled-components 衆多優點中冰山一角。

styled-components 還有不少能夠學習和應用的方面。更多內容詳見 styled-components 文檔。

特性概覽
  • 模版語言服務於 CSS 語法,和傳統 CSS 語法同樣。
  • 它強制要求代碼符合模塊化的設計
  • 經過幫你處理類名,可以解決權重的問題。
  • 全部能用 SCSS 完成的,以及更多的功能,如今均可以用 JS 實現。
可能不太適用的場景
  • 很顯然,它須要依賴 JavaScript,這也就意味着若是沒有它,樣式就不會加載,這可能致使樣式混亂。
  • 可讀性很好的類名被替換爲毫無疑義的 hash 字符串。
  • 組件的概念而不是級聯的類名可能會讓人更難以理解,尤爲是這種思惟的轉變可能對代碼安排有比較大的影響。

設計系統

隨着網頁組件的興起和對原子設計(基本思想是將 UI 打破爲基本的構建單元)的需求增長,不少公司都選擇建立組件庫和設計系統。與可以處理上述的樣式問題的技術和方法不一樣,設計系統表明了一種組織方法,可以處理整個平臺或應用中的組件和設計一致性的問題。

或許可使用咱們在設計系統中討論過的方法來管理樣式,可是設計系統自己側重於的是構建應用的單元塊而不是內部實現。

「設計系統其實是能夠應用於設計和代碼的規則、約束條件和原則們的集合。」

設計系統和組件庫都針對於跨越不一樣平臺和媒介的整個系統,並可以決定整個公司自己的前景。

「設計系統是樣式,組件和理念表達的合體。」

IBM’s Carbon design system

IBM 的 Carbon 設計系統

技術企業一旦得到了動力支持,有時候就必須很是快速的擴大規模,可是對於設計和研發團隊來講,想要跟上企業的發展速度就很是困難了。不一樣的應用、各類新的特性紛至沓來,當企業須要的時候,不斷從新評估、更改以及功能加強,這些都要儘量迅速的交付。

以一個簡單的彈窗爲例;例如,某界面包含一個確認彈窗,它很是簡單,只是接受一個用戶的確定或否認的行爲做爲參數。它的代碼來自於開發者 A。接下來,在設計團隊交付的另外一個界面上,彈窗須要包含一個帶有數個輸入框的表單 —— 開發者 B 完成這部分工做。A 和 B 的工做是分開進行的,他們並不知道對方也在開發相同的模式,因而構建出了兩個基於相同底層功能的不一樣的組件。若是不一樣的開發者都在不一樣的界面上進行開發,咱們甚至可能會看到不一樣的人提交給代碼庫的 UI 都變得不一致了。

更沒必要想,一個擁有衆多開發者和設計者的大公司會怎樣了 —— 結果確定是組件和工做流中都是不一樣的獨立的組件,而不是人們所期待的那樣具備一致性。

設計系統的主要準則就是幫助企業達成這樣的需求:構建並交付新的特性、功能甚至是所有應用,同時能維護標準、高質量、具備一致性的設計。

這裏是一些流行的設計系統的實例:

儘管設計系統自己不只僅是一個組件集合,可是當咱們專門討論樣式問題的時候,應該會對組件庫的部分更加感興趣。組件可以在內部就處理好它的功能、模版以及樣式。工做於應用級別的開發者不須要關注全部組件內部的運做,只須要知道如何在應用裏把它們組裝起來便可。

如今讓咱們想象一下,這些組件中的一些可以更進一步,它們可以被複用而且可維護性很好,而後將它們組織爲一個庫。此時開發應用就是把組件拖過去而後放下那麼簡單了(其實這麼說也並不很是確切,可是在應用中使用一個組件能夠沒必要顧慮其內部的工做)。這其實就是組件庫在作的事情。

爲何人們會想要構建設計系統

  • 如前文所述,它能幫助工程師和設計團隊跟上企業快速變化的節奏,同時維護代碼的標準和質量。
  • 它保證了全局設計和代碼的一致性,可以在長時間內至關程度地幫助你保持可維護性。
  • 設計系統最棒的特性就是它讓設計和開發團隊配合更緊密,從而讓工做協做更流暢。它將過去那種,給研發者數頁的實體模型,讓他們從頭開始研發的模式淘汰了,如今組件和組件的行爲已是通過充分定義的。這是一種徹底不一樣的方式,同時也是更好更快研發具備一致性的界面的方式。

爲何有時候對於你它並非最佳選擇

  • 設計系統須要提早投入大量的時間和精力來從頭將一切安排好 —— 代碼和設計都要很明智。除非真的須要,拖延開發進度,而先來專一於構建設計系統可能並不值得。
  • 若是項目相對比較小,實際上只須要幾個標準和指導方針就能夠保證一致性,那麼設計系統可能會增長沒必要要的複雜度,從而致使浪費。因爲不少著名的公司都採納的設計系統,這種現象可能會影響開發者,讓他們以爲這是最好的方式,而忘記了分析項目實際需求,並確認它是否是真的可行。

Different appearances of a button

按鈕的不一樣外觀

總結

樣式的應用是一個完整的世界,可是卻常常不那麼被人關注和重視。如今的應用大多有複雜的用戶交互界面,若是不考慮樣式問題,它早晚會變得一團亂,它的一致性會減弱,那麼代碼的增長和修改都會變得很困難。

總結一下咱們討論的內容:BEM,以及 SCSS 可以幫助你更好的管理樣式表,它們爲 CSS 帶來了編程的新方法,並以最少的配置建立了有意義的類名結構,使代碼更加整潔。使用像 React 或者 Vue 這樣的前端框架搭建應用,若是你以爲基於組件的方法很順手,你或許能發現,使用 CSS-in-JS 庫來處理類名問題很是方便,它將全部權重問題都解決了,而且還有數個其餘的優點。對於更大的應用和多平臺項目,你或許應該考慮結合其餘方法構建設計系統,這樣能夠加速開發速度並同時保證代碼可維護的統一性。

實質上,方法的選擇仍是要依賴於你的需求和項目的大小,花時間來決定對你來講最好的方法,這是很是重要的。

若是發現譯文存在錯誤或其餘須要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可得到相應獎勵積分。文章開頭的 本文永久連接 即爲本文在 GitHub 上的 MarkDown 連接。


掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源爲 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智能等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章
相關標籤/搜索