对Bootstrap 4 CSS组件架构和命名规则的学习

一、组件最高类名

1个单词的类名

BS4的组件,以组件名单词作为最高的类名,比如警告条,最高的类名是alert,又比如徽章,最高类名就是badge

也就是说,组件与布局是解耦的,不管你把这个组件用在什么地方,这个组件的基本形态首先就是这个样子,之后你想为项目进行个性化定制,那么你可以给最高层追加定制类。

2个单词的类名

下面的btn-toolbar就是两个单词组成最高组件类名,反而子元素的类名有1个单词的btn,这其中的奥妙,就看你怎么看待你的组件了。如果你的组件里面的主要元素是子元素,整个组件就是这些子元素的集合,那么就像btn-toolbar一样就好了,如果是警告条这种肯定是单个使用的组件,那么最高类名就用一个单词就OK。

<div class="btn-toolbar mb-3" role="toolbar" aria-label="Toolbar with button groups">
  <div class="btn-group mr-2" role="group" aria-label="First group">
    <button type="button" class="btn btn-secondary">1</button>
    <button type="button" class="btn btn-secondary">2</button>
    <button type="button" class="btn btn-secondary">3</button>
    <button type="button" class="btn btn-secondary">4</button>
  </div>
  <div class="input-group">
    <span class="input-group-addon" id="btnGroupAddon">@</span>
    <input type="text" class="form-control" placeholder="Input group example" aria-label="Input group example" aria-describedby="btnGroupAddon">
  </div>
</div>

二、对最高层的外观附加类、功能附加类、工具类

外观附加类

比如警告条,BS4的做法是,最高层除了alert,还会紧跟着一个alert-primary或者其他类,也就是对alert进行外观定制化,一个基本的alert可以拓展出无数的附加类。这种类的写法是,把主类放前面,附加词放后面,用短横线链接。

alert-primary强调的是语境,分为了主要的、次要的、危险的、成功的等等这些词,如果还要给一个“可收起的”属性,怎么办?BS4给出的方案是再加一个alert-dismissible,这就是功能附加类。

再比如,徽章可以这么写<span class="badge badge-pill badge-primary">Primary</span>,有2个附加类,badge-pill表示像胶囊一样的形状,跟后面的语境外观不是一回事,所以要另外摘出来定义。

再说一个特殊的栗子<button type="button" class="btn btn-outline-primary">Primary</button>,这是包边的按钮,有带色边线,里面是白色背景填充。为什么不写成<button type="button" class="btn btn-outline btn-primary">Primary</button>呢?因为btn-primary主要特征是填充带色的背景,跟包边是冲突的两套东西,所以没办法配合,只能是另外单独定义一套btn-outline-xxx系列。

还有一个特殊的栗子是active类,它并不是独立的工具类,而是外观附加类,因为它都是用于.btn.active {...}这样的形式,所以没必要写成btn-active了。同理的还有disabled等。

功能附加类

在最高层div身上,为了实现不同的目的,可以施加多个类,比如alert-warning负责外观表现,alert-dismissible负责功能(可收起的),还有其他功能的话,可以继续加。

<div class="alert alert-warning alert-dismissible fade show" role="alert">
  <strong>Holy guacamole!</strong> You should check in on some of those fields below.
  <button type="button" class="close" data-dismiss="alert" aria-label="Close">
    <span aria-hidden="true">&times;</span>
  </button>
</div>

工具类

最后我们还可以看到fade show,这是2个工具类,可以对任何元素起作用,效果一致,fade是渐变动效果,show表示当前是显示的状态。如果你能做出跟具体组件无关的通用的工具类,也可以继续追加到后面。

又如mb-0类,它表示margin-bottom:0;,这个类的意义是什么呢?因为BS的原则是,上下两个模块拉开间距,一律采用margin-bottom,不要写任何的margin-top,原因是间距折叠效应,所以比如一系列<p>,都统一只设置margin-bottom的值就可以了。于是有一个问题就是,最后一个<p>可能不需要margin-bottom,怎么办?给最后的<p>加个mb-0类就好了。

三、使用者自己对最高层的外观附加类、功能附加类、工具类

自定义外观附加类

使用者使用BS4的时候,可以给最高层再加一个外观附加类,比如alert-xxx,这个类的作用应该是,在alertalert-primary基础上,再做外观修改,比如改一改字体大小,改一改行高,等等。这个xxx可以是更高级的概念,比如模块名、页面名,甚至网站名:

  • 如果利用模块名,比如新闻列表,那可以叫alert-newslist,意思是新闻列表里的警告条,就应该是这样子的。
  • 如果利用页面名,比如页面是投票页,那就可以是alert-poll,意思是,用在投票页的警告条就得是我写的这样的长相。
  • 如果利用网站名,比如你这是新浪的页面,可以干脆叫做alert-sina,也就是说,我们新浪的警告条,就应该是这个标准。

自定义功能附加类

写到这里的时候还没想出好的例子,先不写了。

自定义工具类

也没想出好的栗子,先不写了。

