Github: https://github.com/nzbin/snack-helperDocs: https://nzbin.github.io/snack-helpercss
什麼是 helper ?任何框架都不是萬能的,而業務需求倒是多種多樣,不少時候咱們只須要更改組件的部分屬性,而 helper 就是調整細節的工具。我在以前的文章《如何編寫輕量級 CSS 框架》中也舉過例子,咱們徹底不必由於幾個屬性的不一樣而從新編寫新組件。大部分的 helper 都是一個類對應一個 CSS 屬性,屬於最細小的類。經過工做的實踐總結,我以爲編寫一套簡單易用、通俗易懂的 helper 很是重要。本文的目的就是探討 helper 的組成部分、編寫方式以及如何精簡 helper 的命名。html
詳細介紹如何編寫 helper 以前,先說一下我對於組件以及零件的見解。在以前編寫輕量級 CSS 框架的時候,咱們是以組件的方式開發。而編寫 helper 更像是開發一個零件,由於 helper 的屬性單一,並且多個 helper 能夠造成一個組件。好比下面的例子:git
假設有 .boxes
組件github
.boxes { border: 1px solid #eee; border-radius: 5px; margin-bottom: 15px; overflow: hidden; }
假設有以下 helper框架
.b-1 { border: 1px solid #eee !important; } .r-5{ border-radius: 5px !important; } .m-b-15{ margin-bottom: 15px !important; } .overflow-hidden { overflow: hidden !important; }
則 .boxes
= .b-1
+ .r-5
+ .m-b-15
+ .overflow-hidden
函數
我是一個模型愛好者,這樣的組合方式讓我想到了壽屋的 HEXA GEAR 系列模型,這個系列的特色是「<span>零件+零件=組件、組件+組件=骨架、骨架+骨架=素體、素體+武裝=機體</span>」。工具
在編寫 helper 的時候,基於以上想法,我在思考是否能夠把 helper 拆分的足夠精細,這樣它就能夠自成一體造成一個框架,也就是「零件+零件=組件、組件+組件=框架」。使人遺憾的是,個人想法已經被人實踐,前幾天瀏覽 GitHub 時發現了相關的項目 tailwindcss,這個框架就是以 helper 爲基礎,經過屬性疊加的方式添加樣式。佈局
組件式框架和零件式框架是兩種徹底不一樣的思想,難分伯仲,各有優缺點。性能
一套完整的 helper 應該包含哪些內容呢?通常經常使用的有 padding
、margin
、font-size
、font-weight
等。爲了編寫更爲通用的 helper,咱們須要更細緻的劃分。雖然咱們並無打算把它寫成一個框架,可是咱們但願 helper 的功能足夠強大。經過對比和思考,我將 helper 暫時劃分紅如下幾個模塊:測試
和以前編寫輕量級框架同樣,咱們一樣使用 Sass 預編譯器。helper 類幾乎都是 Sass 循環生成的,因此源代碼看上去很精簡。
由於顏色稍微特殊一點,我將顏色與其它內容分開單獨介紹。在編寫輕量級框架的時候,我也定義了經常使用的一些顏色,可是面對特殊需求時略顯單一,因此咱們須要使用 helper 擴充顏色集羣。可是顏色是一個沒法量化的概念,因此再強大的 helper 也沒法面面俱到,只能是必定程度上的補充。參考經常使用的顏色值,最終我設置了紅、橙、黃、綠、青、藍、靛、紫、粉、冷灰、暖灰等幾種色系。
其中每一個顏色都有六個亮度值,分別用 -lightest
、-lighter
、-light
、-dark
、-darker
、-darkest
表示,此處有參考 tailwindcss 的顏色命名。這些顏色都是經過 Sass 的顏色函數生成的。以灰色爲例,Sass 代碼以下:
$gray:#999; $gray-light:lighten($gray, 15%); $gray-lighter:lighten($gray, 25%); $gray-lightest:lighten($gray, 35%); $gray-dark:darken($gray, 15%); $gray-darker:darken($gray, 25%); $gray-darkest:darken($gray, 35%);
這些顏色序列看上去很像一套馬克筆,不過馬克筆灰色系更豐富,包括冷灰、暖灰、藍灰、綠灰。
其中背景色的循環方式以下,爲了便於循環,咱們定義了一個 color map
,而後用 @each
方法循環。
$color-list:( 'gray':$gray, 'brown':$brown, 'red':$red, 'orange':$orange, 'yellow':$yellow, 'green':$green, 'teal':$teal, 'blue':$blue, 'indigo':$indigo, 'purple':$purple, 'pink':$pink ); @each $name,$color in $color-list { .bg-#{$name} { background-color: $color; } .bg-#{$name}-light { background-color: lighten($color, 15%); } .bg-#{$name}-lighter { background-color: lighten($color, 25%); } .bg-#{$name}-lightest { background-color: lighten($color, 35%); } .bg-#{$name}-dark { background-color: darken($color, 15%); } .bg-#{$name}-darker { background-color: darken($color, 25%); } .bg-#{$name}-darkest { background-color: darken($color, 35%); } }
理所固然,我又提到了命名策略。在編寫輕量級框架的時候,我也着重討論了類命名策略以及比較了一些框架的命名方式。不管是框架仍是 helper,類命名都決定了其易用性,並且會影響使用者的習慣,因此我會從簡潔、直觀、易用等幾個角度命名。不過 helper 的命名比較簡單,由於幾乎大多數都是單一的 CSS 樣式,因此命名策略基本都是對 CSS 屬性的抽象與簡化。
我在工做中接觸過兩種 helper 序列的表示方法,一種是常見的數字型,另外一種是尺寸型。以 padding
爲例:
數字型
.p-5 { padding: 5px !important; } .p-10 { padding: 10px !important; } .p-15 { padding: 15px !important; } .p-20 { padding: 20px !important; } .p-25 { padding: 25px !important; }
尺寸型
.p-xs { padding: 5px !important; } .p-sm { padding: 10px !important; } .p-md { padding: 15px !important; } .p-lg { padding: 20px !important; } .p-xl { padding: 25px !important; }
雖然在實際應用時,尺寸型寫法並無什麼不妥,但很明顯它的擴展性不好,並且不直觀。做爲例子,我只寫了五個數值,但若是咱們但願添加更多的 padding 值的話,尺寸型命名就乏力了。我認爲,凡是能夠量化的屬性,好比 padding
、margin
、font-size
、border-width
等,應該直接用數值表示,而對於不能夠量化的屬性,好比 box-shadow
,用尺寸型命名比較合適。
大多數的 helpr 命名都是 CSS 屬性的首字母縮寫形式。好比 p
表示 padding
、m
表示 margin
、f-s
表示 font-size
等。這符合咱們指望的簡潔直觀的要求。但也不能惟縮寫論,全部的命名都用縮寫,由於有些屬性的縮寫會重複,並且有些縮寫以後就不知道具體含義了。咱們能夠沿用以前的規則,能夠量化的屬性都用縮寫,不能夠量化的屬性用簡化的全稱(好比 box-shadow
能夠替換爲 shadow
)。
以 padding 循環爲例:
@for $counter from 0 through 6 { .p-#{ $counter * 5 } { padding: ($counter * 5px) !important; } .p-t-#{ $counter * 5 } { padding-top: ($counter * 5px) !important; } .p-r-#{ $counter * 5 } { padding-right: ($counter * 5px) !important; } .p-b-#{ $counter * 5 } { padding-bottom: ($counter * 5px) !important; } .p-l-#{ $counter * 5 } { padding-left: ($counter * 5px) !important; } }
對於其它幾個 helper 與此相似,循環也很簡單。
margin 的 helper 相比其它來講比較特殊,由於它有負值,因此咱們必須考慮如何表示負值。有些框架用 n
(negtive)表示負值。好比 m-{t,r,b,l}-n-*
的形式:
.m-t-n-5 { margin-top: -5px !important; } .m-r-n-5 { margin-right: -5px !important; } .m-b-n-5 { margin-bottom: -5px !important; } .m-l-n-5 { margin-left: -5px !important; }
我以爲徹底能夠簡化一步,用 -
表示負值,簡單易懂,以下:
.m-t--5 { margin-top: -5px !important; } .m-r--5 { margin-right: -5px !important; } .m-b--5 { margin-bottom: -5px !important; } .m-l--5 { margin-left: -5px !important; }
雖然這種命名方式很簡潔,但看上去和其它 helper 不太統一。
圓角的 CSS 屬性名爲 border-radius
,若是直接簡寫的話和 border-right
就重複了,參見其它框架的表示方法有 corner-rounded
、rounded
等。咱們也能夠簡化一下,好比直接用 r
表示,既能夠表明 rounded
也能夠表明 radius
,一箭雙鵰。這樣的表示方法應該不會有歧義,畢竟在咱們的腦海中,r
表示半徑算是一個根深蒂固的概念。Sass 代碼以下:
@for $counter from 0 through 10 { .r-#{ $counter } { border-radius: ($counter * 1px) !important; } .r-t-l-#{ $counter } { border-top-left-radius: ($counter * 1px) !important; } .r-t-r-#{ $counter } { border-top-right-radius: ($counter * 1px) !important; } .r-b-r-#{ $counter } { border-bottom-right-radius: ($counter * 1px) !important; } .r-b-l-#{ $counter } { border-bottom-left-radius: ($counter * 1px) !important; } }
咱們用 -full
表示 100%
,其它框架也基本如此,稍後再談論 r-100%
這種形式的可行性及問題所在。
.r-full { border-radius: 100% } .r-t-l-full { border-top-left-radius: 100% } .r-t-r-full { border-top-right-radius: 100% } .r-b-r-full { border-bottom-right-radius: 100% } .r-b-l-full { border-bottom-left-radius: 100% }
一樣的,高度和寬度的 100%
數值也用 -full
表示,循環方式相似。
咱們在以前反覆提到了陰影屬於非量化的屬性,因此只能使用尺寸型命名法,固然用數字也不是不能夠,一下子再詳細說明。先看源代碼:
.shadow-xs{ box-shadow:0 1px 5px 1px rgba(0,0,0,.15); } .shadow-sm{ box-shadow:0 2px 10px 2px rgba(0,0,0,.15); } .shadow-md{ box-shadow:0 3px 20px 3px rgba(0,0,0,.15); } .shadow-lg{ box-shadow:0 4px 30px 4px rgba(0,0,0,.15); } .shadow-xl{ box-shadow:0 5px 40px 5px rgba(0,0,0,.15); }
總體而言,比較簡潔,不過陰影的數值我是粗略添加的,實際狀況要作調整。說點題外話,我我的以爲對於非量化的屬性自己而言,或許用處就不大,由於這些屬性可以知足業務需求的可能微乎其微,可是它仍然是不可獲取的一部分。因此說「通用的」 helper 並不必定通用。
經過 font-weight
說一下關於強度的表示法,font-weight
的 CSS 屬性自己就有兩種表示法,一種是直接文字命名,好比 .f-s-thin
, .f-s-normal
, .f-s-bold
等,另外一種是比較直接的 100 ~ 900 數值型表示法。以我我的觀點,我更傾向於數值型表示法,簡單直觀,並無歧義,也算是約定俗成的規定吧。font-weight
的循環比較簡單,並且數值有限,咱們能夠直接寫出從 100 ~ 900 的全部 helper。其它相似的 helper 也能夠用 100 ~ 900 表示強度,好比顏色。
須要注意的是,編寫 helper 時必定要對數值型、尺寸型、強度型命名作好歸類與統一,切記毫無章法地胡亂使用。
對於 r-100%
或者 w-100%
這樣的寫法是能夠的,可是在定義 CSS 時要進行字符轉義,好比
.r-100\% { border-radius: 100% }
使用方式以下
<div class="r-100%"></div>
可是這種寫法總給人怪怪的感受,並且輸入時要按 shift
+ %
,不太方便,因此暫時只做爲參考。
另外說明一點,咱們能夠經過特殊字符定義百分數,好比:
.w-50 { width: 50px; } .w\:50 { width: 50% }
經過約定的這種規則,咱們就能夠爲 helper 添加柵格系統了。不過這只是暫時的想法,畢竟咱們已經有一套輕量級 CSS 框架了。
由於 helper 是循環生成的,因此循環的數量決定了 helper 的豐富度。那麼循環的數量多少合適呢?這是全部 helper 最難統一的地方。不能否認,helper 的數量越多,通用性越強,也就越靈活。任何事物都有兩面性,雖然 helper 越多越好,可是數量太多會形成文件臃腫。目前我寫的 helper 的文件體積幾乎和以前的輕量級框架差很少,某種程度上來講確實在向「零件化」的框架發展。另外一方面,其實 helper 並無必要寫的太全面,不少數值會形成冗餘。
簡單來講,對於有限值的 helper 就能夠所有寫出,好比對其方式、font-weight
等。而對於任意數值的 helper 來講,咱們須要選擇經常使用的一些數值,好比 padding
、margin
等屬性,基本 1~50 px 之間就能夠了,而圓角 1~20 px 足矣。不能量化的屬性好比陰影就徹底看我的喜愛了,我以爲五個尺寸就差很少。對於實在特殊的需求也只能特殊對待了。
如今咱們測試一下咱們所寫的 helper 是否是可以知足通常需求,好比一個帶有圓角陰影的用戶卡片,以下:
See the Pen snack-helper-test
這個實例所有是用 helper 完成的,惋惜這套 helper 沒有柵格系統,因此佈局並不靈活,可是結合以前的輕量級框架,會顯示出它強大的功能。
編寫 helper 比編寫框架要容易的多,但簡單易用、通俗易懂的 helper 還須要嚴謹的思考,詳細的 helper 能夠參見 GitHub 源碼。雖然我一直聲稱沒有打算把 helper 寫成一個框架,但隨着細節的追加與調整,好比添加柵格系統,這個通用的 helper 已經趨向於一個「零件化」的框架了。至於組件式框架和零件式框架哪一個更好,這是一個很難選擇的問題。可是我更傾向於組件與零件的結合,由於我不但願整個 HTML 文件被冗長的 CSS 類裝飾的支離破碎。