CSS 对象模型
DOM 树建立之后,CSS 编译器开始工作。整个过程与 HTML 编译过程基本一致:将 CSS 字符串经过词法、语法分析后,变成一组样式规则集合,也就是 CSSOM,称为 CSS 对象模型。
每一个内部样式表( style 标签内,包括 @import 引用 )、外部样式表( link 引用 )和 HTML 元素的内联 style 属性值都会单独生成一个 CSSOM。
CSSOM 是在 DOM 接口的基础上进行的扩展,因此 JavaScript 访问 CSSOM 需要通过 DOM 提供的接口去实现。例如,访问内部和外部样式规则,需要通过 document 上的 styleSheets 属性;访问内联 style 样式规则,需要通过 HTML 元素的 style 属性。
例子:
//省略了部分代码
<head>
<style>
div {
background: #ccc;
}
p {
color: #ff0000;
}
</style>
</head>
<body>
<div>
<p style="font-size:20px">hello</p>
</div>
</body>
CSSOM 示意图( 图片仅供参考,并不完全准确 )
CSSOM 在谷歌浏览器中的存在形式
我们可以在谷歌浏览器的控制台上,直接操作 CSSOM:
//输入以下代码
document.styleSheets[0].rules[1].style.color="#fff";
document.getElementsByTagName("div")[0].style.backgroundColor="#ff0000";
CSS 样式匹配
CSSOM 建立完成之后,渲染引擎将一直保存这个规则结果。然后,引擎开始为可视 DOM 节点(1)匹配合适的样式信息。匹配的过程可以大致分为以下 5 步:
*(1)可视 DOM 节点:DOM 节点中,例如 div、span、img 等节点,是用来展示页面内容的,因此称之为“ 可视节点 ”。与之相反的,head、meta 等节点,或者设置了 display:none
的节点,不会进入最终的布局与绘图环节,页面的最终显示结果,也不会有所体现,因此称这类节点为" 非可视节点 "。
- 首先,为节点创建 RenderStyle 对象,以保存所有匹配到的样式;
- 紧接着,开始匹配浏览器默认样式规则,依次按照 ID、className、标签名等选择器信息逐步匹配,如果匹配上该节点,则添加进 RenderStyle 对象;
- 然后,开始匹配内部和外部样式规则,依次按照 ID、className、标签名等选择器信息逐步匹配,如果匹配上该节点,则添加进 RenderStyle 对象;
- 再然后,将内联 style 样式规则添加进 RenderStyle 对象;
- 最后,渲染引擎对 RenderStyle 对象中的样式规则进行排序,并返回该对象。
例子:
//省略了部分代码
<head>
<style>
div {
background: #ccc;
}
p {
color: #ff0000;
}
</style>
</head>
<body>
<div>
<p style="font-size:20px">hello</p>
</div>
</body>
上例中,我们打开谷歌浏览器,在开发者工具中,点击 P 元素,左边显示的就是该元素最终的匹配结果。
选择器的权重
大多数情况下,同一个节点都会同时匹配到多个样式规则。那么,该节点应该使用哪些样式呢?
通常,渲染引擎会根据选择器的权重来判断,选择器描述的越具体,权重越高,下面介绍一些常用选择器的权重:
*下列选择器的权重依次递增
-
通配符
该类选择器的权重为0。 -
标签选择器和伪元素
该类选择器的权重为1。 -
类选择器、属性选择器和伪类
该类选择器的权重为10。 -
ID选择器
该类选择器的权重为100。 -
内联样式
可以覆盖任何由选择器匹配到的样式规则。 -
!important 声明
带有 !important 声明的样式将覆盖任何其他样式规则。
计算选择器的权重
1、每一种选择器类型的数值相加,应用选择器权重高的样式。
例子:
<style>
/* 标签选择器 + 属性选择器 = 11 */
p[class=text] {
color: brown;
}
/* 类选择器 = 10 */
.text {
color: blue;
}
</style>
<!-- p 元素应用 p[class=text] 中的样式 -->
<p class="text">hello</p>
2、选择器权重相等时,应用最后的那个选择器中的样式。
例子:
<style>
/* 属性选择器 = 10 */
[class=text] {
color: brown;
}
/* 类选择器 = 10 */
.text {
color: blue;
}
</style>
<!-- p 元素应用 .text 中的样式 -->
<p class="text">hello</p>
3、直接作用于元素的样式规则会覆盖继承而来的规则。
例子:
<style>
#box {
color: brown;
}
p {
color: blue;
}
</style>
<div id="box">
<!-- p 元素应用 p 中的样式 -->
<p>hello</p>
</div>
4、DOM 树中元素的距离对权重没有影响。
例子:
<style>
#box p {
color: brown;
}
#main p {
color: blue;
}
</style>
<div id="main">
<div id="box">
<!-- p 元素应用 #main p 中的样式 -->
<p>hello</p>
</div>
</div>
CSSOM View
除了我们上面讲的 CSS 对象模型,其实还有另外一种 CSS 模型,即 CSS 视图模型( CSSOM View )。它的基本含义是为 DOM 节点增加了一些可以访问视图方面的样式信息。扩展的这些属性有些还是很常用的,下面列举几个,具体使用方法和兼容性问题,可以自行查询。
Window 扩展
innerWidth 和 innerHeight
获取浏览器窗口视口的宽/高,包括滚动条。只读。outerWidth 和 outerHeight
获取整个浏览器窗口的宽/高。只读。pageXOffset 和 pageYOffset
获取整个页面水平/垂直滚动的像素值。只读。screenX 和 screenY
获取浏览器窗口在显示器中水平/垂直位置。只读。
HTMLElement 扩展
clientLeft 和 clientTop
获取元素左/上边框的宽度。只读。clientWidth 和 clientHeight
获取元素的内部宽/高,包括内边距,但不包括边框。只读。offsetLeft 和 offsetTop
获取距离最近的拥有定位的父元素的左侧/上侧偏移量。只读。offsetParent
获取距离最近的拥有定位的父元素。只读。offsetWidth 和 offsetHeight
获取元素的宽/高,包括内边距和边框。只读。scrollLeft 和 scrollTop
获取或设置元素距离左侧/上侧滚动的像素值。可读可写。scrollWidth 和 scrollHeight
获取元素内部宽/高,包括由于溢出不可见的区域( 出现滚动条 )。只读。
MouseEvent 扩展
clientX 和 clientY
获取鼠标相对于浏览器窗口( window )的 X / Y 坐标。只读。pageX 和 pageY
获取鼠标相对于文档( document )的 X / Y 坐标。只读。screenX 和 screenY
获取鼠标相对于显示器的 X / Y 坐标。只读。
如有错误,欢迎指正,本人不胜感激。