Skip to content

Latest commit

 

History

History
349 lines (238 loc) · 17.1 KB

css世界.md

File metadata and controls

349 lines (238 loc) · 17.1 KB

《CSS 世界》读书笔记

本书可以说是深入理解 CSS 原理的必读之书,作者张鑫旭也是十年磨一剑,编写了这本独一无二的 CSS 书籍。读其他 CSS 的书籍只能做到知其然,而读这本书却能做到知其所以然。没别的称赞,果断推荐,而且我觉得应该所有的前端开发者都应该好好拜读这本书,以强化自己的 CSS 知识和认知。

本书一开始先给大家构建了一个 CSS 的时间观,让读者知道 CSS 在这个缤纷的网络世界中扮演了什么样的角色,有什么价值。接下来,全书以“流”这个 CSS 设计时最核心的思路,来讲了我们开发常用的一些样式和语法,它们如何构建一个“流”的世界。除了“流”之外,本书也讲了其他的内容,不过那不是我关心的重点。

最后,本书讲解的内容都是 CSS 2.1 版本的,发布距今都已经 10+ 年了,可以说是最常用、最普及的知识了。CSS 3 的知识本书没有涉及,作者没有解释,但是读到最后我想明白了这个原因 —— 本书立意独特,讲解的都是作者精心准备、读者常不理解或者犯错误的知识点,例如float的使用、line-height的认知等。而这些易理解出错的方面,CSS 2.1 中有很多,但是 CSS 3 中却很少。因为,CSS 2.1 很多语法的设计初衷和现在的使用场景都不一致,导致很多误解或者误用,而 CSS 3 设计用意和场景完全匹配,误用很少。因此,CSS 3 也就没得讲了,干脆就不讲了。

当然,以上的这个原因,纯属我个人的猜测。如有雷同,也属于巧合。最后,再重点强调一下 CSS 2.1 的设计初衷:

CSS 2.1 是为图文展示而设计的。

CSS 世界观

书中这部分内容比较少,但是作者提出来的这个比喻我觉得特别贴切。这么一比喻,就把 CSS 与浏览器、操作系统的关系给一下子说清楚了,生动形象。

  • 操作系统是宇宙,浏览器是王国,css 是一个一个的魔法师,例如width魔法师、font魔法师……
  • 不同的操作系统就是不同的平行宇宙,比较强大的如 windows, os X, ios, android
  • 不同的宇宙中王国的命运不一样,例如 os X 宇宙中 safari 王国比较强大,而 windows 宇宙中 safari 王国就异常没落
  • 不同宇宙或者不同王国中,魔法师在法力表现上也不尽相同,如 chrome 王国和 firefox 王国中的魔法师,有些法术可能就不太一样(即浏览器兼容性)

书中这部分也内容比较少,但是我觉得“流”这个概念对于本书的阅读和理解非常总要,因此就单拿出来一个大标题来重点说明,可能文字并不多。

书中提到,SVG 的标准在 2003 年就发布了,而 CSS 2.1 的标准直到 2007 年才发布,而那时候 web 1.0 已经很普及了,但是最终还是 CSS 战胜了 SVG 成为了网页布局的主导语言。究其原因,第一是因为 CSS 更加适合图文布局,第二就是 CSS 的“流”特性。当然,SVG 后来换发第二春,成为了 canvas 直接的竞争对手,也是因为网页图形化的兴起,这是另外一回事儿。

“流”,我理解就是它能在不同尺寸的容器中,合理的处理图文信息的这种不确定性,其实就是流动特点。图片可大可小,文字可多可少、字体多变,再加上尺寸多变,这种不确定性只能通过“流”去解决。例如一个不确定尺寸的容器,只能用水来完全填满,而水就具有流动特性。具体 CSS 的例子就不列举了,下文遍地都是,在这里也列举不全。

元素的尺寸

width

width:auto使用场景很多,表现形式也很多,书中提到以下几种情况:

  • 充分利用可用空间,即流动性。例如<div>会自动铺满整个父容器。
  • 收缩和包裹,例如浮动和绝对定位的“包裹性”,
  • 收缩到最小,例如表格中每个单元格的文字,会自动收缩
  • 超出容器限制,例如其中的内联元素设置了white-space: nowrap

