前端基础篇之CSS世界

我想你每天写css代码有时候也会觉得很痛苦:这个布局的css怎么这么难实现!我也经常会有这种感觉,一个看似简单的布局总是要琢磨半天才能实现,偶尔还会出现一些怪异的超出理解的现象。这是因为我们对css只是大概知道个形,并没有看透css的本质。在同事的推荐下我阅读了张鑫旭老师的《css世界》,才发现css跟想象中的不太一样。本文为《css世界》个人总结笔记,为缩减篇幅丢弃了张老师冗余的小幽默,丢掉了些含金量较低的章节内容,因为ie已经被淘汰出局,所以有关css兼容性的地方也全部忽略不记,同时对个人觉得不易理解的地方加上了一些自己的理解和验证,所以错误之处还望指正。顺便推荐个好用的在线代码编辑工具,国内镜像站点,方便各位对本文实例进行测试。另外本文会随着作者对css的更深入理解而逐步更新,希望到最后能够文如标题展现出真正的css世界。

小刚老师

  • 基本概念
  • 盒模型四大金刚
  • 好基友line-heightvertical-align
  • 流的破坏
  • 层叠规则
  • 文本控制
  • 元素的显示与隐藏
  • 弹性布局
  • 网格布局

基本概念

这些基本概念有些可能不易理解但却都很重要,如果看完还是很不理解的话需要自己谷歌或百度,网上关于这些概念的文章不少。

“流”又叫文档流,是css的一种基本定位和布局机制。流是html的一种抽象概念,暗喻这种排列布局方式好像水流一样自然自动。“流体布局”是html默认的布局机制,如你写的html不用css,默认自上而下(块级元素如div)从左到右(内联元素如span)堆砌的布局方式。

块级元素和内联元素

这个大家肯定都知道。

块级元素是指单独撑满一行的元素,如div、ul、li、table、p、h1等元素。这些元素的display值默认是block、table、list-item等。

内联元素又叫行内元素,指只占据它对应标签的边框所包含的空间的元素,这些元素如果父元素宽度足够则并排在一行显示的,如span、a、em、i、img、td等。这些元素的display值默认是inline、inline-block、inline-table、table-cell等。

实际开发中,我们经常把display计算值为inline inline-block inline-table table-cell的元素叫做内联元素,而把display计算值为block的元素叫做块级元素。

width: auto 和 height: auto

widthheight的默认值都是auto

对于块级元素,流体布局之下width: auto自适应撑满父元素宽度。这里的撑满并不同于width: 100%的固定宽度,而是像水一样能够根据margin不同而自适应父元素的宽度。

对于内联元素,width: auto则呈现出包裹性,即由子元素的宽度决定。

无论内联元素还是块级元素,height: auto都是呈现包裹性,即高度由子级元素撑开。

注意父元素height: auto会导致子元素height: 100%百分比失效。

css的属性非常有意思,正常流下,如果块级元素的width是个固定值,marginauto,则margin会撑满剩下的空间;如果margin是固定值,widthauto,则width会撑满剩下的空间。这就是流体布局的根本所在。

外在盒子和内在盒子

外在盒子是决定元素排列方式的盒子,即决定盒子具有块级特性还是内联特性的盒子。外在盒子负责结构布局。

内在盒子是决定元素内部一些属性是否生效的盒子。内在盒子负责内容显示。

display: inline-table; 外在盒子就是inline,内在盒子就是table。外在盒子决定了元素要像内联元素一样并排在一排显示,内在盒子则决定了元素可以设置宽高、垂直方向的margin等属性。如下图


右侧的table和左侧的文字在一行排列(外在盒子inline的表现特征),同时有拥有自定义宽度111px(内在盒子table可以设置宽高)。

css权重和超越!important

曾经有道面试题把我难住了:

// 假设下面样式都作用于同一个节点元素`span`,判断下面哪个样式会生效
body#god div.dad span.son {width: 200px;}
body#god span#test {width: 250px;}

可怜当时做了三年前端的我竟然还不知道css有权重

css选择器权重列表如下:

