Github: https://github.com/nzbin/snack-helpercss
Docs: https://nzbin.github.io/snack-helperhtml
什么是 helper ?任何框架都不是万能的,而业务需求倒是多种多样,不少时候咱们只须要更改组件的部分属性,而 helper 就是调整细节的工具。我在以前的文章《如何编写轻量级 CSS 框架》中也举过例子,咱们彻底不必由于几个属性的不一样而从新编写新组件。大部分的 helper 都是一个类对应一个 CSS 属性,属于最细小的类。经过工做的实践总结,我以为编写一套简单易用、通俗易懂的 helper 很是重要。本文的目的就是探讨 helper 的组成部分、编写方式以及如何精简 helper 的命名。git
详细介绍如何编写 helper 以前,先说一下我对于组件以及零件的见解。在以前编写轻量级 CSS 框架的时候,咱们是以组件的方式开发。而编写 helper 更像是开发一个零件,由于 helper 的属性单一,并且多个 helper 能够造成一个组件。好比下面的例子:github
假设有 .boxes
组件框架
.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 系列模型,这个系列的特色是“零件+零件=组件、组件+组件=骨架、骨架+骨架=素体、素体+武装=机体”。布局
在编写 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 by Zongbin (@nzbin) on CodePen.
这个实例所有是用 helper 完成的,惋惜这套 helper 没有栅格系统,因此布局并不灵活,可是结合以前的轻量级框架,会显示出它强大的功能。
编写 helper 比编写框架要容易的多,但简单易用、通俗易懂的 helper 还须要严谨的思考,详细的 helper 能够参见 GitHub 源码。虽然我一直声称没有打算把 helper 写成一个框架,但随着细节的追加与调整,好比添加栅格系统,这个通用的 helper 已经趋向于一个“零件化”的框架了。至于组件式框架和零件式框架哪一个更好,这是一个很难选择的问题。可是我更倾向于组件与零件的结合,由于我不但愿整个 HTML 文件被冗长的 CSS 类装饰的支离破碎。