其中最常用的就是,让<div>铺满父容器时,不要故意设置width:100%,因为还可能会有 padding margin border 的宽度影响,让其自适应就好了。

针对盒子模型来说,width默认作用域content-box上,即内容区域。现在的普遍做法是增加box-sizing: boxer-box。不过作者的另外一种解决方案也非常体现“流”特性。

.father {
	width: 180px;
}
.son {
	margin: 0 20px;
	padding: 20px;
	border: 1px solid;
}

最后作者解释了box-sizing设计的初衷,让我读来眼界大开。因为我们专业于一门技术,不仅仅要知道 what 和 how ,还要知道 why 。书中提到,box-sizing的设计初衷是为了解决替换替换元素宽度自适应问题。所谓的“替换元素”可以简单的理解为各种表单元素,例如input textarea video object 还有 img ,这些元素的样式最难控制。

替换元素有一个特点,例如textarea,宽度不容易被控制,不具有流动性。即,div如果不设置宽度会撑满父容器,而textarea则不会。这种情况下,如果没有box-sizing的话,我们没法通过控制宽度来实现自适应。例如,如果针对textarea设置width:100%,是作用域content-box,再加上padding border宽度,就超出父元素了。

height

CSS 的默认“流”是水平方向的,宽度是稀缺的,高度是无限的

有时候设置height:100%无效,是因为只要父元素是height:auto,子元素在文档流中(不是float或者absolute),那么子元素的高度百分比就被忽略 ,记住这条原则。要想解决这个问题,就得让父元素必须有一个可以生效的高度值,例如:

html. body {
	height: 100%;
}
div {
	height: 100%;
}

当然,直接对div设置绝对定位,也可以让height:100%生效。不过注意,绝对定位的宽高百分比计算是相对于padding-box的,而正常情况下的计算则是相对于content-box

内联元素

块级原则负责结构,内联元素负责内容

内联元素不仅仅是display: inlineinline-block inline-table也算是内联元素,其表现就是可以和文字在一行显示。

书中提到了“内联盒子模型”,可以对比一下普通的盒子模型。不过这个模型日常使用中基本不会关心到,因此简单列一下,详细内容去看书。

  • 内容区域
  • 内联盒子
  • 行框盒子
  • 包含盒子

最后书中提出了一个非常非常非常重要的概念 —— 幽灵空白节点(作者起的名字),这是日常开发中实时遇到但却实时被大家忽略的一个问题。该问题触发有一个前提,就是必须是 HTML5 文档声明。

<!doctype html>
<html>

如下例子,这个div的高度并不是 0 ,而是 18px 。命名里面什么内容都没有,为何有高度呢?

<div><span></span></div>

其实可以这么理解,<span>前面有一个宽度为 0 的空白字符(即幽灵空白节点),它撑起了整个内联元素的高度,也就撑起了<div>的高度。

这个空白节点的影响,会出现于没有文字的内联元素场景中,而且基本是以“坑”的形式来出现的。例如,下面代码执行后,imgdiv的下边界会有一个空白区域,这是为何?

<div>
	<img src="xxx.png"/>
</div>

盒模型

盒模型是 CSS 的基础知识,它包含四个盒子:content-box, padding-box, border-box, margin-box ,书中也是按照这个顺序来写的,下面针对一些印象比较深的内容做记录。

content

替换元素,即可以被替换的元素。常见的有<img> <object> <video> <iframe> <textarea> <input> <select>。替换元素有以下几个特点:

  • 内容可替换,例如图片 src 可随意换
  • 基本样式 CSS 很难改变,你无法通过 CSS 将<select>做的像某些 UI 组件那么漂亮
  • 有自己的尺寸,基线是下边缘,<video>默认就有自己的尺寸,<textarea>可以通过rowcol修改尺寸,<img>的基线就是其下边缘

简单来说,替换元素有自己的一套尺寸计算逻辑,并不符合“流”特性。

padding

块状元素的 padding 比较简单。对于内联元素的 padding ,水平方向会影响布局,而垂直方向可增加其可视区域却不会影响布局。这也是好多开发者以为内联元素的垂直 padding 不起作用的原因。此处书中提到了两个例子,都是在不改变布局的情况下,第一是增加链接的可点击区域,第二是对锚点标题设置边距,都很实用。

