![]() |
VOOZH | about |
CSS 預處理器允許你使用不同的語言編寫樣式,將其轉換為瀏覽器可以理解的 CSS,這在瀏覽器實現新功能速度非常緩慢的時候是極其重要的。第一個主要的 CSS 預處理器是 2006 年發布的 Sass,它具有新型的簡潔語法(縮進代替括號、沒有分號等),並增加了 CSS 中缺少的高級功能,例如變量、輔助函數和計算。以下是使用帶變量的 Sass 的示例:
$dark-color: #4a4a4a $light-color: #f9f9f9 $side-color: #eee body color: $dark-color header, footer background-color: $dark-color color: $light-color main background: $light-color nav, aside
background: $side-color
請注意,如何使用 $ 符號定義可重用變量,並消除括號和分號,使語法更清晰簡潔。雖然 Sass 的語法簡潔是一件好事,但當時變量是革命性的功能特性,因為它們為編寫簡潔且可維護的 CSS 開闢了新的可能性。
如果使用 Sass,你需要安裝 Ruby,這是用於將 Sass 代碼編譯為常規 CSS 的程式語言。然後,你需要安裝 Sass gem,然後在命令行中運行將.sass 文件轉換為.css 文件的命令,以下是一個示例:
sass --watch index.sass index.css這個命令會將一個名為 index.sass 常規 CSS 的文件中的 Sass 代碼轉換成一個名為 index.css(在任何時候,--watch會提示它保存更改的內容,這很方便)。
這個過程稱為構建步驟,這在 2006 年可是一個重大的難題。如果你能熟練使用 Ruby 這樣的程式語言,那麼這個過程將會非常簡單。但當時許多前端開發者只使用不需任何此類工具的 HTML 和 CSS,因此,對開發者來說,學習整個生態系統以獲得由 CSS 預處理器提供的功能是一個很高的要求。
2009 年,CSS 的 Less 預處理器發布,它也是用 Ruby 編寫的,並且提供了與 Sass 類似的功能。主要的區別在於語法,其語法的設計儘可能接近 CSS,這意味著任何 CSS 代碼都是有效的 Less 代碼,下面是使用 Less 語法編寫的示例:
@dark-color: #4a4a4a; @light-color: #f9f9f9; @side-color: #eee; body { color: @dark-color; } header, footer { background-color: @dark-color; color: @light-color; } main { background:
@light-color; } nav, aside { background: @side-color; }
它們幾乎是相同的(@前綴代替 $ 變量),只是不像 Sass 示例那樣漂亮,但它與 CSS 具有相同的大括號和分號,這種與 CSS 相似的特點使得開發人員更容易接受它。2012 年,JavaScript(特別是 Node.js)代替 Ruby 用於重寫和編譯 Less。這讓 Less 比那些使用 Ruby 的同類速度要快,並且這讓 Less 在那些已在工作流程中使用 Node.js 的開發人員中更受歡迎。
要將此代碼轉換為常規 CSS,首先你需要安裝 Node.js,然後安裝 Less,最後運行如下命令:
這個命令會將名為 index.less 文件中的 Less 代碼轉換為 index.css 中的常規 CSS。請注意,Lessc命令並沒有提供查看文件以及進行文件更改的方式(這與 Sass 命令不同),這意味著你需要安裝不同的工具來自動監視和編譯 .less 文件,這為進程增加了複雜性。不過,這對於習慣使用命令行工具的程式設計師來說,並不是一件難事兒,但對於其他只想使用
CSS 預處理器的人而言,這是一個難以跨越的障礙。
伴隨著 Less 在意識層面上獲得很大的認可,Sass 開發人員在 2010 年增加了一種名為 SCSS 的新語法(可以認定為 CSS 的高配版,與 Less 類似)。他們還發布了 LibSass,這是 Ruby Sass 引擎的 C / C ++ 埠,它的作用是使其加速,並且能夠支持多種語言。
另一種替代 CSS 預處理器的是 Stylus,它於 2010 年推出,採用 Node.js 編寫,與 Sass 或 Less 相比,它更注重語法的清潔度。一般說來,談論最多的三種 CSS 預處理器是 Sass、Less 和 Stylus。它們在提供的功能方面都非常相似,所以無論你選擇哪個,都不算選錯。
然而,有些人認為 CSS 預處理器變得不那麼重要了,因為瀏覽器最終會實現它們的一些特性(例如變量和計算)。此外,還有一種稱為 CSS 後處理的方法,可能會使 CSS 預處理器過時(顯然有爭議),我們將在後面介紹這些方法。
CSS 後處理器使用 JavaScript 來分析並將 CSS 轉換為有效的 CSS。從這個意義上講,它與 CSS 預處理器非常相似,你可以將其視為解決相同問題的不同方法。關鍵的區別在於,雖然 CSS 預處理器使用特殊語法來標識需要轉換的內容,但在無特殊語法下,CSS 後處理器可以解析常規 CSS 並對其進行轉換。下面這個例子來最好地說明了這一點。讓我們來看看用上面最初定義 CSS 的一部分去設計標題標籤的樣式:
h1, h2, h3, h4, h5, h6 { -ms-hyphens: auto; -moz-hyphens: auto; -webkit-hyphens: auto; hyphens: auto; }粗體的部分稱為瀏覽器前綴,在瀏覽器試驗性地添加或測試新的 CSS 功能時會被用到,它為開發人員使用 CSS
的新特性提供了一種方法。-ms前綴是指 Microsoft Internet Explorer,-moz 前綴是指 Mozilla Firefox,-webkit 前綴是指使用 Webkit 渲染引擎的瀏覽器(如 Google Chrome、Safari 和 Opera 的新版本)。
請注意,添加所有這些不同的瀏覽器前綴以便使用 CSS 的新特性是非常麻煩的。如果有自動添加瀏覽器前綴的工具的話,將會很省心,我們可以用 CSS 預處理器來解決這個問題。例如,你可以用 SCSS 做這樣的事情:
@mixin hyphens($value) { -ms-hyphens: $value; -moz-hyphens: $value; -webkit-hyphens: $value; hyphens: $value; } h1, h2, h3, h4, h5, h6 { @include hyphens(auto); }
在這裡,我們使用了 Sass 的 mixin 功能,這個功能允許你在定義了一個 CSS 塊後,能在其他地方重用。當這個文件被編譯成常規的 CSS 時,任何 @include 語句都將被替換成與之匹配的 CSS @mixin 語句。總的來說,這並非是一個糟糕的解決方案,但是你需要為任何需要瀏覽器前綴的 CSS 屬性在首次定義 mixin 時負責。這些 mixin 定義需要維護,因為在瀏覽器更新其 CSS 兼容性之後,你可能希望刪除一些你不再需要的特定瀏覽器前綴。
不是使用 mixin,而是只寫常規的 CSS,並使用一個工具自動識別需要前綴的 CSS,並相應地添加前綴,在這方面,一個 CSS 後處理器就能夠做到。例如,如果你將 PostCSS 與 autoprefixer 插件一起使用,則可以在沒有任何瀏覽器前綴的情況下編寫常規的 CSS,並讓後處理器完成剩下的工作:
h1, h2, h3, h4, h5, h6 { hyphens: auto; }hyphens: auto,行將被替換為相應的瀏覽器前綴(正如 autoprefixer 插件中定義地那樣,並不需要你直接管理)。也就是說你可以只寫常規 CSS 而不必擔心任何兼容性或特殊語法,這是一件非常好的事。
除了用於 PostCSS 的 autoprefixer 外,還有一些插件可以讓你做很酷的事情。cssnext 插件允許你使用 CSS 的試驗性功能,該 CSS 模塊插件可以自動改變類來避免名稱衝突,stylelint 插件識別 CSS 中的錯誤和不合常規的行為。這些工具在過去的一兩年內才開始起步,為開發人員展示了從未有過的工作流程!
然而,這一過程需要付出代價。與使用 CSS 預處理器相比,安裝和使用 PostCSS 之類的 CSS 後處理器更為重要。你不僅需要使用命令行來安裝和運行工具,還需要安裝和配置各個插件並定義一組更複雜的規則(例如,面向哪些瀏覽器等),而不是直接從命令行中運行 PostCSS,許多開發人員將其整合到可配置的構建系統中,如 Grunt、Gulp 或 webpack,這些可幫助你管理在前端工作流程中可能使用到的所有不同的構建工具。
注意:如果你以前從未使用過現代的前端構建系統,那麼學習所有的必要組件可能會讓你覺得是一件顛覆的事情。如果你想從頭開始,請查閱我的文章 Modern JavaScript Explained For Dinosaurs,它涵蓋了前端開發人員所需的所有 JavaScript 工具。
值得注意的是,CSS 後處理器的身上存在一些爭議,有人說它們應該統稱為 CSS 預處理器,還有別的說法認為它們應該簡單地稱為 CSS 處理器等,也有一些人認為 CSS 後處理器完全不需要 CSS 預處理器,而有些人認為它們應該一起使用。無論怎樣,很顯然,如果你有興趣更深一步挖掘出 CSS 的潛能,那麼學會使用 CSS 後處理器將值得你去嘗試。
CSS 預處理器和 CSS 後處理器等工具為改進 CSS 開發體驗邁出了重要的一步,但單靠這些工具還不足以解決大型 CSS 代碼庫的維護問題。為了解決這個問題,人們開始記錄關於如何編寫 CSS 的不同的指導方針,通常稱為 CSS 方法論。
在我們深入研究任何特定的 CSS 方法論之前,我們要清楚這麼多年是什麼使得 CSS 的維護變得如此困難?關鍵的問題在於 CSS 的全局性 - 你定義的每種風格都會應用於頁面的每個部分。想出一個詳細的命名規則來維護唯一的類名或者用特殊規則來決定哪個樣式應用於給定的元素,這將變成你的工作。CSS 方法提供了一種有組織性的方式來編寫 CSS,以解決大型代碼庫的痛點,讓我們以時間順序粗略地看一下那些流行的方法。
OOCSS(Object Oriented CSS)是在 2009 年首次提出的,它遵循兩種原則。第一個原則是將結構和表現隔開,這意味著定義結構(如布局)的 CSS 不應該與定義表現(如顏色、字體等)的 CSS 一起混用,這使得應用程式更容易重構其表現。第二個原則是將容器和內容隔開,這意味著將元素視為可重用的對象,而且不管對象在頁面的哪個位置,看起來都應該是相同的。
OOCSS 提供了成熟的指導方針,但沒有具體的方案。後來的方法如 SMACSS 採用了 OOCSS 的核心概念並增加了更多細節,使其更容易入門。
l-或layout-作為類名稱的前綴。對於狀態規則,你需要在描述狀態的類名加上前綴,比如is-hidden或is-collapsed。
與 OOCSS 相比,SMACSS 有更多的細節,但在決定哪些 CSS 規則應該進入哪個類別時仍需要慎重考慮。後來像 BEM 這樣的方法避免了做決策的步驟,使其更容易被採用。
BEM(Block、 Element、 Modifier)於 2010 年推出,它是將用戶界面劃分為獨立 Block 的一種方法論。一個 Block 是一個可重複使用的部件(例如搜索表單,定義
)。Element 為 Block 的一小部分,它不能獨立重複使用(如搜索表單內的 button,Search)。Modifier 是一個實體,定義為外觀、狀態、Block 或 Element 中的行為(例如禁用搜索表單里的按鈕,定義為Search)。
BEM 很容易理解,它具有特定的命名規則,新手在應用它時無需做出複雜的決策。它的缺點是類名非常冗長,並且不遵循傳統的規則來編寫語義類名。後來的方法如 Atomic CSS 會把這個非傳統的方法帶到了另一個層面上!
<button
class="search-form__button">Search</button>,而是這樣的:<button class="f6 br3 ph3 pv2 white bg-purple hover-bg-light-purple">Search</button>。
如果你對這個例子的第一反應是害怕而退縮,那麼你不是一個人,因為許多人認為這種方法與現有的 CSS 最佳實踐方案完全背離。然而,不同場景下最佳實踐方案的有效性引起了人們的質疑,在這個過程中也引起了不錯的討論。這篇文章 做了很好的分析,重點闡述了傳統的關注點分離是如何創建依賴於 HTML 的 CSS(甚至是應當在什麼時候使用 BEM 等方法),而 Atomic CSS 或功能型方法則是基於 CSS 創建的 HTML。兩者都沒錯,但經過仔細觀察,你會發現 CSS 和 HTML 之間完全的分離從未真正地實現過!
其他的 CSS 方法,如 CSS in JS,實際上包含了 CSS 和 HTML 總是相互依賴的概念,是最具爭議性的方法之一。
CSS in JS 是 2014 年推出的一種方法,它的觀點是:不在單獨的樣式表中定義 CSS 樣式,而是直接在每個組件中定義。它是作為 React JavaScript 框架的一種方法而引入的(它採用了有爭議的方法,直接在 JavaScript 中為組件定義 HTML 而不是在單獨的 HTML 文件中)。最開始的時候,它採用內聯樣式,但後來使用 JavaScript 來生成 CSS(使用基於組件的獨一無二的類名),並使用樣式標記將其插入到文檔中。
CSS in JS 再次完全違背了現有 CSS 最佳實踐中的分離問題,這是因為我們使用網絡的方式隨著時間的推移發生了巨大變化。最初網站主要由靜態網站組成,那時將 HTML 內容與 CSS 分離很有意義。如今,Web 用於創建動態的 Web 應用程式,這時,通過可重用組件分離更有意義。
CSS in JS 的目標是能夠用 HTML / CSS / JS 封裝的「硬邊界」定義組件,使得每個組件中的 CSS 不會影響任何其他組件。React 是最早被廣泛採用的框架之一,它們為這些組件提供了「硬邊界」的支持,隨後影響了其他主流框架,如 Angular,Ember 和 Vue.js 等。需要注意的是, CSS in JS 是新型的一種方法,在這期間開發人員試圖在 Web 應用程式的組件時代為 CSS 建立新的最佳實踐,並進行了大量的實驗。
我們很容易被許多不同的 CSS 方法淹沒,但重要的是要記住,沒有一種完全正確的方法—— 當你面對足夠複雜的 CSS 代碼庫時,你應該將它們視為幾種不同工具作為備用。經過深思熟慮,為你的作品選擇一個最佳的工具,並且在這個過程中進行的每一次試驗都將為每位開發人員帶來長遠利益!
綜上所述,這就是現代的 CSS。我們介紹了使用 CSS 進行基礎設計的排版屬性,將 CSS 用於使用浮點、flexbox 和基於網格的布局,使用 CSS 預處理器以獲取新語法(如變量和 mixins),使用 CSS 後處理器實現轉換功能,例如添加瀏覽器前綴,並使用 CSS 的幾種方法論進行維護,克服 CSS 樣式的全局性。我們沒有機會深入了解 CSS 提供的許多其他功能,例如高級選擇器、轉換器、動畫、形狀、動態變量等。
由於現代的 CSS 總是在不斷地變化和快速發展,將其用在工作上難免讓人頭疼。但別忘了,隨著時間的推移,網絡也在不斷發展,很高興有很多聰明的人願意加入這個行列,構建具體的工具和提出有效的方法來提升 CSS 的實踐能力。我希望這些信息可以作為路線圖,幫助你踏上旅程!
「前端之巔」是 InfoQ 旗下關注大前端技術的垂直社群。緊跟時代潮流,共享一線技術,歡迎關注。
PWA、Web 框架、UI 與動畫、Node... 大前端的下一站在哪裡?前端工程師的價值和成長路徑是什麼?GMTC2018 上,來自 Google、Facebook、BAT 等 60+ 國內外一線前端大牛,將與你面對面探討大前端領域最新技術趨勢和實踐,想要升職加薪就快來吧!掃描下方二維碼或點擊「閱讀原文」了解更多大會詳情!
目前大會 8 折熱銷中,團購更優惠,購票諮詢:18514549229(同微信)