最终,最高层的类的样子应当是:“主类 外观类 自定义外观类 功能类 自定义功能类 工具类 自定义工具类”这样的顺序,就对了。

四、上下级类怎么写

下级专门定义一个类的情况

从BS4来看,比如警告条,警告条里面有能点击的链接,这样形成了上下级类,BS4的方案是:

<div class="alert alert-primary" role="alert">
  This is a primary alert with <a href="#" class="alert-link">an example link</a>. Give it a click if you like.
</div>

就是说警告条里的链接,它的类的写法就应该是alert-link。前面还是主类,后面加功能名称。

BS的原则是:能不级联就不级联,尽量只给最顶级标签加各种类,这样方便管理,而且,这些类定义的样式尽量是能继承的样式。所以,BS直接给alert-link设样式,不写成级联形式。这样,alert-link继承了祖先元素的一部分样式,自己又定义了一部分样式,这差不多就够用了,没必要写成.alert .alert-link这样的声明。

下级不专门定义类的情况

看一个栗子:

<div class="alert alert-success" role="alert">
  <h4 class="alert-heading">Well done!</h4>
  <p>Aww yeah, you successfully read this important alert message. This example text is going to run a bit longer so that you can see how spacing within an alert works with this kind of content.</p>
  <hr>
  <p class="mb-0">Whenever you need to, be sure to use margin utilities to keep things nice and tidy.</p>
</div>

<p>标签没有加任何样式,原因是BS4给全局<p>设置了统一的样式,从实践中,很可能你的组件需要跟全局不一样的行高,怎么办呢?应当定义一个类似于这样一个样式:

.alert-sina p {
    line-height: 1.8;
}

这时候问题来了,为什么不给<p>加上alert-p类?因为首先这个类好像BS官方类一样,容易混淆视听,其次,你这个组件的<p>的样式,虽然可能跟全局<p>的样式不一致,但总不至于同一个组件内的<p>与<p>互相样式都不一致吧?所以只要统一给组件内设置一个样式就够了。设置类的原则就是一定要尽量精简,也要尽量降低耦合。

接上面问题,为什么组件里面的<a>就得加上alert-link呢?因为<p>的用途比<a>窄,<p>除了表示一段话,通常没别的作用,<a>就难讲了,有各种用途,所以<a>不可能统一样式,不可以写成.alert a的样子。

三层及以上结构

Card确实是BS4里面比较复杂的一个组件了,我们看一下:

<div class="card" style="width: 20rem;">
  <img class="card-img-top" src="..." alt="Card image cap">
  <div class="card-body">
    <h4 class="card-title">Card title</h4>
    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
    <a href="#" class="btn btn-primary">Go somewhere</a>
  </div>
</div>

主类是card没悬念。

顶部的图片是card-img-top,为啥有个top呢?因为还有一个类是card-img

card-body可以看出,如果你的一个组件有上中下三部分,你就可以用-top、-body、-bottom,也可以用-header、-body、-footer。这个元素一般是做容器用,设置简单的样式即可,一般不作为级联样式表的父元素。

card-titlecard-text单词都是表意的,很好理解不解释。除非为了避免歧义,否则card-title不要写成card-body-title,一共就2个单词连起来就完事。这就好比,你说“她的眼睛是蓝色的”,没有哪个神经病会说“她的脑袋上的眼睛是蓝色的”,因为眼睛只有一对,一定在她的脑袋上,所以不需要特意写出来。

类名用词的惯例:

  • 一条一条的项目,通常就是-item了;

  • 上中下结构,上面提过,就是用-top-body-bottom,也可以用-header-body-footer

  • 若没有上中下结构,而是分为主体和主体旁边的一些零碎,那么主体可以用-inner,旁边的零碎可以另外设定具体名字。

  • 如果语义是菜单,通常用-menu包裹一系列的-item

五、3个单词组成的类名

第3个单词作为修饰词的情况

看个栗子:

<div class="btn-group">
  <button type="button" class="btn btn-secondary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
    This dropdown's menu is right-aligned
  </button>
  <div class="dropdown-menu dropdown-menu-right">
    <button class="dropdown-item" type="button">Action</button>
    <button class="dropdown-item" type="button">Another action</button>
    <button class="dropdown-item" type="button">Something else here</button>
  </div>
</div>

dropdown-menu-right是3个单词的类名,第三个单词right是修饰词。这跟BEM命名法是一致的。

3个单词连起来才描述清楚一个类的情况

看个栗子:

<form class="dropdown-menu p-4">
  <div class="form-group">
    <label for="exampleDropdownFormEmail2">Email address</label>
    <input type="email" class="form-control" id="exampleDropdownFormEmail2" placeholder="email@example.com">
  </div>
  <div class="form-group">
    <label for="exampleDropdownFormPassword2">Password</label>
    <input type="password" class="form-control" id="exampleDropdownFormPassword2" placeholder="Password">
  </div>
  <div class="form-check">
    <label class="form-check-label">
      <input type="checkbox" class="form-check-input">
      Remember me
    </label>
  </div>
  <button type="submit" class="btn btn-primary">Sign in</button>