padding 不支持负值,但是支持百分比。注意,无论是水平方向还是垂直方向的百分比,都是根据元素的宽度计算的

margin

如果该元素是流式填满父容器的元素,则 margin 设置负值可以改变其可视区域,但不影响布局。例如书中 84 页的示例,一行有三个卡片,最后一个和父容器没有间隙,比较常用。

margin 设置百分比值,和 padding 一样,无论是水平还是垂直方向,都是相对于元素宽度做计算的。

垂直方向的 margin 合并是开发中常见的“坑”,下面列出三种常见的场景并给出示例:

第一种情况,相邻兄弟元素的 margin 合并,这是最常见的,示例如下。这个问题并不会造成什么困扰,因此不用规避。

<style>
	p {margin: 1em 0}
</style>
<p>第一行</p>
<p>第二行</p>

第二种情况,父元素和第一个/最后一个子元素,就是经常被问到的margin-top失效的问题。示例如下:

<div>
	<div style="margin-top:80px">内容</div>
</div>

该示例会触发的问题是,子元素的margin-top会作用域父元素上,和我们书写的预期完全不一致。解决这个问题,有以下途径:

  • 让父元素 BFC
  • 给父元素设置border-top
  • 给父元素设置padding-top
  • 父元素和子元素之前添加一个内联元素作为分离

第三种情况,空块级元素的 margin 合并。如下例子。

<style>
	.father {
		overflow: hidden;
	}
	.son {
		margin: 1em 0;
	}
</style>
<div class="father">
	<div class="son"></div>
</div>

该示例中,子元素的margin-topmargin-bottom会合并在一起,导致子元素的高度只有1em —— 前提是子元素是空的,没有任何内容。

其中这种场景,通过下面的例子解释就很清楚了。下面的示例中,AAABBB之间的距离就应该是10px,而不是离着很远。

<style>
	p {
		margin: 10px 0;
	}
</style>
<p>AAA</p>
<p></p>
<p></p>
<p></p>
<p>BBB</p>

说完了垂直合并,再看看margin: auto带来的流动性。margin:auto是为了填充闲置的尺寸而设计的,规则是:

  • 如果一侧定值,一侧 auto ,则 auto 为剩余空间大小
  • 如果两侧都是 auto ,则评分剩余空间

例如靠左对齐

.son {
	width: 200px;
	margin-right: auto
}

例如水平居中对齐

.son {
	width: 200px;
	margin: 0 auto;
}

例如水平垂直居中对齐

.son {
	posotion: absolute;
	top: 0; right: 0; bottom: 0; left: 0;
	width: 200px; height: 100px;
	margin: auto; /**将上下左右的空白区域都均分并自动填充**/
}

border

这部分没有要记录的内容。

内联元素

内联元素有两个知识点 —— line-heightvertical-align

基线

line-height 是两个基线之间的距离,vertical-aligin 的默认值就是基线(baseline),基线到底是什么?基线,就是一行文字中字母x的下边缘

line-height

内联元素的高度是由 line-height 决定的,并不是 font-size 。而且,对于非替换元素的内联元素,其高度完全由 line-height 决定,跟 fontsize border padding 都没有关系。但是,line-height 却无法决定替换元素的高度,例如一行文字中有图片,图片的高度时不受这一行的 line-height 影响的。

line-height 可以让单行或者多行文字近似的垂直居中。因为 vertical-align 默认是基线对齐,而基线对齐并不一定就是垂直居中对齐。想要实现绝对的垂直居中,还需要 vertical-align 帮忙。如下代码(注意看注释):

<style>
	.box {
		line-height: 120px; /* 对内联元素前面的空白幽灵节点起作用,使其能撑开整个盒子 */
		backgroud-color: #ccc;
	}
	.content {
		display: inline-block; /* 使当前元素为内联元素,因此前面会出现空白幽灵节点 */
		line-height: 20px;
		vertical-align: middle;
	}
</style>
<div class="box">
	<div class="content">段落内容。。。</div>
</div>

以上方法,也可以用于图片的垂直居中,只需要将<div class="content">换成<img/>即可。

