CSS 基础与实用特性大全
系统的 CSS 基础知识和工程化内容。
简介
CSS(Cascading Style Sheets),层叠样式表。用于描述网页呈现的语言,包括颜色、布局和字体。 独立于 HTML,可以与任何基于 XML 的标记语言一起使用。
历史
CSS1(废弃),CSS2 1996~1999 规范基础样式;CSS3 2001 分模块发布如背景和边框、盒子模型等。
工作原理
和 HTML 一样,CSS 内容被加载到网页中后会被解析为 CSSOM,会和 DOM 结合成渲染树,浏览器根据这颗渲染树进行布局、绘制和合成,最终就成了我们看到的网页。
使用方式
一般有四种使用方式
style 元素
<style type="text/css">
...;
</style>
link 标签。需要指明 rel,rel 指的是 relation(关系),常用的取值还有 perfetch
<link rel="stylesheet" type="text/css" href="basic.css" />
行内样式
<p style="color: gray">text</p>
@import 指令。引入的 sheet.css 是相对于所在 css 的地址,将其他 css 文件的内容读入该位置
@import url(sheet.css);
层叠
若要用一种最简单的方式解释层叠,我觉得就是:决定最终显示效果的规则。
选择器
- 元素选择器
- 类选择器
- ID 选择器
- 属性选择器
- 伪元素选择器
- 通用选择器
属性选择器
- 简单属性:只需要拥有该属性,对应的样式就会生效
a[href] {
color: red;
}
a[href][title] {
color: blue;
}
- 精准属性值:属性值必须匹配
img[type="fat cat"] { width: 100px } <img type="fat cat" alt="Garfield" />
- 部分属性值:属性值按照规则匹配
组选择器
多个选择器可以通过不同的符号进行组合,以实现不同的选择效果
分组选择器
,
- 选择器列表,将不同选择器组合在一起,选择所有能被列表中任意一个选择器选中的节点
示例:div, span 会同时匹配 <span>
和 <div>
组合器
(空格)- 后代组合器,选择所有指定的后代元素
示例:A B>
- 直接子代组合器,选择所有指定的直接子代节点
示例:A > B~
- 一般兄弟组合器
示例:A ~ B+
- 紧邻兄弟选择器
示例:A + B
连写
多个选择器连续书写
特指度
特指度由四个权重组成,为 a-b-c-d。这四个权重是相互独立的,没有进位一说。不同选择器有不同的权重、合起来就是特指度。需要特别记住的就是 0 特指度比没有特指度更优,后面会举例说明。
特指度a-b-c-d
的规则
- a = 样式声明来自行内属性 ? 1 : 0
- b = 选择器中 ID 属性的数量
- c = 选择器中其他属性和伪类的数量
- d = 选择器中元素名和伪元素的数量
- 继承和连接符没有特指度,通用选择器特指度为 0
很生动的一张图:
通过认真阅读图片,可以得知以下结论
- 通用选择器不影响特指度
- 各个权重互独立计算,没有进位计算
- 同级选择器特指度都只增加 1
- !important 重要声明始终覆盖选择器声明
继承
不少属性是可以通过父元素继承的,例如 color,可以通过查看 mdn 的文档的 inherited 属性看看属性是否是可以继承的,当然你也可以手动修改该属性。
但是继承的样式是没有特指度的,所以 0 特指度会胜过无特指度,观察下面例子:
<style>
* {
color: grey;
}
.title {
color: red;
}
</style>
<div class="”title”">
Title
<p>sub title</p>
</div>
最终结果是,可以看到在 p 中,sub title 的颜色是 0 特指度的灰色而不是继承的红色
层叠计算
权重
!important > 行内样式 > ID > 其他属性(Class 等)、伪类 > 元素、伪元素来源(开发者、读者、用户代理)
读者!important > 开发者!important > 开发者 > 读者 > 用户代理特指度
a-b-c-d 特指度高的生效前后位置
排在后面的规则生效
读者指的是网站的用户通过浏览器的接口修改的样式。读者样式一个最直接的例子就是在 chrome 浏览器的外观设置中的字体,其中有有默认字号和字号两个选项
读者样式样式就是默认字号,网页中的文字默认的大小 我们日常开发中 使用 font-size 直接就覆盖了。
而最小字号就是读者样式 + !important ,你会发现你的 font-size 无论设置多小,始终都不会小于 12px,就是因为设置中的这个用户选项限制的。
布局方式
视觉格式化基础
视觉格式化的内容非常多,这里只列举了三个常用的概念、知识点
- 视觉格式化模型:使文档显示时的一套计算规则,根据盒子模型将文档中的元素转换为盒子。
- 盒子模型:内容、内边距、边框、外边距
- 纵向格式化:计算容纳块的高度,同一 BFC 的块级元素之间会折叠纵向外边距
块级格式化上下文
Block Formatting Context(BFC),块盒子的布局过程发生的区域,也是浮动元素与其他元素交互的区域。
创建格式化上下文
- 根元素(html)
- 浮动元素( float 值不为 none)
- 绝对定位元素(position 为 absolute 或 fixed)
- 行内块元素(display 为 inline-block)或 flow-root
- overflow 不为 visible
清除浮动
典型的浮动流就是将浮动元素从他的普通流位置中剔除,放到行的开始。这么做的问题就是原本的容器不会再考虑浮动元素的高度,会有高度塌陷的问题,后面如果有别的块级元素的话,会继续填充在浮动流的空白处。
用得最多的方法就是 clear: both,但是在 p 有兄弟元素想 float 成侧边栏时就不好使了,此时就可以将 float 用 BFC 包装起来,不是同一个 BFC 的元素就不会互相影响了
其他格式化上下文
IFC(Inline Formatting Context,内联格式化上下文),块容器盒子在不只包含块级盒子的情况下创建 IFC
GFC(GridLayout Formatting Context,网格布局格式化上下文)display: grid
FFC(Flex Formatting Context,弹性格式化上下文),display: flex 等 flex 相关值
常用布局
布局 | 说明 | 场景 |
---|---|---|
float 布局 | 兼容性好。浮动元素会一个跟着一个,以实现横向布局。不推荐。 | 导航栏、圣杯布局等行布局 |
table 布局 | 兼容性好。同一行的元素等高,同一列的元素等宽。不推荐。 | 等高布局、代码差异(react-diff-viewer) |
flex 布局 | 轻松控制同一方向各元素的位置。 | 通过结合垂直和水平方向的布局,实现各种响应式布局 |
多列布局 | column-count 列数 | 类报纸的多列文本显示。 |
层模型 | position 为 relative、absolute、fixed、stickily | 为所欲为、吸顶 |
grid 布局 | 二维的响应式布局。 | 未知 |
工程化
首先我们需要明确的是工程化到底要解决的问题是什么: 多人协同时 CSS 的可维护性。
推荐 facebook 工程师的一次演讲:React: CSS in JS
我这边仅列四条认为比较重要的问题:
- 命名冲突
- 冗余代码
- 压缩
- 变量
命名冲突
- 规范命名:OOCSS,BEM,SMACSS
- Web Components
<style scope></style>
在 js 中会通过函数作用域起到局部命名空间的作用,在 css 中需要使用 webcomponents 才可以有局部的命名空间。规范命名可以说是最初的模块化 Bootstrap antd 等都在用。style scope 其实是有官方提案的,但是浏览器的支持程度惨不忍睹。vue 的 scope 是类似 css modules 的实现。
变量
CSS 已经原生支持,github 和 tailwindcss 都在用,放心使用
使用示例:
PostCSS
在 node 生态下,聊工程化就离不开 postcss,他是专门用来处理的 css 的。。目前热门的 css 工具基本上都是基于他来实现的,例如 css-loader、cssnano、autoprefixer。
他核心的作用就是把 css 转成抽象语法树:
基于他实现的工具,理论上可以解决目前所有问题
构建工具
基于 webpack 等构建工具,会有很多插件和工具库可以选择,此处列出常用的四种
- css modules:进行一定配置,最后自动生成带有哈希值的 class name
- CSS in JS(React):styled-components、emotion 等
- scope(Vue):vue cli 集成的 css modules 方案
- 行内样式
其他
CSS 中还有很多重要的组成部分,例如字体、单位、阴影和动画等,推荐阅读 CSS 权威指南一次性爽够。若对新兴的 CSS 技巧感兴趣的话可以阅读 CSS 一姐 Lea Verou 的 css 揭秘和 more css 系列的演讲。