逐行阅读 Bootstrap 源码

前言

Bootstrap 是我接触前端开发时学习的第一个 CSS 框架,也是第一个完整看完文档的开源项目。在正式和非正式项目中多次使用 Bootstrap v3,也基本了解了 Bootstrap 的优缺点、如何定制 Bootstrap 等“高阶玩法”。

在自学前端开发的两年余时间里,裸写 CSS 代码时总能遇到一些没有见过的“古怪” CSS 语句和样式,而在使用 Bootstrap 时并不会出现此类问题,遂决定阅读 Bootstrap 项目中 CSS 部分的源码,看看到底是什么在“扰乱”开发者的视线,而 Bootstrap 为开发者提高效率做了哪些有趣的事情。

说明

  • 本博文内容基于 Bootstrap v3.3.7。按照 Bootstrap.css 文件从上到下的顺序逐行进行阅读;
  • 博文标题中的“逐行阅读 Bootstrap 源码”,是指逐行阅读生成的 Bootstrap.css 文件代码,并非阅读 Bootstrap 项目构建前的原始文件代码,诸如 LESS 文件代码、JavaScript 代码等;
  • 本博文并不涉及 Bootstrap 项目中的 JavaScript 部分;
  • 以下遴选出来的 CSS 属性或语句,是基于本人现有水平进行挑选的,基本放弃阅读和理解兼容旧版 IE 浏览器的 hack 代码;
  • 本文不适合 CSS 初学者,仅作为个人备忘录。

正文

由于 Bootstrap v3 参考了开源项目 Normalize.cssHTML5 Boilerplate 的部分代码;使用 CSS 预处理语言 LESS 编写;使用 Grunt 构建;构建生成的 Bootstrap.css 文件从上到下分为三个部分的代码:

  1. 参考 Normalize.css 的代码;
  2. 参考 HTML5 Boilerplate 的代码;
  3. Bootstrap v3 自身的代码。

Normalize.css 样式

  • text-size-adjust: 100%;:使得没有针对移动小屏幕设备进行页面(宽度)优化的网站的字体,得以在小屏幕上进行缩放(一般为放大),并且不会出现横向滚动条。
  • vertical-align: baseline;:定义行内元素或 table cell 的垂直对齐方式。
  • audio:not([controls]) 选择器:选择不带 controls 属性的 audio 元素。
  • svg:not(:root) 选择器:其实 Normalize.css 作者的意思是选择 HTML 页面内的 SVG 元素。使用了 :not(:root) 排除掉非根元素的 SVG 是因为 SVG 在某些文档内可以作为根元素(也就是说这些文档其实并不是 HTML 文档),所以要排除掉。
  • box-sizing: content-box;:使用 content-box 作为盒模型尺寸,也就是在写一个盒模型大小时,边框宽度不包含在盒模型大小内。也就是假如该盒模型 width: 100px;border: 10px;,其实际宽度就是 10px(左边框宽度) + 100px(盒模型宽度) + 10px(右边框宽度) = 120px(总宽度)
  • appearance: button;:将元素的表现形式设置为 button 的样式(自带一些按钮的状态)。
  • button::-moz-focus-inner { padding: 0; border: 0; }:针对 Firefox,移除掉 Firefox 按钮 focus 状态下的按钮内边框和间距。
  • ::-webkit-inner-spin-button::-webkit-outter-spin-button 伪元素:一般配合数字输入框表单元素使用,用于设置数字增减的按钮的样式。

HTML5 Boilerplate 样式

  • a[href]:after { content: " (" attr(href) ")"; }:在 a 标签的链接后插入 href 属性中的 URL。
  • p, h2, h3 { orphans: 3; widows: 3; }:当一段块级文字,例如一个段落,跨越两个或多个打印页面,通常而言,这段块级文字只会在页面的最后或开始的地方,显示一到两行内容。widowsorphans 就是分别用来设置打印页前后可以显示的块级文字段落的行数的。换言之,如果一个打印页面内容不下设置的行数,该块级文字就会往后或往前一页显示。
  • page-break-after: avoid;:禁止在当前元素后立即换页,也就是当前元素后面一定得跟着一点内容。