line-height 的继承无处不在,而line-height 不同值类型对于继承也会有不同的影响,这一点经常被考察到。例如

  • line-height: 50px这种固定尺寸,往下继承的就是50px
  • line-height: 1.5这种数值,往下继承的就是1.5这个倍数
  • line-height: 150%或者line-height: 1.5em这种方式,往下继承的是当前计算出来的数值,而不是倍数,这里一定要注意!!!

vertical-align

vertial-align 只有在内联元素以及 table-cell(即表格单元格)元素中才能生效,vertical-align 值比较多,可参考 http://www.w3school.com.cn/cssref/pr_pos_vertical-align.asp 。其中,书中重点强调了可使用数字或者百分比,用处比较大。例如,当文字和小图标一行时,小图标位置偏上,可以给小图标设置line-height: -5px让其下移,书中 128 页。

书中这里还讲解了好多 vertical-align 的内容,不过我没有继续往下看,因为感觉这些内容已经太深太专业了,和日常的开发联系并不大,因此就先跳过。

流的破坏和保护

本章讲解的元素没有流动特性,而是对流动特性的破坏,但是这也和“流”有关。主要与floot BFC absolute相关。

float

首先,float 是一个很古老的样式属性,它设计的初衷就是实现简单的图文混排(像报纸一样),并没有考虑其他的使用场景。而现在 float 被大家大量的用来做布局使用,做不是它设计初衷的事情,肯定会出现很多问题,也失去了流动性。因此,float 是魔鬼,尽量不要触发它,能躲则躲。CSS3 慢慢普及之后,我们可以使用 flex grid 来做布局,不要再用 float 了。

元素设置了 float 会有以下几个特性:

  • 包裹性。本来元素是自动撑满整个父容器的,设置了 float 之后就会收缩,紧紧包裹住内容。
  • 触发 BFC(是其中一个条件)
  • 破坏文档流,使父元素塌陷
  • 没有任何 margin 合并。都跳出文档流了,肯定也不符合流式布局的特点了。

float 和流式布局也可以结合使用,例如左右布局,左侧元素宽度60px并且设置float,右侧设置margin-left: 70px即可,书中 156 页。

最后,和 float 分不开的还有 clear ,基本一个clear-fix就能搞定了。

BFC

BFC,block formatting context,跨级格式化上下文。如果一个元素触发了 BFC ,那其内部元素无论设置什么样式变化,都不会对元素外部产生影响。BFC 元素不能出现 margin 重叠,也不可能收到 float 的影响。能触发 BFC 的条件是:

  • <html>跟元素
  • float 不是 none
  • overflow: auto/scroll/hidden
  • display: table-cell/table-caption/inline-block
  • position: fixed/absolute

即,只要符合以上条件之一,都不需要使用clear:both来清除浮动,因为 BFC 元素不会收到浮动影响布局。

一般用于触发 BFC 的条件是overflow: hidden,它简单好用又不会对布局产生影响。float 结合 BFC 可以写成:

<style>
	.left {float: left}
	.right {float: right}
	.bfc {overflow: hidden} /* 专门定一个一个 bfc 的 class */
</style>
<div class="bfc">
	<img src="xxx.png" class="left"/>
	<p class="bfc">文字内容……</p>
</div>

absolute

absolute 也具有破坏性和包裹性,这一点和 float 一样。absoute 还有一个重要的特性是无依赖,书中 184 页讲到,因为我之前了解过这块,因此就不再写了,但是确实很重要很常用。

另外,absolute 和 fixed 在和overflow:hidden一起使用时,可能会遇到各种无法隐藏的问题,因此不要一起混用。如果遇到 absolute 和 fixed 元素需要裁剪时,可使用clip语法,不会出问题

最后,absolute 可体现流体特性,从一个垂直居中对齐即可体现,即结合margin:auto,上文已经写了这个 demo 了,书中 202 页有。

其他非“流”内容

其他和流体布局关系不大的内容,读来对我的印象没有那么深,用起来也不容易出现误解和问题,不重点关注了。

总结

CSS 是“流”的世界,这包括:

  • 元素尺寸
  • 盒子模型
  • 内联元素
  • 流的破坏和保护(float、BFC、absolute)

而这,就是 CSS2.1 的最核心内容。