本博文原载于我的博客 · 前端养成记 · loyalsoldier.me
前言
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.css
和 HTML5 Boilerplate
的部分代码;使用 CSS 预处理语言 LESS 编写;使用 Grunt 构建;构建生成的 Bootstrap.css
文件从上到下分为三个部分的代码:
参考
Normalize.css
的代码;参考
HTML5 Boilerplate
的代码;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; }
:当一段块级文字,例如一个段落,跨越两个或多个打印页面,通常而言,这段块级文字只会在页面的最后或开始的地方,显示一到两行内容。widows
和orphans
就是分别用来设置打印页前后可以显示的块级文字段落的行数的。换言之,如果一个打印页面内容不下设置的行数,该块级文字就会往后或往前一页显示。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;
语句:描述了如何处理空格(包括换行符、空格和制表符),详情见下图:
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-wrap
。word-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;
。
总结
遇到不懂的,建议在 MDN 上查询:https://developer.mozilla.org/zh-CN/docs/Web/CSS
若想了解更精确的定义,建议浏览 W3C 标准文档:https://www.w3.org/TR
以上内容如有错误,欢迎提出,我们共同讨论。
难点
其实要构建 Bootstrap v3 这样的大型开源项目,真正的难点在于:
如何进行规划;
如何优雅地构建;
如何高效地沟通、协作、配合。
如果可以的话,下次阅读 Bootstrap v4 源码,我想可以通过窥探上面这三个难点在 Bootstrap 的实践,来更好地理解 Bootstrap 的全套“源码”。