CSS 的核心之一就在此,直接影响我们开发中的调试和布局!!!
举个 🌰:页面上存在一个 h1 元素,不设置任何样式,但是当我们点开 computed 查看,几乎 MDN 上的 CSS 属性都存在且有值。这里的每一个属性才真正是这个元素在页面上所呈现的样式。换言之,我们在样式表中书写的样式不一定是最终样式。
CSS 属性值的计算过程是某个元素从所有 CSS 属性没有值,到所有 CSS 属性都有值的过程。
1. 确定声明值
在作者样式表(开发人员设置的)和浏览器默认样式表中,找到「没有冲突」的样式,直接作为计算后的样式。
2. 层叠 - 解决冲突
在两张表中,找到有冲突的样式,经过三个步骤(顺序不能错)解决冲突:
2.1 比较重要性
! important 的默认样式 > ! important 的作者样式 > 作者样式表 > 默认样式。
2.2 比较特定性(权重)
对每个样式分别计数:style、id、属性、元素。最终选择数量大的。
- id:id 选择器的数量;
- 属性:属性、类、伪类的数量;
- 元素:元素、伪元素的数量。
在 vscode 上会有直接的展示,默认省略 style,因为 style 中,1 表示内联样式,0 表示非内联样式。
2.3 比较源次序
源码中靠后的样式覆盖靠前的样式。
补充,优先级的规则从低到高为:
- 元素选择器:如 p、div。优先级最低。
- 类选择器和伪类选择器:如 .class、:hover。
- ID 选择器:如 #id。优先级较高。
- 内联样式:如 <div style="color: red;">。优先级最高。
- !important:可以强制覆盖其他规则的优先级,但要谨慎使用。
举个 🌰
<p id="section" class="paragraph">段落</p>
#section {
color: red;
}
.paragraph {
color: orange;
}
p {
color: yellow;
}
最终颜色为 red,因为 ID 选择器的优先级高于元素选择器。
3. 继承
对经过了前两步骤之后「仍然没有值」的属性,若「可以继承」的属性,则使用继承。
CSS 中的很多属性是可以被继承的。例如 color 和 font-family 等样式会从父元素传递到子元素。
注意 📢:
- 可继承属性:如 color、font-family、line-height 等。这些属性如果在子元素中没有显式指定,会继承父元素的值。
- 不可继承属性:如 border、margin、padding。这些属性不会从父元素继承。
- inherit 关键字:可以强制任何属性继承父元素的值,即使该属性默认不可继承。
举个 🌰
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
.container {
border: 2px solid #f3ddf3;
border-radius: 6px;
color: orchid;
}
.paragraph {
border: inherit;
border-radius: inherit;
}
</style>
</head>
<body>
<div class="container">
父元素 div
<p class="paragraph">子元素:强制继承父元素</p>
</div>
</body>
</html>
color 属性是自动继承,border 属性是强制继承。继承之前和继承之后:
- initial 关键字:将属性值重置为默认值,通常用于恢复浏览器的默认样式。
举个 🌰
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
.container {
border: 2px solid #f3ddf3;
border-radius: 6px;
color: orchid;
padding: 10px;
font-size: 26px;
}
#div {
font-size: inherit;
}
</style>
</head>
<body>
<div id="div" class="container">恢复浏览器的默认样式</div>
</body>
</html>
4. 默认值
最后,对「仍然没有值」的属性,使用 MDN 官网的默认值。
以上就是 CSS 属性的计算过程,对于页面上所有元素的 CSS 属性都是如此。
浏览器从 CSS 代码到最终的样式渲染过程中,经过多个阶段完成。为了达到视觉上最终的样式,浏览器会解析样式表、继承和应用样式值,最后计算出应用到每个元素的具体样式。
补充一些:
5. 计算值(Computed Value)
经过优先级和继承计算后,浏览器会获得每个元素的计算值。在这个阶段,所有的相对值都会转换为绝对值。例如,em、% 等相对单位会被计算成具体的像素值。
具体过程:
- 相对单位计算:em 是相对于父元素的字体大小,% 是相对于某个父级元素的尺寸。例如,如果父元素的 font-size 是 16px,那么 2em 相当于 32px。
- 百分比计算:通常用在宽高、边距、位置等属性中,比如 width: 50% 是基于父元素宽度的 50%。
🌰
div {
width: 50%; /* 计算值取决于父元素的宽度 */
font-size: 2em; /* 计算值取决于父元素的字体大小 */
}
6. 使用值(Used Value)
使用值是 CSS 属性值的另一个阶段,是在计算值的基础上进一步确定的。例如,在 width 和 height 的计算中,如果内容溢出了容器,浏览器可能会调整某些属性的值。
- 溢出处理:当一个元素内容比容器大时,overflow 属性会决定如何处理,比如裁剪内容或显示滚动条。
div {
width: 100px;
height: 50px;
overflow: scroll; /* 超出范围时,显示滚动条 */
}
7. 实际值(Actual Value)
实际值是元素在显示时真正呈现出来的样式,结合了设备特性和环境(如分辨率、DPI)等因素。在不同的设备上,元素的实际渲染可能会有所不同。
- DPI 和屏幕缩放:在高分辨率设备上,元素可能看起来比低分辨率设备要小,因此实际显示的像素值会有所不同。浏览器会根据设备的 DPI 调整实际显示值。
8. 布局阶段(Layout Phase)
布局阶段是浏览器根据已计算的样式值,计算出每个元素的大小和位置的过程。这个过程通常依赖于 box model(盒模型),以及 display、position 等布局属性。
注意点📢:
1、盒模型:元素的大小由 content、padding、border 和 margin 决定,布局时需要将这些因素考虑在内。
2、流式布局:默认情况下,块级元素会垂直排列,内联元素会水平排列。
3、浮动和清除:float 属性会改变元素在文档流中的行为,而 clear 用于清除浮动对其他元素的影响。
9. 渲染阶段(Rendering Phase)
最后,浏览器将经过布局计算后的元素绘制到页面上。这一步还包括处理 CSS 中的颜色、字体、阴影等视觉效果。
注意点:重绘(Repaint)与回流(Reflow):修改布局属性(如 width、height)会触发回流,而修改视觉属性(如 color)只会触发重绘。回流比重绘消耗更多资源,因此在性能优化中应尽量减少回流的发生。
10. 总结
1、浏览器的默认样式表:浏览器会应用一套默认样式,确保即使不编写样式表,HTML 也有基本的可读性。
2、使用 initial、inherit、unset 等关键字:这些关键字可以帮助控制样式的继承与重置。
- initial:重置为初始值;
- inherit:强制继承父元素的值;
- unset:依据属性是否可继承来决定使用初始值或继承值。
3、动态单位:vh、vw 等单位可以用于动态布局。它们表示相对于视口宽度或高度的值。
div {
width: 50vw; /* 宽度是视口宽度的 50% */
height: 100vh; /* 高度是视口高度的 100% */
}
4、相对单位和绝对单位的区别:绝对单位(如 px)在不同设备上表现一致,而相对单位(如 %、em)的行为依赖于父元素或上下文。