</form>

form-check-label是3个单词组成的类,它的意思是form中的check容器中的label标签。通常有一个父元素叫form-check

form-check-input也是3个单词组成的类,它的意思是form中的check容器中的input标签。通常有一个父元素叫form-check

总结

  • 可以把组件当做一个人体来看。比如眼睛,它虽然属于头部,但你并不用强调眼睛是“头部的眼睛”。虽然不用强调,但是眼睛还是会继承头部的特性,比如头部的海拔高,所以你眼睛的海拔也高。这就算是继承。栗子可能不太恰当,理解意思即可。

  • 如果用sass来写css,不要沉迷于sass的级联写法,因为组件化的特征就是尽量不级联。sass里的级联,最多是2级连一起就够了。所以,请努力让级联扁平起来。

  • 想给一个组件加样式,应当尽量放在最顶级类里,然后多利用CSS的继承,能在最高级类里面定义的,一定要在最高级类里定义,遇到不能继承的,再在下级类里另写样式。

  • <p>这种标签,属于用的场合多,但意义简单,所以,要修改<p>的样式,不要给<p>身上放类,应该用.xxx p {}这种级联形式。反之,<a>就最好在它身上放类。

  • 从dropdown的栗子可以看出,一个组件可以包含其他组件,这是允许的,其他组件的类名不要写成dropdown-xxx-xxx,这样等于你把好容易解耦的样式又耦合起来了,应当直接定义一个xxx-xxx类,然后用.dropdown .xxx-xxx {}来定义样式。

  • 容器名字一般就是header/body/footer这种。

  • 即使是很底层的标签,类名也不要繁复,除非有必要,否则应当尽量短。form-check-input之所以长,是因为它专门用于<input type="checkbox">,实在没办法简写成form-input

  • 注意区分两个概念“模块”和“组件”。模块是什么?比如页面左侧导航,比如新闻列表,比如天气预报模块,等等。组件就好比螺丝,模块就好比各种型号的自行车,螺丝生产的时候有自己的工业标准,并不关心螺丝将来是用在哪个厂家的哪辆自行车上。所以,组件的标签上不要带模块名字,而是应该用级联写法,比如模块是评论框,那么模块最外层的类可以叫comments,它里面有几个组件,任何组件的类名都不要带comments字样。最后,用.comments .xxx {}就搞定了样式。

  • 有时候你会纠结模块的类名,比如评论区,到底类名应该是comment-section还是comment。说白了,如果下级有类名叫comment,那么顶级类名叫comment-section是可以的,如果一个个的comment形成了list的感觉,顶级类也可以叫comment-list,如果下级并没有一个类名叫comment,那么顶级类名就可以直接叫comment,应该是没问题的。所以,一切看情况而定,类名尽量简单。

附录一:id什么时候用?怎么写?

锚链接定位

<a href="#header">跳转到header</a>配合上<a id="header"></a>实现锚链接。

<label for="...">

<label for="a"><input id="a" type="checkbox"></label>用于让label操作控件。

当做JS的操作绑定元素

比如BS里面有id="btnGroupDrop1"aria-labelledby="btnGroupDrop1"

    <button id="btnGroupDrop1" type="button" class="btn btn-secondary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
      Dropdown
    </button>
    <div class="dropdown-menu" aria-labelledby="btnGroupDrop1">
      <a class="dropdown-item" href="#">Dropdown link</a>
      <a class="dropdown-item" href="#">Dropdown link</a>
    </div>

由于JS的元素选择器查找id比查找其他的形式要快,所以给被选择的元素加上id是个好习惯。

另外,最好给id名的前面加上js-,这表示这个元素是一个js钩子。

当做最大的模块名

比如你的页面有5个大模块,比如header、footer、main等等的,你除了可以用<header>标签外,也可以用<div id="header">,当然了,这种情况下能不用id就别用,因为id主要不是干这个用的。

id的写法

可以有2种,一种是驼峰写法btnGroupAddon2,一种是下划线写法btn_group_addon_2,具体用哪种都可以,真心没有任何区别,所以项目内部统一一种即可。我个人偏向于下划线写法,因为我喜欢给变量名使用驼峰写法,这样的话两种写法在js中就可以一眼区分。

一般不要用连接线写法,因为容易跟class混淆,而且id名可以直接拿来当js的window对象的属性,也就是window.btn_group_addon_2就指向该元素,但是window.btn-group-addon-2是非法的写法。

附录二:注释什么时候写?

业界目前认为最正确的做法,是只给hack做注释,因为你不注释,我真的不好理解你这个hack是干嘛的。其他情况下,应当通过类名就可以让人明白这个类是干什么的。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,264评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,549评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,389评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,616评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,461评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,351评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,776评论 3 387
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,414评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,722评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,760评论 2 314
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,537评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,381评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,787评论 3 300
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,030评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,304评论 1 252
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,734评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,943评论 2 336

推荐阅读更多精彩内容