如何編寫輕量級 CSS 框架

Github: https://github.com/nzbin/snackcss

Docs:  https://nzbin.github.io/snackhtml

前言

這篇文章我已經醞釀了半年之久,或者說拖沓了這麼久吧。想說的東西不少,卻又無從提及。現在輕量級框架如雨後春筍,層出不窮。我想每一個人都應該概括總結工做中的常見需求,編寫一套適合本身的 CSS 框架。在以前的文章中,我提到了面向對象的 CSS(好比 BEM、OOCSS、SMACSS,詳見 http://vanseodesign.com/css/dry-principles/)。這是一種思想,並不涉及具體的 CSS 問題,主要是類命名的策略!如今仍然有不少人對於前端框架的認識還停留在表面,認爲 Bootstrap 是後端人員專用,前端不必等等。我不知道這種說法從何而來,我最開始也不喜歡使用框架,或許和不少人的想法同樣,畏懼新知識、懼怕難以駕馭、遇到問題的時候沒法解決等等。最關鍵的一點是不少人認爲框架的樣式是固定的,修改起來太麻煩,還不如本身根據設計圖寫起來方便。前端

爲何使用框架

爲何使用框架?答案顯而易見,效率。除此以外,使用框架或者研究框架的意義還有不少,好比面向對象思想的具體實現。在上一家公司工做的時候,開始的幾個項目我也是用最原始的方法書寫 CSS 。項目之中最讓我頭疼的就是類的命名。我想大多數人都是根據功能去命名,這就形成了不少的冗餘,相同的組件可能寫不少次。簡單舉一個例子,以下圖,我的中心的登陸界面。node

不少人包括我剛開始的時候可能會選擇下面的類命名及佈局方式,其通用性很是差git

<div class="login-area">
    <div class="login-img">
    <
img src="..." />
  </
div> <div class="login-text">
    <
a href="...">請點擊登陸</a>
  </
div> </div>

然而瞭解 Bootstrap 的人應該一眼就發現上圖就是一個 media 對象,無非一些小細節須要調整一下github

<div class="media">
    <div class="media-left">
        <img src="..." />
    </div>
    <div class="media-body media-middle">
        <a href="...">請點擊登陸</a>
    </div>
</div>

爲了讓文字與圖片居中對齊,咱們可使用 Bootstrap 的 .media-middle 的輔助類。若是在工做中還要根據需求自定義一些輔助類調整細節,固然這是一個移動端的例子,能夠選擇移動端框架相關的 media 對象。npm

另外,在項目改版的時候,原始的方法的修改更是慘不忍睹,能夠說是噩夢,冗長的 CSS 文件、混亂的功能劃分、類名、色值等等。最後也只能硬着頭皮一點一點修改。那一刻我才體會到框架的意義以及前端工具的重要性。我從工做中總結出,要麼你能夠熟練的使用某一個框架,要麼就本身實現一個框架後端

前端框架對比

目前市面上前端框架主要分重量級與輕量級。重量級主要有 Bootstrap、Semantic、UIkit、Foundation 等,輕量級有 Pure、Skeleton、Miligram 等。常常關注前端動態的工程師會發現輕量級框架每一年都層出不窮。在我上面提到的主流輕量級框架以外還有不少相似的框架。我一直問本身,爲何要重複造輪子。通過研究,我發現這些輕量級框架其實大多都不能勝任工做需求,並且模仿的痕跡很重,基本上都或多或少的有 Bootstrap 的影子。那麼這些輕量級框架有沒有意義呢?固然有。可是就我我的觀點,選擇輕量級框架反倒不如本身實現一個框架。由於大多輕量級框架就像是工做總結,是根據本身的業務需求實現的。因此大多不具備通用性。sass

前端框架的對比主要以 Bootstrap、Semantic、UIkit 爲主,由於我我的感受這三個最具備表明性,並且設計風格各有特點。Foundation 也有不少大公司在用,但以我我的觀點,不管是框架的易用性仍是設計風格,相比其它幾個框架稍遜一籌。前端框架

其中 Bootstrap 和 Semantic 是面向對象的最好體現。

我先說一下 Bootstrap 的優點,不是設計風格,不是模塊,不是特效,而是柵格,響應式柵格。Bootstrap 的柵格在與其它框架對比中佔有絕對優點,不管是柵格的劃分仍是類名的風格都堪稱經典。若是讀者有心看一下 Bootstrap 的 Less 源文件,就會感覺到 Bootstrap 對於響應式柵格的獨具匠心。其實在 Bootstrap 以前也有不少柵格方案,可是給人的感受就是不夠利索,類名繁瑣很差記。然後來的不少框架,尤爲輕量級的框架大多都有 Bootstrap 的影子。

下面咱們經過對比幾個框架的柵格和按鈕來看一下類命名的策略。

Bootstrap

<div class="row">
  <div class="col-md-8"></div>
  <div class="col-md-4"></div>
</div>

<button class="btn btn-primary" type="submit">Button</button>

Semantic

<div class="ui grid">
  <div class="ten wide column"></div>
  <div class="six wide column"></div>
</div>

<button class="ui primary basic button">Primary</button>

Foundation

<div class="row">
  <div class="small-3 columns"></div>
  <div class="small-9 columns"></div>
</div>

<button type="button" class="primary button">Primary</button>

UIkit

<div class="uk-grid">
    <div class="uk-width-1-2"></div>
    <div class="uk-width-1-2"></div>
</div>

<button class="uk-button uk-button-primary" type="button">Primary</button>

Pure

<div class="pure-g">
    <div class="pure-u-1-2"></div>
    <div class="pure-u-1-2"></div>
</div>

<button class="pure-button pure-button-primary">A Primary Button</button>

經過上面的對比,你們應該已經發現了這些框架的命名策略的不一樣。不能否認,Bootstrap 的命名最經典。

以前在網上看到有人討論關於框架的易用性,有人說 Bootstrap 的類名太長,然而經過上面幾個框架的對比,Bootstrap 的類並不繁瑣,並且用預處理器編寫框架時嵌套會比較靈活。

Semantic 的類名最簡潔,經過多個定語的修飾組成一句話,確實頗有意思。可是過多的修飾類在編寫框架時會稍顯凌亂,有利有弊,因人而異吧。

Foundation 的柵格應該是最豐富的,策略上相似 Bootstrap,只是對公共屬性進行了拆分,你們也能夠看看其中的具體細節。

UIkit 和 Pure 的策略相同,都加了前綴以區分其它框架,可是很顯然類名過於冗長了。我在編寫框架時也這樣想過,可是最終放棄了這種方式。

關於 CSS 預處理器

CSS 預處理器早已不是什麼新鮮事,可是真正可以在工做中運用的人有多少呢?熟練使用預處理器特性的人又有多少呢?

我以前工做的時候也沒有用預處理器,由於不用,因此也意識不到預處理器的好處。主要是以爲麻煩,由於要使用編譯器編譯一下,還不如直接寫 CSS 方便。可是在項目維護的時候就意識到預處理器的好處。後來在幾個項目中嘗試了預處理器,可是對於模塊化的寫法不太明確。預處理器做爲工具,能夠實現模塊化編寫 CSS,那麼應該如何劃分模塊?另外,預處理器有不少特性,可是大多數人剛開始只用到變量和嵌套,其它的特性幾乎不多用到。我相信在本身動手實現一個輕量級框架的過程當中,咱們能夠對預處理器有一個全面的瞭解。

目前流行的預處理器有 Less,Sass,Stylus 三個,選擇哪一個徹底是看本身的習慣。我最開始由於 Bootstrap 瞭解的 Less,可是由於習慣選擇了 Sass,其次 Sass 的功能要更全面一些。

不管是工做仍是本身寫項目,都要搭建一個項目環境,也就是安裝一系列的 npm 包。相比刀耕火種的開發方式,使用工具開發的前期準備過程稍顯麻煩,然而一旦環境建好,後期的開發將會遊刃有餘。

Miligram 這個輕量級框架在 Github 上有很高人氣,可是說實話,用處並不大。不過這個框架的構建方式很是值得學習。雖然 CSS 對於不少人來講很簡單,可是真要去寫一個框架,仍是很是棘手,這時候就須要借鑑一些優秀的框架。

編寫框架大體會用到的 npm 以下:

--autoprefixer
--node-sass
--npm-run-all
--rimraf
--onchange

其實最主要的就是一個 node-sass,其它的都是輔助 CSS 文件的生成修改,你們感興趣的話能夠去 npm 官網搜索這些插件,瞭解具體用法,若有不懂能夠給我留言,我就不囉嗦了。

編寫輕量級框架

終於到了本篇文章的重頭戲。

簡單介紹一下,我給本身編寫的框架取名 Snack,原意「快餐」,主要表達簡單之意。雖然是輕量級框架,但我並不想拿輕量級作爲噱頭,畢竟體量輕意味着某些功能的缺失以及疏漏。這個框架的意義更多的是交流學習,我試圖借鑑其它框架的優秀之處,儘可能簡化類名,以及嘗試探索一些更通用的組件。

大多數的輕量級框架只是 CSS 框架,不涉及 JS 部分,主要用於網頁的佈局。我之因此打算本身編寫框架,是由於工做中重複的東西太多,經過框架能夠很好的將這些零散組件整合到一塊兒。另外一方面,寫個小項目,學點新知識是一件趣事。

編寫框架是去年想作的事情,但由於時間緣由,拖了好久。寫框架之初我曾陷入一個誤區,我打算設計一些比較前衛的樣式,立體的按鈕、浮動的面板等,好比下圖中的風格。

https://dribbble.com/shots/524593-Soft-Interface-Black

可是在斷斷續續編寫框架的過程當中,我逐漸找到了方向,上圖的樣式只是一種皮膚,編寫框架之初不該該把重點放在這上面。固然,好的 UI 設計也是框架成功的一部分。

模塊劃分

編寫框架的第一步就是要肯定框架應該包含哪些模塊。由於是輕量級框架,因此模塊確定沒有重量級框架那麼全面,只有核心的一些組件。經過比較一些輕量級框架以及工做總結,大體經常使用的模塊包括柵格、媒體、按鈕、排版、表單、表格、面板以及輔助工具。

在經常使用的這幾個組件中,須要重點關注的是柵格、表單及面板,媒體組件也很重要,可是自由發揮的空間不大,我直接用了 Bootstrap 的媒體組件。

命名策略

首先是類命名的層次與結構。類命名一直是我比較糾結的地方,剛開始工做的時候爲了起一個見名知意又簡潔的類名老是抓耳撓腮。我在編寫框架時儘可能避免與 Bootstrap 的類名重疊,但也不能徹底避免。對比其餘框架會發現,這種狀況不可避免的會出現,畢竟類名會有必定的規律性以及層次性。在這一點上我比較喜歡 Bootstrap 的風格。下面和 Bootstrap 的表單作一個對比。

Bootstrap 的表單結構及類名

--div.form-horizontal
  --div.form-group
    --label.control-label
    --input.form-control

Snack 的表單結構及類名

--div.form-row
  --div.form-item
     --label.form-label
     --input.form-field

這個表單結構總體而言還算不錯,只是個別地方須要修改。有一些框架不給 input 等元素起類名,而是給父元素一個類名,我的對這種作法表示疑問,不起類名會下降框架編寫及使用的靈活性。

第二個策略是組件的修飾,好比按鈕及面板都存在多個語境(顏色、大小等),在這一點上我編寫框架時作了一些簡化,風格上有些 Semantic 的影子。

<button class="btn primary">primary</button>
<table class="table bordered striped">...</table>
<div class="boxes primary">...</div>

關於修飾類的策略是一個仁者見仁智者見智的問題,至於哪一種方法更好,還須要在編寫框架的過程當中摸索。

柵格系統

演示示例: https://nzbin.github.io/snack/#grid

任何框架必須創建在柵格的基礎上才能靈活佈局。我在前面提到了 Bootstrap 的精華就是柵格系統。柵格系統的編寫須要使用預處理器的循環功能,不然就要作無謂的重複勞動了。我遇到過一些輕量級框架是用 Less 編寫的,其柵格系統就沒有用循環,這樣的源碼稍顯唐突,多是做者對 Less 的循環功能不熟,固然 Less 自己的循環比較弱,用起來有些彆扭。關於預處理器的循環,能夠參照我以前翻譯的 《CSS 預處理器中的循環》,比較詳細地對比了三種流行預處理器的循環功能。簡單說一下,Less 沒有循環,但能夠用遞歸實現,而 Sass 和 Stylus 有真循環。

我編寫的柵格系統也是默認 12 列,可是後來發現 12 列的柵格缺乏最經常使用的列寬(好比 10%、20%、30%等),好比下面 CodePen 展現的例子用 12 列柵格是沒法完成的,因此我又添加了 10 列柵格,但仍然沒法面面俱到,不過已經很靈活了。

See the Pen snack-grid by Zongbin (@nzbin) on CodePen.

柵格的使用和 Bootstrap 是同樣的,除了 12 列柵格外,10 列柵格以及均分柵格都要添加 .cols-

<!-- 默認 12 列柵格,因此省略 cols-12 -->
<div class="row">
    <div class="col-5"></div>
    <div class="col-7"></div>
</div>

<!-- 10 列柵格 -->
<div class="row cols-10">
    <div class="col-3"></div>
    <div class="col-7"></div>
</div>          

這個柵格並無響應式,只有一個斷點,小屏手機上的話全部柵格都會單行顯示。一方面,這樣的設計符合大多數輕量級框架的初衷;另外一方面,我打算再寫一個針對移動端的框架,畢竟 Web 端和移動端的風格差距較大,按照業務需求分開會更好。不過最近我更改了源文件,爲響應式預留了擴展方式。

表單

演示示例: https://nzbin.github.io/snack/#forms

在上面的命名策略中已經展現了 Snack 表單的基本結構,基本表單除告終構以外,樣式上並無太多能夠討論的地方。在此說一下表單中 checkbox 的結構調整,先看一下 Bootstrap 的 checkbox 結構。

<!-- checkbox -->
<div class="checkbox">
  <label>
    <input type="checkbox" value=""> checkbox
  </label>
</div>

<!-- checkbox-inline  -->
<label class="checkbox-inline">
  <input type="checkbox" id="inlineCheckbox1" value="option1"> checkbox
</label>

以上兩種結構不能有誤差,稍有誤差樣式就會錯亂,靈活性較差。其次我在想兩種結構能不能整合在一塊兒,加強靈活性。想了好久,找到了方法,Snack 結構以下:

<!-- checkbox -->
<div class="checkbox">
  <label>
    <input type="checkbox" value=""> checkbox
  </label>
</div>

<!-- checkbox-inline -->
<div class="checkbox inline">
  <label>
    <input type="checkbox" value=""> checkbox
  </label>
</div>

也能夠將樣式直接加到 label 標籤上。另外,若是將 input 移到 label 標籤外也是沒有問題的,以下:

<!-- checkbox -->
<div class="checkbox">
  <input type="checkbox" id="checkbox1" value="">
  <label for="checkbox1">checkbox</label>
</div>

<!-- checkbox-inline -->
<div class="checkbox inline">
  <input type="checkbox" id="inlineCheckbox1" value="">
  <label for="inlineCheckbox1">checkbox</label>
</div>

這種結構有一個好處,就是能夠自定義 input 樣式,詳見下面的 CodePen 的 scss 文件。radio 的設置和 checkBox 是同樣的。

See the Pen snack-forms by Zongbin (@nzbin) on CodePen.

輔助類

輔助類是一系列類的組合,好比字號大小、顏色值、padding、margin 以及左右浮動等。在一些 Bootstrap 搭建的後臺管理系統中尤其常見,這樣佈局起來就會比較靈活。如下是一個邊框的輔助類。

.border-left-right {
  border-left: 1px solid #eee;
  border-right: 1px solid #eee;
}
.border-top-bottom {
  border-top: 1px solid #eee;
  border-bottom: 1px solid #eee;
}
.border-left {
  border-left: 1px solid #eee;
}
.border-right {
  border-right: 1px solid #eee;
}
.border-top {
  border-top: 1px solid #eee;
}
.border-bottom {
  border-bottom: 1px solid #eee;
}

關於輔助類的更多內容能夠閱讀這篇文章《如何編寫通用的 Helper Class

盒組件

演示示例: https://nzbin.github.io/snack/#boxes

盒組件是我整個框架中比較滿意的一個模塊。之因此要作這個組件主要是以爲 Bootstrap 的 list 組件和 panel 組件能夠整合到一塊兒。固然,這樣的作法有利有弊。盒組件在後臺管理系統的佈局中表現的尤其突出。其命名也是多種多樣,好比 panel、widget、portlet、ibox、card等,每一個後臺管理系統框架都會對這個組件進行深度開發,可見其在佈局上的重要性。給一個組件起一個合適的類名也很關鍵,想了好久,最後用了 box 的類名,固然通常狀況下儘可能不要用 box,由於這個類名比較寬泛。下面的 CodePen 模擬了 Bootstrap 的 list 及 panel 組件。

See the Pen snack-boxes by Zongbin (@nzbin) on CodePen.

主題

給框架添加主題是一件有趣的事情。Snack 的默認主題是白色,由於喜歡黑色,最後添加了暗夜主題,編寫主題只需改變組件的顏色。演示文檔 的頁面用了暗夜主題,點擊上方的紅色按鈕能夠切換主題。

總結

若是你們問我那個框架更好,我會絕不猶豫的選擇 Bootstrap。在工做中能夠根據需求的難易進行框架選擇,若是業務比較重,最好根據 Bootstrap 進行二次開發;反之,能夠選擇一些輕量級框架,最好仍是根據本身的需求造輪子,若是你們願意選擇或是借鑑個人框架,那會是個人榮幸。

相關文章
相關標籤/搜索