前端架構是一系列工具和流程的集合,旨在提升前端程式碼的質量,並實現高效、可持續的工作流。今天主要分享的是其中的前端中CSS如何進行模組化開發。
過去處理HTML的方法
過去,HTML通常被分為兩大陣營:程式式和靜態式。
程式式HTML:自動化程度100%,可控制程度接近為0
這通常適合由於前端團隊參與專案之前,專案的功能開發(包括HTML輸出)已經進行了幾周甚至幾個月了(例如使用jsp,頁面也是後端進行輸出的)。如果標記原始碼被複雜的渲染過程打亂,而且還來自不同的模版,那麼情況就會變的更加糟糕。
這意味著,對於任何不是後端複雜性的人而言,更新HTML會變得異常困難。而往往到了這個適合,後端開發者已經開始著手別的任務了,沒有事件回過頭來進行任何重大的修改。
這種制約因素的影響是,為了把內容更好的嵌入HTML中,編輯人員和後端開發者寧可寫一堆標記和CSS類名。最終,他們編寫的程式碼可能會是這樣:
<div id="header" class="clearfix">
<div id="header-screen" class="clearfix">
<div id="header-inner" class="container-122 clearfix">
<div id="nav-header" role="navigation">
<div class="region region-navigation">
<div class="block block-system block-menu">
<div class="block-inner">
<ul class="menu">
<li class="first leaf">
<a href="/start">Get Started</a>
複製程式碼
這段程式碼顯示了一個簡單的頁面頂部,即使在填充內容之前都可以包含10層巢狀,更可怕的是,在實際開發中這還是特別誇張的現象,經驗告訴我們,他還能巢狀更多。
以前,這種“div亂燉”或許確實有助於我們把靜態ps影象做成HTML頁面,但是隨著我們的需求日漸成熟,我們急需更好的方法來駕馭它們。
靜態標記:自動化程度接近於0,可控程度100%
如果我們的專案規模比較小,或者任務只是開發的一個需要填充一大塊主題區域的頁面,那麼編寫靜態HTMl會更為方便一點。雖然這種情況靈活性很大,但是也意味著我們必須負責維護所有的程式碼,當需求變更是我們需要每個頁面單獨手動修改,所以我們的程式碼會是這樣的:
<header>
<section>
<nav>
<div>
<ul>
<li>
<a href="products">Products</a>
<ul>
<li>
<a href="/socjs">Socks</a>
複製程式碼
為了保持簡潔,語義化是首選,應用樣式所以來的是HTML5元素名稱和他們的層級關係,而非CSS類名。我們的HTML中沒有css類名,主導航的樣式會自動繼承到二級導航的錨地按上面,最終我們往往會新增後代選擇起:
header > section > nav > div > ul > li > a {
color: white;
}
header > section > nav > div > ul > li > ul > li > a{
color: blue;
}
複製程式碼
過去,這種靜態標記的方式使得對於任何一個懸停狀態或者啟用狀態選擇器,程式碼至少得寫那麼長。你根本不想看三級導航會被寫成什麼樣子,更不要想四級甚至五級導航了...
平衡可控性和自動化
我們都在追求的理想狀態是,網站上的每一行HTML都是有程式自動生成,而作為前端開發人員,我們只需要管理好這個用來產生HTML的模版和流程。遺憾的是顯示並非如此,即使實在最好的情況下,也需要使用者去生成內容,而這些內容是無法自動新增css類名的。我們只能通過模版來決定類似表格,表單和導航欄這樣的HTML,這樣也算是給我門帶來了一定的靈活性和必要的自動化。
模版化和靜態化的區別在於,程式執行完成之後,我們還可以通過一套類名系統給html新增css類名,並且不在通過元素標籤和層級關係來決定視覺外觀。
<nav class="nav">
<ul class="nav__container">
<li class="nav__item">
<a class="nav__link" href="/products">
<ul class="nav__container--secondary">
<li class="nav__item--secondary">
<a class="nav__link--secondary" href="/socks">
複製程式碼
上面的這種方案似乎相當冗長,其實這一定沒有什麼好辯解的,但是我們給每個元素都新增了對應的css類名,這樣看起來更加清晰一點,更加模組化一點,而且具有複用性。我們可以作為通用模版去使用。
CSS模組化
要使用這種模組化方法去定義html,我們需要先改變構建頁面的方法和思路。單獨的靜態網頁其實壓根就不存在,所謂的網頁都已經成為了過去。
如今,css理論幾乎和css或者js框架一樣繁多,但是css或js框架的用法比較繁瑣,而且必須成套使用,而css理論更多是闡述html和css之間的關係,而不是預編譯的程式碼庫,因此使用起來會更為靈活。
當然,沒有那個方法論是完美的,你可能會發現,一個專案與某個方法比較契合,但是另一個專案可能更適合另外一種方法。所以你完全可以創造一套自己的方法論,或者將現有的理論根據自己的需求進行一些修改,因此當你猶豫不決,不知道該使用那個方法論的時候,不如先看看一些比較接觸的方法論,然後再根據自己手裡的專案進行分析。
OOCSS方法
-
分離結構和外觀
將視覺特性定義為可複用的單元,比如
simple
class就代表使用直角,complex
則表示使用圓角甚至還加了陰影。 -
分離容器和內容
不再將元素位置作為樣式的限定詞。和在容器內標記的CSS類名不同,我們現在使用的是可複用的CSS類名,比如toggle-title,他應用於相應的文字處理上,但是不管這個文字的元素是什麼。這種方式下如果沒有應用別的CSS類名,你可以讓標籤以預設的樣式呈現。
SMACSS方法
Scalable and Modular Architecyure for CSS,模組化架構的可擴充套件CSS方法。
-
基礎
如果不新增css類名,標記會以什麼外觀呈現。
-
佈局
把頁面分成一些區域。
-
模組
設計中的模組化、可複用的單元。
-
狀態
描述在特定的狀態或者情況下,模組或佈局的顯示方式。
-
主題
一個可選的視覺外觀層,可以讓你更換不同的主題。
BEM方法
Block Element Modifier,塊元素修飾符
BEM使我們要看到第三個方法,是SMACSS的另外一個方面。BEM只是CSS類名命名規則。它並不涉及如何書寫你的CSS的結構,而只是建議每個元素都新增帶有如下內容的CSS類名。
-
塊名
所屬組建的名稱。
-
元素
元素再塊裡面的名稱。
-
修飾符 任何與塊或者元素相關聯的修飾符。
BEN使用非常簡潔的約定來建立CSS類名,而這些字串可能會相當長。元素名加在雙下滑線後(例如toggle__details),修飾符加在雙橫槓後面(如toggle__details——active)。這裡的details是元素,active是修飾符,這個約定使得CSS類名便得非常清晰。使用雙橫綱是為了避免呢塊名被混淆成修飾符。 這個方法在OOCSS或者SMACSS裡使用的好處時候,每個CSS類名都能詳細地描述了它實現了什麼。在程式碼中沒有open或者is-active這樣只在特定背景下才能理解的CSS類名。如果單獨看open和is-active這連個名字,我們並不知道他們的含義是什麼。雖然BEM方法看起來很累贅、很冗餘,但是當看到toggle__details--active的CSS類名,我們就知道它是表示:這個元素的名稱是details,位置在toggle元件裡,狀態為啟用狀態。
選擇適合的方案
當然,我們專案中最重要的還是要找到一個適合的解決方案。不要因為一套規範很流行或者別的團隊正在使用就選擇它。著三個方法都提供了類似的工具,並且以相近的方式在系統中使用。
歡迎大家關於我的公眾號-- 思享說: