CSS 世界
概述
本书讲解的是 css2.1 流不适用 table
选择器:
- 类选择器
- ID 选择器
- 属性选择器
[title="css-world"]
[title="css-world"]
[title~="css-world"]
[title^="css-world"]
[title$="css-world"]
- 伪类选择器
:first-child
- 伪元素选择器
:before
关系选择器:
- 后代选择器 空格连接
- 相邻后代选择器
>
- 兄弟选择器
~
- 相邻兄弟选择器
+
流、元素、基本尺寸
块级元素(block level element)
div
/li
/table
都是块级元素
配合 clear
来清除浮动,浮动属性对浮动元素同级块级元素设置,且必须在浮动元素之后(所以使用:after
)
/**清除浮动带来的影响*/
.clear:after {
content: "";
display: "table";
clear: both;
}
list-item 放小圆点的盒子叫 ”标记盒子(marker box)“
每个元素由两个盒子(外盒子和内外盒子)组成,按照 display 的不同
display:block
实际由外在的 块级盒子和内在的块级容器盒子组成,可以理解成display:block-block;
display:inline-block
实际由外在的内联盒子和内在的块级容器盒子组成
width
“无宽度准则” width 默认作用在 content-box (容器盒子)上,
width: auto;
有如下四种宽度表现:
- 充分利用可用空间 fill-available,如 div 默认是 100% 与父容器
- 收缩与包裹,shrink-to-fit,如 inline-block,会根据 content 的实际宽度来计算,此外,浮动元素和绝对定位元素都具有包裹性
- 收缩到最小,容易出现在 table 里面,table 的 td。
- 超出容器限制,如内联元素被设置了
white-space:nowrap
或者很长的英文或者数字就会超出容器的限制
三无原则:
- 无宽度,块级元素设置了宽度,流动性丢失
- 无图片
- 无浮动
格式化宽度仅出现在“绝对定位模型”中,position 为 absolute 或者 fixed的元素。表现为包裹性,宽度由内部尺寸决定。 对于非替换元素,如果同时设置了对立方位的属性,即 left/right 或 top/bottom,则元素 的宽度由祖先元素(postion != static)决定。如 1000(祖先元素 width)-20(right)-20(left)
替换元素的宽度不受 display 水平影响,即使设置了 display:block
宽度也不会变化。
非替换元素,如果 display:block
,则具有流动特性,宽度由外部决定。
box-sizing 的作用是改变 width 作用的盒子
- content-box 默认值
- padding-box
- border-box
- margin-box
作者认为 box-sizing 被发明出来最大的初衷应该是解决替换元素宽度自适应问题。
原因如下:比如 textarea 是替换元素,首先上面说的 display 不能影响他的宽度,还得搭配 width 属性来设置宽度。但是 textarea 是有 border 的,并且自带有 padding,所以需要 width/border/padding 三者共存。如果是默认的 box-sizing:content-box;
设置宽度 100%,其最终的宽度=父元素的宽度+border+padding 的宽度,肯定超出父元素的,所以需要设置为 box-sizing:border-box;
。
<div>
<textarea style="width:100%;"></textarea>
</div>
height
height: 100%;
如果父元素 height 为 auto 则会被忽略
生效的两种情况:
- 设置 html, body 都是 100%,高度相对于 content-box 计算
- 使用绝对定位,position: absolute; 相对于 padding-box 计算
min-width/max-width 出现在自适应布局或者流体布局中 min-width/min-height 初始值是 auto; max-width/max-height 初始值是 none;
图片设置 height:auto 可以保持原来的比例 max-width 会覆盖 width,即使 width 配置了 !important;
使用 max-height 实现过渡隐藏效果
.element {
max-height: 0;
overflow: hidden;
transition: max-height 0.25s;
}
.element.active {
max-height: 666px;
}
:checked ~ .element {
/** checked 旁边的元素*/
}
内联元素 inline-level element
块级负责结构,内联负责内容,所以 height 和 width 只能作用在结构上。
内联指的是外在盒子,所以 inline-block
也是内联元素。
内联盒模型:
- 内容区域(content area) 大小受字符本身控制,本质是字符盒子 character box
- 内联盒子(inline box),指的是外在盒子,决定元素是内联还是块级
- 行框盒子(line box),每一行都是一个行框盒子
- 包含盒子(containing box),由一个个的行框盒子组成
“幽灵空白节点” 实际上也是一个盒子,不过是个假想盒,名叫“strut”,中文直译为“支柱”,是一个存在于每个“行框盒子”前面,同时具有该元素的字体和行高属性的 0 宽度的内联盒。
Each line box starts with a zero-width inline box with the element’s font and line height properties. We call that imaginary box a “strut
盒尺寸
content 属性
替换元素,根据内容是否可被替换,分为替换元素和非替换元素,如 input/img/video/iframe 等都是替换元素 修改某个属性值,内容可被替换的元素就叫替换元素。 所有替换元素都是内联水平元素,都可一行显示
替换元素的特性:
- 内容可替换
- 内容外观不受 css 的影响
- 有自己的尺寸
- 在很多 css 属性上有自己的表现规则,如 vertical-align 替换元素基线是下边缘
替换元素的尺寸计算规则优先级:css 尺寸(通过 css 定义的尺寸)>HTML 尺寸(如 img 的 width 属性)>固有尺寸(不设置任何样式和属性)
- 替换元素和非替换元素只隔了一个 src 属性 chrome 的所有元素都支持 content 属性
- 替换元素和非替换元素隔了一个 content 属性,使用 content 属性,我们还可以让普通标签元素变成替换元素。
首屏图片异步加载
img {
visibility: hidden;
}
img[src] {
visibility: visible;
}
content 无法设置 img 尺寸,即下面设置无效
div:before {
content: url(1.jpg);
display: block;
width: 200px; height: 200px;
}
content 属性生成的内容都是替换元素
- content 生成的内容,文本无法选中、复制
- 不能左右 :empty 伪类
- content 动态生成值无法获取
content 属性通常用在 :before
:after
这两个伪元素中,通常用于下面几个地方:
- 比如用于清除浮动
- 用于字符内容生成
- 如实现 ... 动态加载效果
- 我们常用的字符图片
- 图片生成
- content 开启闭合符号生成,
open-quote
close-quote
不常用 - content attr 属性值内容生成
:after {
content: `\a`;
white-space: pre;
/**换行*/
content: "...\A..\A.";
}
img:after {
/* 获取 alt attr 的内容放到 content 里面*/
content: attr(alt);
}
div:before {
content: url(1png);
}
content 实现计数器,通常用于实现索引值
counter-reset
给计数器起名字,顺便告诉计数器从几开始,默认 0counter-increment
counter()/counters()
/*计数器名字是 wangxiaoer 默认值是 2*/
.xxx {
counter-reset: wangxiaoer 2 wangxiaosan 3;
}
css 计数器规则 ”普照规则“。普照源(counter-reset)唯一,每普照(counter-increment)一次,普照源增加一次计数值。
padding
- 非替换的内联元素,padding、margin 和 border 都不加入行盒高度的计算。利用此特性,可以增加连接或者按钮点击区域大小
比如 div 里面的 span 设置了 padding,会影响 span 的高度,但是这个 padding 设置的值对 div 的高度是没有影响的。 例子:通过这个特性设置锚点距离页面上部的距离 见 4.2.1
- 不支持负值,padding 的百分比(水平和垂直方向)是相对于宽度计算的
- 标签元素内置 padding
- 图形绘制,padding 配合 background-clip 可以实现三道杠和双层圆点图形效果
.icon-dot {
display: inline-block;
width: 100px; height: 100px;
padding: 10px;
border: 10px solid;
border-radius: 50%;
background-color: currentColor;
/*只对 content区域着背景色 default border-box*/
background-clip: content-box;
}
margin
- 元素尺寸,包括 border 和 padding,offsetWidth 和 offsetHeight,也叫“元素偏移尺寸”,对应 jquery 的 width 和 height
- 元素内部尺寸,padding box 的尺寸,clientWidth 和 clientHeight,也叫“元素可视尺寸”,对应 jquery 的 innerWidth 和 innerHeight
- 元素外部尺寸,包含 padding、border、margin,对应 jquery 的 outerWidth(true) 和 outerHeight(true)
window.innerHeight
浏览器可视高度,如果有水平滚动条包含滚动条的高度window.innerWidth
浏览器可视宽度,如果有垂直滚动条包含滚动条的宽度
元素尺寸符合充分利用可用空间,则可通过 margin 改变尺寸。
/*获取第三个元素*/
li:nth-of-type(3n) {
margin-right: 0;
}
特性 chrome 浏览器子元素超过 content box 会触发滚动条显示 只能使用子元素的 margin-bottom 来触发滚动条留白
margin 合并:
- 相邻元素 margin 合并
- 腹肌和第一个最后一个子元素
- 空块级元素 margin 合并
margin 的初始值是 0,margin:auto;
是为块级元素左中右对其设计的,对应 text-align 控制左中右对其,填充规则:
元素水平方向自动填充为父元素宽度,垂直方向无法自动填充,默认为零,所以设置 margin:auto,垂直方向无法居中。margin 触发的条件是,width 或者 height 为 auto 时,具有水平或者垂直方向的自动填充。
- 一侧定值,一个 auto,auto 为剩余空间大小
- 两侧 auto,平分剩余空间
正常情况下,margin:auto;
只会水平居中,可以利用绝对定位进行垂直水平居中:
.father {
width: 300px;
height: 150px;
position: relative;
}
.son {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
width: 200px;
height: 100px;
}
margin 无效情形:
- 内联非替换元素 margin 无效,比如对 span 设置 margin 无效
- 表格的 tr、td 或者
display:table-cell/table-row
的元素设置 margin 无效 - margin 合并的时候
- 绝对定位元素非定位方向 margin 无效
若想使 margin 生效,必须是和当前元素定位方向一样的 margin 属性才可以,元素默认定位方向是左和上
- 定高容器的子元素的 margin-bottom 或者宽度定死的子元素的 margin-right 的 定位“失效”
- 内联特性导致的 margin 无效,比如 img 的 vertical-align 特性基线对齐,导致 margin-top 到一定的范围之后不再继续生效
border
- border-width 不支持百分比
- border-style
- none
- solid
- dashed
- double,由上中下三部分组成,如 1px=0+1+0,是一根实线,5px=2+1+2,上下两根实线,中建一个 1px 的间隙
通过透明 border 来扩大按钮的可点击区域 border 实现三角形和梯形
/*三角形*/
div {
width: 0;
border: 10px solid;
border-color: #f30 transparent transparent;
}
内联元素与流
line-height
基线就是字母 x 的下边缘,x-height 是字母 x 的高度。vertical-align:middle
不是绝对的垂直水平居中,原因是不同的字体在行内盒子位置不一样,可能会有下沉效果。
ex
CSS 中的一个相对单位,指的是小写字母 x 的高度,可以实现 不受字体和字号影响的内联元素的垂直居中对齐效果
内联元素默认是基线对齐的
div 的高度由行高而非文字决定
非替换的内联元素,可视高度由 line-height 决定
行距 = line-height - font-size,第一行与最上边的距离是半行距
替换元素, line-height 不会影响替换元素的高度,line-height 改变的是“幽灵空白节点“的高度,只能决定最小高度。
块级元素,对块级元素没有作用
改变 line-height,实际上是通过改变块级元素里面的”行框盒子“占据的高度实现的进而改变了块级元素的高度 line-height 不仅是内联元素高度的基石,而且还是整个 CSS 世界高度体系的基石。
多行文本实现垂直居中效果:
- 多行文字使用一个标签包裹,然后设置 line-height,相当于设置了幽灵空白节点的高度
- 设置 vertical-align: middle
line-height
支持的值:
- 数值,如
line-height:1.5
,子元素会继承这个值 - 百分比值,如
line-height:150%
,子元素会继承计算后的值,即 150%*font-size - 长度值,如
line-height:20px
,同上
每个”行框盒子“前面都有一个宽度为 0 的具有该元素字体和行高属性的”幽灵空白节点“ 行框盒子的高度由高度最高的内联盒子决定的
vertical-align
line-height 起作用的地方 vertical-align 一定起作用,line-height 只能应用于内联元素以及 display 值为 table-cell 的元素 属性值分为 4 类:
- 线类,如 base-line、top、middle、bottom
- top、bottom 看边缘和行框盒子
- baseline/middle 和字符 x 打交道
- 文本类,如 text-bottom
- 上标下标类,如 sub、super
- 数值百分比类,如 20px, 20% 等,百分比是针对 line-height 的计算值计算的
vertical-align 属性只能作用在 display 计算值为 inline、inline-block,inline-table 或 table-cell 的元素上。因此,默认情况下,\、\、 \等内联元素,\、\
.box {
line-height: 32px;
}
.box > span {
font-size: 24px;
}
<div class="box">
<span>文字</span>
</div>
上面这段 css 会导致 box 的实际高度不是 32px,而是 36px,原因是 vertical-align 默认值是 base-line,”幽灵空白节点“ 的 font-size 和 span 都受 line-height:32px
影响,因为文字默认是基线对齐,两个字号不一致,导致彼此会发生上下位移。位移距离足够大,就会超过行高的限制。
解决办法:改变 box 的 font-size 和 span 的字体大小一致,或者设置 span vertical-align: top;
vertical-align: text-top;
盒子的顶部和父级内容区域的顶部对齐vertical-align: text-bottom;
盒子的底部和父级内容区域的底部对齐
inline-block 元素如果里面没有内联元素,则基线是 margin 底边缘,否则基线是元素最后一行内联元素的基线。
一个实现的很棒的 modal 框
<div class="container">
<div class="dialog"></dialog>
</div>
<style>
.container {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: rgba(0, 0, 0, 0.5);
text-align: center;
font-size: 0;
white-space: nowrap;
overflow: auto;
}
.container:after {
content: "";
display: inline-block;
height: 100%;
vertical-align: middle;
}
.dialog {
display: inline-block;
vertical-align: middle;
text-align: left;
font-size: 14px;
white-space: normal;
}
</style>
原理: font-size:0,则 x 中心点应该在 container 的上边缘,因为设置了高度 100% 伪元素,导致伪元素和这个中心点对齐,x 中心点下移了半个容器高度,x 中心点就在容器的垂直中心线上。此时设置 dialog 的 vertical:middle
,弹框的垂直中心位置和 x 中心点对齐,所以事先了 dialog 的垂直居中,配合 text-align: center
进而实现水平垂直居中
流的破坏与保护
浮动的本质是实现文字环绕效果,有两个特性:
- 父级元素塌陷(目的就是为了实现文字环绕效果),父级元素定高可以解决
- 行框盒子区域限制,行框盒(每行内联元素在的盒子)高度如果和浮动元素垂直高度有重叠,则行框盒子会跟随浮动元素,而不会有重叠
浮动元素的特性:
- 包裹性; 将子元素包裹起来,宽高都等于子元素
- 块状化并格式化上下文;内联元素使用 float 修饰之后,就会变成块级元素
- 破坏文档流;会使父元素塌陷,
- 浮动参考,float “浮动参考” 是 “行框盒子”,相对于当前的行框盒子进行定位
- 浮动锚点,如果没有内联元素行框盒子,则相对于浮动锚点定位,可以理解成一个没有 border、margin、padding 空的内联元素
- 没有任何 margin 合并;
clear
clear
元素只对块级元素才有效,设置 clear 属性的元素作用对象是自己,而不是针对 float 元素。
clear 属性是让自身不能和前面的浮动元素相邻,对后面的浮动元素不闻不问
.clear:after {
content: '';
display: table; // 也可以是'block',或者是'list-item'
clear: both;
}
上面代码能撑开盒子的原因就是为了不和浮动元素相邻,撑开了盒子
clear:both
元素前面是 float 元素,即使当前元素设置 margin-top 为负值也不会和浮动元素同一行显示clear:both
后面元素依然可能发生文字环绕
BFC
block formating context,块级格式化上下文,BFC 内部子元素不会影响外面元素,也不会受外面元素影响。 主要目的是实现更健壮、更智能的自适应布局。
触发 BFC
- HTML 根元素
- float 不为 none
- overflow 为 auto、scroll 或 hidden,普通元素设置了 overflow:hidden 之后,会自动填满容器中除了浮动元素外的剩余空间
如浮动元素相邻元素会发生文字环绕,此时对相邻元素设置 overflow: hidden 后会自动填充除了浮动元素外的空间
- display 为 table-cell、table-caption 或 inline-block
- position 不为 relative 或 static
BFC 特性的自适应布局的优点:
- 自适应内容由于封闭而健壮,容错性更强。
设置 clear:both 不与浮动元素一行显示,会导致错位;而设置 overflow:hidden 则会实现自适应布局,与浮动元素同行显示
- 自适应内容自动填满浮动以外区域,无需关心浮动元素宽度
BFC 自适应元素:
- overflow:auto/hidden
- display:inline-block
- display:table-cell
overflow
裁剪的是 border-box 的内边缘
overflow 属性值
- visible 默认值
- hidden 裁剪
- scroll 滚动条区域一直存在
- auto,不足滚动没有滚动条,可以滚动时滚动条出现
一些特性总结:
- html 页面默认的滚动条是作用在
html
标签上的,可以通过overflow:hidden
来取消滚动 - 滚动条会占用容器的可用宽度或者高度,滚动条的宽度通常是 17px
实现单行文字溢出 ... 效果,下面三个设置缺一不可
.ell {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
position:absoulte
具有块状化、包裹性、破坏性,absolte 和 float 同时存在,float 无效
“无依赖绝对定位”:没有设置 left/top/right/bottom 属性值的绝对定位,有如下特性:
- 相对性,是相对于当前位置进行计算
虽然 position:absolute 会导致内联元素块状化,但是内联元素并不会导致换行。 我理解作用的顺序是,先按正常位置渲染出 div/span,然后 position:absolute 开始起作用,根据 margin 等配置调整位置,但是整个过程结束之后不占据实际的 css 空间
- 不占据空间,不占用 css 流的尺寸空间
absolute 虽然会导致当前元素块状化,但是作用在 span 上,并不会导致换行,原因是它不占据空间。 比如用来实现图表左上角的 TOP1 提示、导航右上方的图标提示、实现登录页面 里面的必填图标和错误提示的布局、下拉列表
absolute 和 text-align 相互作用原理:
行内元素有 “幽灵空白节点作用”,如 text-align:center 会导致该节点在行中建,然后 absolute 元素才开始起作用,导致跟随该节点
absolute 和 overflow:
如果 overflow 不是定位元素,同时绝对定位元素和 overflow 容器之间也没有定位元素,则 overflow 无法对 absolute 元素进行剪裁。
absolute 和 clip:
clip 要起作用,position 必须是 absolute 或者 fixed
.clip {
position: absolute;
clip: rect(0 0 0 0);
}
使用 clip 进行剪裁的元素其clientWidth 和 clientHeight 包括样式计算的宽高都还是原来的大小 clip 隐藏仅仅是决定了哪部分是可见的,非可见部分无法响应点击事件等;然后,虽然视觉上隐藏,但是元素的尺寸依然是原本的尺寸
absolute 流动性: 当 absolute 遇到 left/top/right/bottom 属性的时候,absolute 元素才真正变成绝对定位元素 普通元素流体特性只有一个方向,默认是水平方向,但是绝对定位元素可以让垂直方向和水平方向同时保持流动性
/* 上下左右留白 30px */
.box {
position: absolute;
left: 0; right: 0; top: 0; bottom: 0;
margin: 30px;
}
absolute 和 margin:
绝对定位元素的 marg
position:relative
relative 的定位有两大特性:一是相对自身;二是无侵入。
tips
- 内联状态下,图片底部是有间隙的