权重值 选择器
1,0,0,0 内联样式:style=""
0,1,0,0 ID选择器:#idName{...}
0,0,1,0 类、伪类、属性选择器:.className{...} / :hover{...} / [type="text"] ={...}
0,0,0,1 标签、伪元素选择器:div{...} / :after{...}
0,0,0,0 通用选择器(*)、子选择器(>)、相邻选择器(+)、同胞选择器(~)

以前想当然的以为权重是十进制的,即十个class选择器等于一个id选择器,这是错误的。CSS权重进制在IE6为256,后来扩大到了65536,而现代浏览器则采用更大的数量。所以我们可以忽略进制的问题,从高往低比较权重值。

如果权重是十进制的比较方式,则十一个class选择器的权重高于一个ID选择器。但经测试并非如此:地址。


可以看到十一个class选择器的样式并没有覆盖一个id选择器的样式,因为:

当两个权值进行比较的时候,是从高到低逐级将等级位上的权重值来进行比较的,而不是 1000个数 + 100个数 + 10个数 + 1个数 的总和来进行比较的,换句话说,低等级的选择器个数再多也不会超过高等级的选择器的优先级的。

正确规则:

  1. 先从高等级进行比较,高等级相同时,再比较低等级的,以此类推;
  2. 完全相同的话,就采用 后者优先 原则;

因此上面那道的面试题比较应该是在第二等级id选择器的比较就结束了:(#god + #test = 0,2,0,0) > (#god = 0,1,0,0);而上图种例子中两个权重分别是:(#test = 0,1,0,0) > (.test....test10 = 0,0,11,0),也是在第二等级id选择器的比较时就结束了。所以以后比较权重,就先比较id选择器个数,如果id一样多,再比较class选择器个数。哇,感觉这可以是一道专坑中文社区的面试题啊。

在css中,!important的权重相当的高。如果出现了!important,则不管权重如何都取有!important的属性值。但是宽高有例外情况,由于宽高会被max-width/min-width覆盖,所以!important会失效。

width: 100px!important;
min-width: 200px;

上面代码计算之后会被引擎解析成:

width: 200px;

盒模型(盒尺寸)

元素的内在盒子是由margin boxborder boxpadding boxcontent box组成的,这四个盒子由外到内构成了盒模型。

IE模型: box-sizing: border-box 此模式下,元素的宽度计算为border+padding+content的宽度总和。

w3c标准模型): box-sizing: content-box 此模式下,元素的宽度计算为content的宽度。

由于content-box在计算宽度的时候不包含border pading很烦人,而且又是默认值,业内一般采用以下代码重置样式:

:root {
  box-sizing: border-box;    
}
* {
  box-sizing: inherit;
}

内联盒模型

内联元素是指外在盒子是内联盒子的元素。从表现来说,内联元素的典型特征就是可以和文字在一行显示。文字也是内联元素。图片、按钮、输入框、下拉框等替换元素也是内联元素。内联盒模型是指内联元素包含的几个盒子,理解记忆下面的几个概念对css的深入学习极其重要。

  1. 内容区域:本质上是字符盒子。在浏览器中,文字选中状态的背景色就是内容区域。
  2. 内联盒子:内联盒子就是指元素的外在盒子是内联的,会和其他内联盒子排成一行。
  3. 行框盒子:由内联元素组成的每一行都是一个行框盒子。如果一行里面没有内联元素如一个空的div标签,则不会形成行框盒子。行框盒子由一个个内联盒子组成,如果换行,那就是两个行框盒子。比如一个包含了很多字符的换行的的p标签,每一行都存在一个行框盒子。值得注意的是,如果给元素设置display: inline-block,则创建了一个独立的行框盒子。line-height是作用在行框盒子上的,并最终决定高度。
  4. 包含盒子:就是包含块。多行文字组成一个包含块,一个包含块有若干个行框盒子。
  5. 幽灵空白节点:内联元素的每个行框盒子前面有一个“空白节点”,这个“空白节点”不占据任何宽度,无法选中获取,但是又实实在在存在,表现就如同文本节点一样(本文中大量例子会用字母x模拟幽灵空白节点)。

替换元素

替换元素是指内容可以替换的元素,实际上就是content box可以被替换的元素。如存在src=""属性的