理解 CSS - 层叠样式表 | 青训营笔记

207 阅读6分钟

理解CSS

CSS 全名 Cascading Style Sheet,也就是层叠样式表,是第一个具有层叠概念的语言。我们所说的 CSS3 都是指代 CSS2.1 之后的 CSS 内容。

层叠的意思是一个元素的样式按照一种层叠规则应用样式,也就是对于同种修饰,元素会应用优先级更高的样式。

样式层叠优先级(递减)

  • 用户代理样式表 - 浏览器默认样式
  • 用户样式表 - 很少用
  • 作者样式表 - 开发者编写的内容
  • 作者样式表使用了 !important
  • 用户样式表使用了 !important
  • 用户代理样式表使用了 !important

选择器优先级 / specificity 特异性(递减)

  • (O 类别,不属于选择器,放在这里方便比较)内联样式
  • (A 类别)id 选择器
  • (B 类别)class 选择器 = 属性选择器 = 伪类选择器 ( pseudo-class )
  • (C 类别)标签选择器 = 伪元素选择器 ( pseudo-element )

样式优先级判断示例:

ul li.green

优先级 = A: 0 + B: 1 + C: 2,其标记(A, B, C)为 (0, 1, 2)

没有 #xxx 这样的 id 选择器,有一个 class 选择器和两个标签选择器 ( ul 和 li )

div :is(p, #card)

补充::is() 本身没有优先级,以其参数中优先级最高的为准,:where 的优先级为 0

优先级 = A: 1 + B: 0 + C: 1,其标记(A, B, C)为 (1, 0, 1)

:is() 中 id 选择器 #card 优先级比标签选择器 p 优先级更高,所以 :is(p, #card) 属于一个 A 类别,还有一个 div 属于标签选择器属于 C 类别。

.class.class VS .class

前者优先级 = A: 0 + B: 2 + C: 0,其标记(A, B, C)为 (0, 2, 0)

后者优先级 = A: 0 + B: 1 + C: 0,其标记(A, B, C)为 (0, 1, 0)

所以该元素会应用 .class.class 中所编写的样式

标记(A, B, C)是为了方便我们判断为同一个元素添加的样式中,哪一个会被应用在元素上


这里有一张表可以帮助更好的理解这个规则:specifishity.com/specifishit…

也推荐阅读这些内容:

juejin.cn/post/710386… 一篇 CSS 优先级的博客

developer.mozilla.org/zh-CN/docs/… CSS优先级 - MDN


源码位置也会影响优先级

“The last declaration in document wins.” 文档最后声明的样式胜出

  • 对于通过 @import 引入的样式,按照 @import 的顺序
  • 对于 link 和 style 标签的样式,根据在 document 中的顺序决定。

盒模型

浏览器根据视觉格式化模型 ( visual formatting modal ) 将所有元素表示为盒子模型,CSS 通过盒子模型做 layout。

W3C 标准盒模型(content-box)

"在标准模型中,如果你给盒设置 widthheight,实际设置的是内容部分。padding 和 border 再加上设置的宽高一起决定整个盒子的大小。"

例如,其总宽度 = 内容宽 + 左 padding + 右 padding + 左 border + 右 border(没有 margin 计算在内)

替代(IE)盒模型

IE5.x 和 IE6 有自己的非标准盒模型,例如,其总宽度 = 设置的宽度。也就是说 width 设置了多少,实际宽就是多少,并且已经包含了 border 和 padding 在内,那么实际的内容 content 的宽度就是总宽度 - 左 padding - 右 padding - 左 border - 右 border。

我们可以通过 box-sizing 的 content-box 和 border-box 来切换这两个模型(后者是 IE 盒模型)

常规流布局

任意盒子都有内外显示类型,外部显示类型(display-outside)决定了该盒子如何与同一格式化上下文中的元素一起显示,而内部显示类型(display-inside)规定了该盒子内部的布局方式,

例子:

display: flex 外部会显示为 block,参与块级格式化上下文(BFC),而 display: inline-flex 外部会显示为 inline,参与内联格式化上下文。但这两个属性内部都参与弹性布局。

BFC

也就是 block formatting context(块级格式化上下文)。其布局规范是:“在一个块级格式区域中,盒子会从包含块的顶部开始,按顺序垂直排列。同级盒子间的垂直距离会由 margin 属性决定。相邻两个块级盒子之间的垂直间距会遵循外边距折叠原则被折叠。 在一个块格式区域中,每个盒子的左外边缘与包含块左边缘重合”

我们平时说的 BFC 是一个盒子是 BFC 或者具有 BFC 特性,此时 BFC 表示 block formatting context root。不管外部表示类型是什么,其内部表示是 flex-root,也就是说这个盒子内部形成了一个新的块级格式化上下文。

触发一个盒子 BFC 特性的条件:

  • display: flow-root | inline-block
  • position: absolute | fixed
  • float 不为 none
  • overflow 不为 visible

外边距塌陷

这些情况会导致外边距塌陷:

  • 两个兄弟元素之间相邻的上下外边距
  • 父子元素之间相邻的上下外边距
  • 内容为空元素自己上下外边距相邻

解决办法:

  1. 在相邻元素上下之间增加 border、padding 或者 内联元素,使得它们不再相邻
  2. 在父子元素重叠时,可以设置父元素为 BFC,使父子在不同的块级格式化上下文中

IFC

“在内联格式区域中,盒子会从包含块的顶部开始。按序水平排列。只有水平外边距、边框和内边距会被保留。这些盒子可以以不同方式在垂直方向上对齐,可以底部对齐或顶部对齐,或者按照文字底部对齐。我们把包含一串盒子的矩形区域称为一个线条框 ( line-box ) ”

line-box 的高度是最高元素的顶部到最低元素的底部。

相关的应用是通过设置字体的 line-height 为其包裹元素的 height 使得文字垂直居中,以及为了使得图片和文字水平居中对齐,设置图片 vertical-align: middle 的同时设置图片的父亲元素 font-size 为 0。(这是因为图片设置 vertical-align: middle 使得图片在 baseline 水平基线的基础上上移了半个 x 字母的高度,设置其父元素字体大小为 0 可以使图片水平中线和文字基线对齐)

Position 定位

relative

元素相对于原来在文档流的基础上移动

absolute

元素被移除文档流,其原本的位置不存在了,相对于最近的非 static 定位祖先元素进行定位

fixed

元素被移除文档流,元素相对于屏幕视口进行定位,屏幕滚动不会改变其位置。

sticky

元素相对于它最近滚动祖先(祖先的 overflow 是 scoll/hidden/auto)的视口 ( scrollport ) 进行移动。

层叠上下文(The stacking context)

层叠上下文是对HTML元素的三维构想,将元素沿着垂直屏幕的虚构 z 轴排开。 形成新的层叠上下文的条件:

  • position: relative 或 absolute 并且 z-index 不是 auto
  • position: fixed 或 sticky
  • flex 或 grid 的子元素;并且 z-index 不是 auto
  • opacity 的值小于 1
  • transform的值不为 none
  • will-change 的值不为通用值
  • ... 见规范