【正视CSS 06】构建我们自己的世界观!
前言
我们很小的时候什么都不知道,于是什么都会是别人对我们解释,也许是父母,也许是师长,但是随着年龄的增大,我们会逐步形成自己的世界观,并且当我们有小孩时候,他会问我们很多问题,我们会为他解答,那么我们的答案有何而来呢?
我们的答案来自我们自己的世界,来自我们自己形成的世界观!
我们初学 CSS 时候什么也不知道,于是我们从书上、博客上获取了很多知识,那么我们是不是也应该形成自己的世界观呢?我们碰到的问题是不是都可以用我们形成的世界观解释呢?
以上是我最近思考的问题,我觉得我们有必要形成自己的世界观了,形成世界观才是长大的标志,我形成的世界观可以不坚固,可以很小但是他必须存在,你们的也必须存在。
我们需要捍卫我们的世界观,我们需要建造我们的世界观,当我们的世界足够大,足够发达的时候,我们就会被称为高手啦,哇哈哈!!!
师尊,我们的页面是哪里来的?
在我们的浏览器中输入了一个 url 后,我们的服务器便会返回一堆字符串给我们,这个字符串就是传说中 html。
从得到 html 字节开始,dom 树便开始勾践了,遇到以下情况时候 dom 树的构建会被暂时阻塞:
① 网络卡
② 有未加载的脚本
③ 样式还未加载结束就遇到 script
dom 树是基础,dom 树构建结束以后便根据样式与 dom 构建我们的渲染树了,这个时候样式文件便会阻塞我们的页面渲染。
PS:有些网页会把 CSS 写在页面里,而不是外部文件是为了避免页面闪烁,或者出现裸奔的局面。
当样式表加载结束后,渲染树也被构建好了,我们的页面就基本成型了。
渲染树一旦构建完成后,若是 js 脚本操作 dom,就很可能引起页面回流,过多的回流是前端性能的杀手。
浏览器下载的顺序是由上到下的,渲染顺序也是由上到下的,下载样式表与渲染树形成是同步完成的
在渲染到页面某一部分时,上面的所有部分已经下载完成,并且渲染结束(一旦有 js 引起改变,边可能引起之前元素发生回流)
若是浏览器中有多个样式表,在所有样式表下载结束后浏览器又会将所有的样式表放到一起重新解析,会对之前的所有元素重新渲染,所以样式表过多也不是太好的。
PS:我们在做页面时候要注意页面的大小开始不宜过大,这样可以渲染的很快,以延迟加载的方式进行。
以上的逻辑可以分割如下:
① 构建 dom 树
② 构建 render 树
PS:渲染树,写英文为了防止以后被问到不知道是什么,包含颜色和属性的矩形块。
③ 布局 render 树,确定每个节点在屏幕上的确切坐标,然后开始绘制。
师尊,我们的页面如何布局呢?
以上为浏览器干的事情,他干完了就形成了我们所看到的页面,我们不需要过于关注,但是我们需要关注他的布局。
当渲染树被创建并添加到树中,他并没有位置和大小,计算他位置与大小的过程便是 layout 或者 reflow。
每个渲染对象都有一个 layout 或者 reflow 方法,每个渲染对象须有布局的 children 的 layout 方法。
每个小变化都可能导致重新布局,浏览器使用一个 dirty bit 系统,一个渲染对象发生变化就会标记他以及他的 children 胃 dirty,就会重新布局之,若是仅仅是其 children 有问题的话,就只会搞他的 children。
全局回流(reflow)是需要避免的,因为其很耗性能,窗口改变会引起全局回流是可以理解的,但是改变整个浏览器字体大小的事情我们要少做。
渲染一个对象时候,这个元素的尺寸(高度不定)由其 parent 决定,他又会决定其 children 对象,children 积累高度与 margin、padding 便为自己的尺寸,总之这个过程中浏览器很忙。
浏览器在渲染页面的时候很忙,所以你一个不小心哪里不如他意了他就会使坏的,所以不要一来就认为浏览器有 bug,他忙自然关注不了太多。
PS:元素绘制的过程就是讲元素压入堆栈的过程,一个渲染对象的堆栈顺序为:背景色 -> 背景图 ->border->children->outline。所以我们在写 css 时候规则可言参照之
CSS 规定所有元素都应该具有盒模型(内容区、padding、border、margin),但是不同元素又有差异:
块级元素——块级盒模型
行内元素——生成一个或者多个 inline boxes ,inline boxes 组成 line boxes 确定其行高
none——不生成盒模型
师尊,什么是盒模型?
盒模型对我们后面的布局至关重要
浏览器要定位元素就必须知道其定位与尺寸, 浏览器有三种方式布局:
① normal 根据自身和模型大小布局
② float 开始与普通流类似,然后脱离文档尽可能靠左或者靠右
③ absolute 与 dom 无关,根据 top 等决定位置,盒模型决定尺寸
以上三种无论如何都应该有其支点,这个支点就是传说中的 containing block(包含快),也就是元素所处容器,再简单点就是依赖于其 parent 了(这块可能有误)
前面我们说过,每个元素皆遵循盒模型定理,所以各个元素可以简单看做一个个盒子,小盒子摆放依赖于大盒子。
① static/relative 元素包含快为其父元素的内容区(出去 padding 部分)
② absolute 包含快为最近定位元素(absolute/relative)
③ fixed 为根元素(html)
④ float 包含快为最近的块级元素
师尊,BFC/IFC 又是什么?
而在盒子们布局时候为了减除彼此间的影响,便出现了 block formatting context(块级上下文)这种布局特性,我理解为隔开盒子的隔板。
以下行为会产生 bfc:
① float 不为 none
② overflow 不为 visible
③ display 为 table-cell,table-caption,inline-block 中的任何一个
④ position 不为 relative 和 static 时
在 IE7 以下没有 BFC 的概念,其为了解决的这个问题便提出了 haslayout,两者之间可以画等号,但是 haslayout bug 较多,所以 IE7 以下有很多 bug。
相邻的块级元素之间会发生 margin collapse 现象,便是外边距叠加行为。
这个原因便是相邻且在同一 bfc 时垂直外边距叠加行为。
垂直外边距便会叠加要解决的话,
有两种方案(不让其相邻,处在不同的 bfc)可以为外部设置 padding 属性将彼此隔开,当然也可以使用 overflow 触发器 bfc 导致其处在不同的 bfc,便不会造成叠加
师尊,块级元素又是什么?
有了以上知识后,我们再来看看块级元素
块级元素会独占一行,在 normal 中,其排布由其盒模型确定
PS:IE6 盒模型解析有误,需要向下兼容需要处理
块级元素为布局大户,他与 position 的配合便是布局的瑞士军刀。
我这里对 absolute 布局的块级元素有两种理解:
1 absolute 破坏了元素的高宽,并且将其剥离正常文档流,而形成了一个会飞的 inline-block 元素,其初始原点(top/left)与文档流中正常元素一致,但不会影响其它元素
2 absolute 拥有了自己的 bfc 环境,自成一格与主流 bfc 分割开后,大小由盒模型确定,位置由 top 等确定
因为页面上可能出现多个 absolute,所以彼此间的显示可能出现遮盖的现象,所以我们有了 z-index 遮盖家伙帮我们干事。
PS:我猜测,要让元素靠近我们其实是让其 bfc 靠近我们,而 ie7 以下不存在 bfc,取而代之的是 haslayout,所以在 ie7 以下便会有这样那样的 bug,并且元素需要依赖其父元素的 z-index,事实上便是子元素的 haslayout 需要依赖父元素的 haslayout,他这样的真相便是,标准浏览器的 bfc 是各自独立的,ie7/6 的 haslayout 是依赖于父元素的(猜测,欢迎拍砖)
行内元素
对于行内元素来说,每个字会形成一个匿名 inline boxes,每个行内元素也会有一个 inline boxes,一行的 inline boxes 便会形成一个 line boxes,行框决定着这行的高度。
但是,我们这里的 inline boxes 干了什么事呢?
既然有块级格式上下文,便会有 inline formatting contexts(行内格式化上下文)
ifc 中,inline boxes 都是水平排列的,起点是其 containing block 的头部,
PS:这块我有所欠缺,后面再补上
inline boxes 会撑开 line boxes,line boxes 才给予了我们一行的高度,所以文字撑不开高度,是 inline boxes 撑开的高度,最后便是 line-height 决定高度(若是块级元素的高度未设定)。
float
我们知道 float 也会创建独立的 bfc,这里我对他的理解也形成了两种:
1 float 这家伙破坏了元素的高度,将之变为会左右移动的 inline-block,虽然高度不存在了,但是宽度还在,所以其它文本会围绕之,块级元素(边框等)却会覆盖之。
2 float 拥有了自己的 bfc 了,所以脱离了文档流,其 margin 属性与其它元素无关了(该理念还无法成型,暂时依赖第一个吧)
你的世界观形成了吗?
至此,我们便了解了 css 中的很多东西了,我们以此形成了世界观,于是我们今后需要在此世界中找到所有我们需要的答案,若是找不到就说明这个世界还不够发达,需要你在建,我们需要维护他,不让他崩毁,但他若是真的崩毁了也不要紧,因为你在形成的世界会无比的辉煌!!!
好了我们以此世界观来解释我们遇到的一些问题:
兼容性问题?
其实我们说的兼容性问题主要是 IE7 以下有问题,IE7 以下因为不存在 BFC 而替用了 haslayout,所以会有很多 bug,针对 bug,
高手会避免 haslayout 产生问题,而一般人会选择使用 hack 技术
为什么会高度坍塌?
因为 float 破坏了元素的 inline boxes,而我们的 inline boxes 撑开了我们的块级元素,所以不动态指定高度的话,其实不会具有高度的。
如何解决高度坍塌,其原理是什么?
clear:我这里猜测清除浮动强制修复了行内元素的 inline boxes,所以元素又能撑开块级元素了(但是我不能证明自己)
overflow:overflow 触发了元素的 bfc,让元素具有独立的 bfc,所以其元素不用坍塌了!以上就是坑爹的!因为我自欺欺人都不行,何况忽悠你们,所以我们这里换个说法,这里我想换个思路,我们知道 bfc 其实就是格式化上下文,说白了他会包裹着我们的元素(我们在 IE7 中有时候用 a 标签模拟按钮,但是没戏,触发 layout 后便可以了,应该就是这个原理),若是我们来看看触发了 bfc 的元素,他本来都没了高度,但是我要包括你,我们不能包裹没有的东西吧,所以浏览器又被迫恢复了其 inline boxes。
PS:我第一是确实一时间找不到还有什么问题可以让我自说自答了,二来是怕真的出现问题答不起,我好不容易搭建起了的世界就给崩毁了就太伤心啦,所以我暂时不在问自己问题了。
为什么我在 js 操作 dom 的时候风扇会不停的转?
因为操作 dom 后可能引起大量回流 reflow,所以页面又要重新布局,这个过程很耗资源的。
为什么我们要指定图片的容器宽度
因为图片加载后,若是宽度不固定,会撑开他所在页面,以下部分会发生下层现象,也是一种 reflow,(dom 构建结束后才加载图片)
结语
我形成了自己的 CSS 时间观了,虽然他还很脆弱,但是我会慢慢建设他,让我的 CSS 世界坚固而美丽。
各位,若是你们觉得有什么不足以及错误,请提出哦。