Bootstrap 样式

  • .sr-only { clip: rect(0, 0, 0, 0); }.sr-only 这个类主要为了增强网站的无障碍性(可访问性)。假设在一个导航栏的 DOM 结构的主要内容之前,有很多超链接,可以使用 .sr-only 类在视觉上隐藏掉这些超链接。也就是说,为了保证视力障碍用户对网站的正常使用,通常需要在导航栏的主体内容之前,增加一些网页阅读器(朗读器)能够很好识别的内容和结构,以提高视力障碍者对网站结构的理解,而这些内容,恰恰是视力正常用户所不需要的,所以可以使用 .sr-only 类在视觉上隐藏掉这些内容,仅供网页阅读器(朗读器)正常辨别即可。语句 clip: rect(0, 0, 0, 0); 用于隐藏添加了 .sr-only 类的 label 标签。
  • .sr-only-focusable 类:确保一旦超链接被 :focus 或者 :active 了,也就是超链接被激活了,就会在视觉上可见。用于照顾使用键盘进行网页导航的用户,也是增强网站的无障碍性(可访问性)的手段之一。
  • white-space: nowrap; 语句:描述了如何处理空格(包括换行符、空格和制表符),详情见下图:

    white-space: no-wrap 的各选项

  • border-collapse: collapse;:为表格设置合并边框。

  • text-overflow: ellipsis; white-space: nowrap;:组合起来意思就是:超出盒模型宽度的段落不换行,并以 ... 显示。
  • cursor: help;:鼠标指针变成帮助图标。
  • box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .25);:盒模型内阴影,向右偏移 0px,向上偏移 1px,阴影扩展 0px,背景色为不透明度 75% 的黑色。
  • word-break: break-all;word-break 属性主要用于设置拉丁字符(英文、拉丁文等)与非拉丁字符(也就是 CJK,Chinese、Japanese、Korean,中文、日文、韩文)之间的换行规则。word-break 使得换行可以发生在任意两个字符之间;此选型更多地用于大篇幅非拉丁字符与少量拉丁字符组成的元素中,以便文字更好地分布。也就是说:如果元素内有大量英文,不建议使用这个选项,因为有很大几率会在一个英文单词的某两个字母中进行段落换行。这对于拉丁字符而言,是一个很糟糕的体验(因为拉丁字符的换行通常发生在音节、空格处)。

    W3C 规范中关于 word-break 属性的解读:word-break-property

  • word-wrap: break-word;word-wrap 是旧标准的遗留产物,新标准中的属性叫 overflow-wrapword-wrap 属性用于规定当一长串不可换行/断句的字符串由于太长,不能放入一个给定宽度的容器内时,用户代理(浏览器)是否可以在一个单词的内部进行断句以避免产生字符溢出。只有 white-space 设置为允许 wrapping 时,word-wrap 才会生效。

    一般而言,word-break: break-all;word-break: break-all; 会一起使用。

  • touch-action: manipulation;touch-action 用于指定某个给定的区域是否允许用户操作,以及如何响应用户操作(比如划动、缩放等)。manipulation:浏览器只允许进行滚动和持续缩放操作,任何其它被auto值支持的行为不被支持。

  • background-clip: padding-box;background-clip 设置元素的背景(背景图片或颜色)是否延伸到边框下面。padding-box:边框下面没有背景,即背景延伸到内边距外沿。
  • .btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) 选择器:选择的是 .btn-group 的直接 .btn 子类,它不能是 .btn-group 下的第一个 .btn,也不能是最后一个 .btn,同时不带有 .dropdown-toggle 类。由此可见,CSS 伪元素或者伪类可以通过连写的方式来进行条件式选择/排除。
  • table-layout: fixed;table-layout 属性定义了表格布局算法,用于对表格中单元格、行和列进行布局。fixed 选型定义了:表格和列的宽度通过表格的宽度来设置,某一列的宽度仅由该列首行的单元格决定。在当前列中,该单元格所在行之后的行并不会影响整个列宽。
  • :empty 伪类选择器:匹配没有任何子元素(包括 text 节点)的元素。
  • text-align: start;:一个实验性质的语句。如果内容方向是从左至右,则等于 text-align: left;,反之则为 text-align: right;

总结

以上内容如有错误,欢迎提出,我们共同讨论。

难点

其实要构建 Bootstrap v3 这样的大型开源项目,真正的难点在于:

  1. 如何进行规划;
  2. 如何优雅地构建;
  3. 如何高效地沟通、协作、配合。

如果可以的话,下次阅读 Bootstrap v4 源码,我想可以通过窥探上面这三个难点在 Bootstrap 的实践,来更好地理解 Bootstrap 的全套“源码”。

Loyalsoldier

死飞,设计,编码,音乐……美物都值得善待。