Open wallleap opened 2 years ago
title: CSS 世界笔记 date: 2022-10-12 20:32 updated: 2022-10-12 20:32 cover: //cdn.wallleap.cn/img/pic/illustrtion/202210121558633.jpg category: 技术杂谈 tags:
本文由个人学习张鑫旭老师的《CSS 世界》整理而来,通过阅读这本书,发现了很多之前没注意到的细节,文中加入了自己的想法和理解,舍弃了有关 IE 兼容性的问题,建议有一定 CSS 基础的同学阅读,如有错误请指正。
✨ CSS 有别于传统程序语言,在 CSS 的世界里,页面上的任何看似简单的呈现都是由许许多多 CSS 属性共同作用的结果。 CSS 并无逻辑可言,看重的是特性间的相互联系和具象能力。
✨ CSS 有别于传统程序语言,在 CSS 的世界里,页面上的任何看似简单的呈现都是由许许多多 CSS 属性共同作用的结果。
CSS 并无逻辑可言,看重的是特性间的相互联系和具象能力。
CSS 全称是 Cascading Style Sheets,翻译成中文就是“层叠样式表”,所谓“层叠”,顾名思义,就是样式可以层层累加,比方说页面元素都继承了 12 像素的大小,某标题就可以设置成 14 像素进行叠加。这种层叠策略对于样式的显示是相当的灵活。
CSS 是由一个个规则集(ruleset)组成的,规则集包括选择器和声明块两部分
,
{}
;
其他概念:
/* */
/* 注释1 /* 注释2 */ */
rgba
hsla
url
calc
rgba(0,0,0,.5)
url('css-world.png')
attr('href')
scale(-1)
@
@media
@font-face
@page
@support
选择器是用来瞄准(选择)目标元素的东西,例如,上面的 .selector 就是一个选择器
.selector
.
#
[]
[title]{}
[title="css-world"]{}
[title~="css-world"]{}
[title^= "css-world"]{}
[title$="css-world"]{}
:
:first-child
:last-child
::first-line
::first-letter
::before
::after
`、
、
,还有
>
~
+
Web 应用场景千变万化,Web 标准也是不可能面面俱到的,也会存在规范描述以外的场景,此时,各大浏览器厂家只能根据自己的理解与喜好去实现,一旦个性化就会出现差异,就比如 Firefox 和 IE/Chrome 浏览器表现不一样。
实际上,此时遇到的表现差异并不是浏览器的 bug,用计算机领域的专业术语描述应该是“未定义行为”(undefined behavior)。
“流”实际上是 CSS 世界中的一种基本的定位和布局机制,可以理解为现实世界的一套物理规则,“流”跟现实世界的“水流”有异曲同工的表现。
所谓“流”,就是 CSS 世界中引导元素排列和定位的一条看不见的“水流”。
CSS 世界构建的基石是 HTML,而 HTML 最具代表的两个基石 <div> 和 <span> 正好是 CSS 世界中块级元素和内联级元素的代表,它们对应的正是图 1-3 所示的盛水容器中的水和木头,其特性表现也正如现实世界的水和木头,如图 1-4 所示。
<div>
<span>
流是如何影响整个 CSS 世界的?
📌 table 有自己的世界,“流”的特性对 <table> 并不适用
<table>
HTML 常见的标签有 <div>、<p>、<li> 和 <table> 以及 <span>、<img>、<strong> 和 <em> 等。
<p>
<li>
<img>
<strong>
<em>
虽然标签种类繁多,但通常我们就把它们分为两类:块级元素(block-level element)和内联元素(inline element)。
块级元素占据其父元素(容器)的整个水平空间(一般独占一行),垂直空间等于其内容高度,常见的块级元素有 <div>、<li> 和 <table> 等。
这些元素的 display 属性值默认是 block、table、list-item 等。
display
block
table
list-item
🌰 应用:清除浮动
正是由于“块级元素”具有换行特性,因此理论上它都可以配合 clear 属性来清除浮动带来的影响。
clear
.clearfix:after { content: ''; display: table; /* 也可以是 block 或者是 list-item */ clear: both; }
📌 为什么 list-item 元素会出现项目符号 ——之所以 list-item 元素会出现项目符号是因为生成了一个附加的盒子,学名“标记盒子”(marker box),专门用来放圆点、数字这些项目符号。
📌 为什么 list-item 元素会出现项目符号
——之所以 list-item 元素会出现项目符号是因为生成了一个附加的盒子,学名“标记盒子”(marker box),专门用来放圆点、数字这些项目符号。
内联元素又叫行内元素,指只占据它对应标签的边框所包含的空间的元素,这些元素如果父元素宽度足够则并排在一行显示的,如 span、a、em、i、img、td 等。
span
a
em
i
img
td
“内联元素”的“内联”特指后文提到的“外在盒子”,这些元素的 display 值默认是 inline、inline-block、inline-table、table-cell 等。
inline
inline-block
inline-table
table-cell
✨ 一般情况下,行内元素只能包含数据和其他行内元素,而块级元素可以包含行内元素和其他块级元素 就行为表现来看,“内联元素”的典型特征就是可以和文字在一行显示,浮动元素貌似也是可以和文字在一个水平上显示的,实际上,浮动元素和后面的文字并不在一行显示,它已经在文档流之外了,浮动元素会生成“块盒子”
✨ 一般情况下,行内元素只能包含数据和其他行内元素,而块级元素可以包含行内元素和其他块级元素
就行为表现来看,“内联元素”的典型特征就是可以和文字在一行显示,浮动元素貌似也是可以和文字在一个水平上显示的,实际上,浮动元素和后面的文字并不在一行显示,它已经在文档流之外了,浮动元素会生成“块盒子”
每个元素都两个盒子,外在盒子和内在盒子
run-in
width
height
content-box
padding-box
border-box
margin box
margin
外在盒子是流体布局的本质所在,从作用上来讲,块级负责结构,内联负责内容
按照 display 的属性值不同,外在盒子和内在盒子组成不同
✨ 在 CSS 中,所有的元素都被一个个的“盒子”(box)包围着(容器盒子) 每个盒子由四个部分(或称区域)组成,其效用由它们各自的边界(Edge)所定义,与盒子的四个组成区域相对应 每个盒子有四个边界:内容边界 Content edge、内边距边界 Padding Edge、边框边界 Border Edge、外边框边界 Margin Edge
✨ 在 CSS 中,所有的元素都被一个个的“盒子”(box)包围着(容器盒子)
每个盒子由四个部分(或称区域)组成,其效用由它们各自的边界(Edge)所定义,与盒子的四个组成区域相对应
每个盒子有四个边界:内容边界 Content edge、内边距边界 Padding Edge、边框边界 Border Edge、外边框边界 Margin Edge
可以通过设置 box-sizing 属性修改盒模型
box-sizing
w3c 标准盒模型:
box-sizing: content-box
content
IE 盒模型:
box-sizing: border-box
border
padding
有 content 和 border,那有没有可能还有其他的?
.box1 { box-sizing: content-box; } /* 默认值 */ .box2 { box-sizing: padding-box; } /* Firefox 曾经支持 */ .box3 { box-sizing: border-box; } /* 全线支持 */ .box4 { box-sizing: margin-box; } /* 从未支持过,本身就没有价值(设定好了宽高之后 margin 值并不能再影响盒子大小) */
这里介绍的“内联盒模型”是简易版
内容区域(content area)
inline-box 又名内联盒子
inline-box
anonymous inline box
line-box 名为行框盒子
line-box
vertical-align
container-box 就是包含块的意思
container-box
strut “幽灵空白节点”
strut
✨ 内联元素的所有解析和渲染表现就如同每个行框盒子的前面有一个“空白节点”一样。这个“空白节点”永远透明,不占据任何宽度,看不见也无法通过脚本获取,就好像幽灵一样。 “幽灵空白节点”实际上也是一个盒子,不过是个假想盒,名叫“strut”,中文直译为“支柱”,是一个存在于每个“行框盒子”前面,同时具有该元素的字体和行高属性的 0 宽度的内联盒。
✨ 内联元素的所有解析和渲染表现就如同每个行框盒子的前面有一个“空白节点”一样。这个“空白节点”永远透明,不占据任何宽度,看不见也无法通过脚本获取,就好像幽灵一样。
“幽灵空白节点”实际上也是一个盒子,不过是个假想盒,名叫“strut”,中文直译为“支柱”,是一个存在于每个“行框盒子”前面,同时具有该元素的字体和行高属性的 0 宽度的内联盒。
因为块级元素的流体特性主要体现在水平方向上,所以我们这里先着重讨论 width
width/height 的默认值是 auto,由”浏览器决定“,基于元素的类型和父元素的宽度来计算
auto
max-width 和 max-height 的初始值是none
max-width
max-height
none
虽然 MDN 和 W3C 维基的文档上都显示 min-width/min-height 的初始值是 0,但是,根据作者的分析和测试,所有浏览器中的 min-width/min-height 的初始值都是 auto(❓ 这里我没有太理解嘿,盒子默认没有内容,高度就是 0,有了内容,盒子高度由内容决定,min-height 始终为 0 也是合理的)
min-width
min-height
0
width: auto
width 的默认值是 auto,它至少包含了以下 4 种不同的宽度表现:
fill-available
shrink-to-fit
fit-content
table-layout
white-space: nowrap
height: auto
CSS 的默认流是水平方向的,宽度是稀缺的,高度是无限的,宽度的分配规则就比较复杂,高度就显得比较随意
height:auto 的表现:有几个元素盒子,每个多高,然后一加,就是最终的高度值了(由内容高度决定)
height:auto
height: 100%
height 和 width 还有一个比较明显的区别就是对百分比单位的支持
对于 width 属性,就算父元素 width 为 auto,其百分比值也是支持的;但是,对于 height 属性,如果父元素 height 为 auto,只要子元素在文档流中,其百分比值完全就被忽略了
让元素支持 height:100% 效果:
height:100%
设定显式的高度值,对于普通文档流中的元素,百分比高度值要想起作用,其父级必须有一个可以生效的高度值!
html, body { height: 100%; }
使用绝对定位,绝对定位的元素的百分比高度值是相对于最近的非 static 定位的祖先元素计算的
static
div { position: absolute; height: 100%; }
📌 绝对定位的宽高百分比计算是相对于 padding box 的,也就是说会把 padding 大小值计算在内 非绝对定位元素则是相对于 content box 计算的
📌 绝对定位的宽高百分比计算是相对于 padding box 的,也就是说会把 padding 大小值计算在内
非绝对定位元素则是相对于 content box 计算的
CSS 世界中,min-width/max-width 和 min-height/max-height 属性间,以及与 width 和 height 之间有一套相互覆盖的规则:超越 !important,超越最大
!important
🌰 例子1:图片最后呈现的宽度是 256px
256px
<img src="1.jpg" style="width:480px !important;"> img { max-width: 256px; }
🌰 例子2:最小宽度比最大宽度设置得还大,此时,“超越最大”规则,min-width 活下来,max-width 被忽略,.container 元素表现为至少 1400 像素宽
.container
.container { min-width: 1400px; max-width: 1200px; }
🌰 案例:任意高度元素的展开收起动画技术
.element { max-height: 0; overflow: hidden; transition: max-height .25s; } .element.active { max-height: 666px; /* 一个足够大的最大高度值 */ }
展开后的 max-height 值,我们只需要设定为保证比展开内容高度大的值就可以,但是,如果 max-height 值太大,在收起的时候可能会有“效果延迟”的问题
盒尺寸中的 4 个盒子 content box、padding box、border box 和 margin box 分别对应 CSS 世界中的 content、padding、border 和 margin 属性
CSS 的 content CSS 属性用于在元素的 ::before 和 ::after 伪元素中插入内容
使用 content 属性插入的内容都是匿名的可替换元素,它们不属于文档的一部分,因此不会被 CSS 选择器选中,也不会被 JavaScript 的 document.querySelector() 方法选中
document.querySelector()
根据“外在盒子”是内联还是块级我们可以把元素分为内联元素和块级元素
而根据是否具有可替换内容,我们也可以把元素分为替换元素和非替换元素
替换元素:通过修改某个属性值(例如 value、src 等)呈现的内容就可以被替换的元素就称为“替换元素”,<img>、<object>、<video>、<iframe> 或者表单元素 <textarea> 和 <input> 都是典型的替换元素
value
src
<object>
<video>
<iframe>
<textarea>
<input>
baseline
非替换元素:内容不可替换,除了上述的元素基本都是非替换元素
替换元素的尺寸:从内而外分为 3 类——固有尺寸、HTML 尺寸和 CSS 尺寸
size
cols
rows
替换元素的尺寸计算规则:
video
canvas
iframe
300x150px
display: block
🌰 首屏以下的图片处理
Web 开发的时候,为了提高加载性能以及节约带宽费用,首屏以下的图片就会通过滚屏加载的方式异步加载,当图片的 src 属性缺省的时候,图片不会有任何请求
<img src="./img/pic.jpg" > <!-- 首屏图片 --> <img data-src="./img/pic1.jpg"> <!-- 首屏之外的图片 --> <style> img { display: inline-block; /* 对于 Firefox 浏览器,src 缺省的 <img> 不是替换元素,而是一个普通的内联元素,宽高会无效 */ visibility: hidden; } img[src] { visibility: visible; } </style>
🌰 使用 content 属性生成图片
在 Chrome 浏览器下,所有的元素都支持 content 属性
直接使用 content 属性添加图片路径,视觉上和 src 引入路径一致;如果图片原来是有 src 地址的,我们也是可以使用 content 属性把图片内容给置换掉的
content 属性改变的仅仅是视觉呈现,当我们以右键或其他形式保存这张图片的时候,所保存的还是原来 src 对应的图片
可前往 content 属性测试 - JS Bin 查看
🌰 H1 显示 logo 图片
使用 content 属性,我们还可以让普通标签元素变成替换元素
之前实现网站主标题处仅显示 logo,不显示文字(视觉上展示图片,SEO 仍索引标题文字)是这样实现的:
<h1>网站主标题</h1> <style> h1 { width: 180px; height: 36px; background: url(logo.png); /* 通过设置文字缩进隐藏文字 */ text-indent: -999px; } </style>
我们可以通过添加 content 属性实现,代码更简洁但效果相同
传统 CSS 代码的 <h1> 是一个普通元素,因此需要设定尺寸隐藏文字
<h1>
但是,下面使用 content 属性实现,<h1> 分分钟就变成了替换元素,文字自动被替换,同时尺寸规则就是替换元素的尺寸规则,完美适应原始图片大小
h1 { content: url(logo.png); }
查看:H1 title - JS Bin
在 CSS 世界中,我们把 content 属性生成的对象称为“匿名替换元素”(anonymous replaced element)
:empty
在实际项目中,content 属性几乎都是用在 ::before/::after 这两个伪元素中,因此,“content 内容生成技术”有时候也称 “::before/::after 伪元素技术”。
🌰 把 content 的属性值设置为空字符串,再利用其他 CSS 代码来生成辅助元素,或实现图形效果
.element:before { content: ''; }
🌰 清除浮动带来的影响
.clear:after { content: ''; display: table; /* 也可以是 'block' 等 */ clear: both; }
🌰 辅助实现“两端对齐”以及“垂直居中/上边缘/下边缘对齐”效果
<div class="box"><i class="bar"></i> <i class="bar"></i> <i class="bar"></i> <i class="bar"></i> </div> <style> .box { width: 256px; height: 256px; /* 两端对齐关键 */ text-align: justify; } .box:before { content: ""; display: inline-block; height: 100%; } .box:after { content: ""; display: inline-block; width: 100%; } .bar { display: inline-block; width: 20px; } </style>
:before 伪元素用于辅助实现底对齐,:after 伪元素用于辅助实现两端对齐
:before
:after
使用这种方式,需要注意 HTML 代码有些地方不能换行或者空格,有些地方则必须要换行或者有空格
🌰 content 字符内容生成:比较常见的应用就是配合 @font-face 规则实现图标字体效果
<span class="icon-home"></span> <style> @font-face { font-family: "myico"; /* 自定义字体名称 */ src: url("/fonts/4/myico.eot"); src: url("/fonts/4/myico.eot#iefix") format("embedded-opentype"), url("/fonts/4/myico.ttf") format("truetype"), url("/fonts/4/myico.woff") format("woff"); } .icon-home:before { font-size: 64px; font-family: myico; content: "家"; } </style>
除常规字符之外,我们还可以插入 Unicode 字符,例如换行符
:after { content: '\A'; white-space: pre; }
🌰 来实现字符动画效果
正在加载中<dot>...</dot> <style> dot { display: inline-block; height: 1em; line-height: 1; text-align: left; vertical-align: -.25em; overflow: hidden; } dot::before { display: block; content: '...\A..\A.'; white-space: pre-wrap; animation: dot 3s infinite step-start both; } @keyframes dot { 33% { transform: translateY(-2em); } 66% { transform: translateY(-1em); } } </style>
🌰 content 图片生成
/* 直接用 url 功能符显示图片 */ div:before { content: url(1.jpg); } /* 伪元素中的图片更多的是使用 background-image 模拟 */ div:before { content: ''; background: url(1.jpg); }
🌰 content 开启闭合符号生成
常规实现:
q:before { content: '“'; } q:after { content: '”'; }
自带属性 quotes:
quotes
<p lang="ch"><q>这本书很赞!</q></p> <p lang="en"><q>This book is very good!</q></p> <p lang="no"><q>denne bog er fantastisk!</q></p> <script> /* 为不同语言指定引号的表现 */ :lang(ch) > q { quotes: '“' '”'; } :lang(en) > q { quotes: '"' '"'; } :lang(no) > q { quotes: '«' '»'; } /* 在 q 标签的前后插入引号 */ q:before { content: open-quote; } q:after { content: close-quote; } </script>
可以任意指定 quotes 的字符,CSS 中还有 no-open-quote 和 no-close-quote 关键字,顾名思义,引号不需要了
🌰 content attr 属性值内容生成
img::after { /* 生成 alt 信息 */ content: attr(alt); /* 其他 CSS 略 */ } /* 也支持自定义的 HTML 属性 */ .icon::before { content: attr(data-title); }
🌰 使用 counter() 实现 ol 前的序号展示
counter()
ol
CSS 函数 counter(),返回一个代表计数器的当前值的字符串。它通常和伪元素搭配使用,但是理论上可以在支持 <string> 值的任何地方使用。 可以直接看这篇文章:使用 CSS 计数器更改有序列表序号样式
<string>
初始化/重置计数器:counter-reset: name 初始值
counter-reset: name 初始值
计数器递增:counter-increment: name 递增值
counter-increment: name 递增值
显示计数: content: counter(name, style)/content: counters()
content: counter(name, style)
content: counters()
🌰 content 内容生成的混合特性
各种 content 内容生成语法是可以混合在 一起使用的
a:after { content: "(" attr(href) ")"; } q:before { content: open-quote url(1.jpg); } .counter:before { content: counters(name, '-') '. '; }
”温和”指的是我们在使用 padding 进行页面开发的时候很少会出现意想不到的情况。
clientHeight
clientWidth
line-height
font-size
ul
padding-left
px
<button>
button { padding: 0; }
button::-moz-focus-inner { padding: 0; }
<select>
<radio>
<checkbox>
<label>
button
checkbox
radio
for
id
CSS 中还有很多其他场景或属性会出现这种不影响其他元素布局而是出现层叠效果的现象,可以分为两类
box-shadow
outline
判断:如果父容器 overflow:auto,层叠区域超出父容器的时候,没有滚动条出现,则是纯视觉的;如果出现滚动条,则会影响尺寸、影响布局
overflow:auto
🌰 在不影响当前布局的情况下,优雅地增加链接或按钮的点击区域大小
article a { padding: .25em 0; }
除了使用 padding,也可以使用透明的 border
🌰 利用内联元素的 padding 实现高度可控的分隔线
<a href="">登录</a><a href="">注册</a> <style> a + a:before { content: ""; font-size: 0; padding: 10px 3px 1px; margin-left: 6px; border-left: 1px solid gray; } </style>
🌰 不使用伪元素,仅一层标签实现大队长的“三道杠”分类图标效果
.icon-menu { display: inline-block; width: 140px; height: 10px; padding: 35px 0; border-top: 10px solid; border-bottom: 10px solid; background-color: currentColor; background-clip: content-box; }
🌰 不使用伪元素,仅一层标签实现双层圆点效果
.icon-dot { display: inline-block; width: 100px; height: 100px; padding: 10px; border: 10px solid; border-radius: 50%; background-color: currentColor; background-clip: content-box; }
border 就是“边框”,border 属性在图形构建、体验优 化以及网页布局这几块大放异彩,同时保证其良好的兼容性和稳定的特性表现
border-width
text-shadow
thin
1px
medium
3px
border-style: double
thick
4px
border-style
border-color
border-style: solid
border-style: dashed
border-style: dotted
inset
outset
groove
ridge
color
hover
currentColor
🌰 右下方 background 定位的技巧
假设现在有一个宽度不固定的元素,我们需要在距离右边缘 50 像素的位置设置一个背景图片,可以使用透明边框(默认 background 背景图片是相对于 padding box 定位的,也就是说,background-position: 100% 的位置计算默认是不会把 border-width 计算在内的):
background
background-position: 100%
.box { border-right: 50px solid transparent; /* 对 50px 的间距我们使用 transparent 边框表示 */ background-position: 100% 50%; /* 使用百分比 background- position 定位到我们想要的位置 */ }
🌰 优雅地增加点击区域大小
可以在 icon 外嵌套一层标签或者在 icon 上使用 padding 或透明 border
.icon-clear { width: 16px; height: 16px; border: 11px solid transparent; ... }
🌰 三角等图形绘制
border 属性可以轻松实现兼容性非常好的三角图形效果,其底层原因受 inset/outset 等看上去没有实用价值的 border-style 属性影响,这一转角规则也被 solid 类型的边框给沿用了,只要是与三角形或者梯形相关的图形,都可以使用 border 属性来模拟
solid
/* 四色边框,只留一边有颜色就是梯形,将宽高置为0就是三角形 */ div { width: 10px; height: 10px; border: 10px solid; border-color: #f30 #00f #396 #0f0; } /* 等腰直角三角形 */ div { width: 0; height: 0; border: 10px solid transparent; /* 仅调整垂直方向 border-width 可以让其更扁或更高 */ border-top-color: #f30; /* 保留两个方向的颜色,可以构造更多不同的三角形 */ } /* 利用梯形可以构造倒角矩形 */ div { position: relative; width: 200px; height: 100px; background: red; margin: 20px 20px; } div::before, div::after { content: ''; position: absolute; box-sizing: border-box; width: 200px; height: 10px; border: 10px solid transparent; } div::before{ top: -20px; border-bottom-color: red; } div::after{ top: 100px; border-top-color: red; }
🌰 使用 border 实现等高布局
如下:左侧深色背景区域是由 border-left 属性生成的,元素边框高度总是和元素自身高度保持一致,因此可以巧妙地实现等高布局效果
border-left
<div class="box clearfix"> <nav> <h3 class="nav">导航1</h3> </nav> <section> <div class="module">模块1</div> </section> </div> <style> /* 需要用 clearfix 清除浮动,这里不写出来 */ .box { border-left: 150px solid #333; background-color: #f0f3f9; } .box > nav { width: 150px; margin-left: -150px; float: left; } .box > section { overflow: hidden; } </style>
方便后面理解,先看下元素尺寸相关概念:
offsetWidth
offsetHeight
margin 同样可以改变元素的可视尺寸,但是和 padding 几乎是互补态势
<div class="father"> <div class="son"></div> </div> <script> .father { width: 300px; } /* 宽度300 */ .son { margin: 0 -20px; } /* 宽度340(300+20+20) */ </script>
对于普通块状元素,在默认的水平流下,margin 只能改变左右方向的内部尺寸,垂直方向则无法改变
但是,对于具有拉伸特性的绝对定位元素,则水平或垂直方向都可以
使用 writing-mode 改变流向为垂直流,则水平方向内部尺寸无法改变,垂直方向可以改变(这是由 margin: auto 的计算规则决定的)
writing-mode
margin: auto
🌰 一侧定宽的两栏自适应布局效果
以下案例文字内容就会根据 .box 盒子的宽度变化而自动排列,形成自适应布局效果,无论盒子是 200 像素还是 400 像素,布局依然良好,不会像纯浮动布局那样发生错位
.box
<style> .box { overflow: hidden; } .box > img { float: left; } /* .box > img { float: right; } */ /* 图片右侧定位 */ .box > p { margin-left: 140px; } </style> <div class="box"> <img src="1.jpg"> <p>文字内容...</p> </div>
图片右侧定位,但是按 HTML 顺序
<style> .box { overflow: hidden; } .full { width: 100%; float: left; } .box > img { float: left; margin-left: -128px; } .full > p { margin-right: 140px; } </style> <div class="box"> <div class="full"> <p>文字内容...</p> </div> <img src="1.jpg"> </div>
🌰 两端对齐布局
列表块两端对齐,一行显示 3 个,中间有 2 个 20 像素的间隙
li { float: left; width: 100px; margin-right: 20px; } /* 最右边也会有 30 的 margin,可以用下面的选择器或在第 3 个加上个类名 */ li:nth-of-type(3n) { margin-right: 0; }
还可以通过给父容器添加 margin 属性,增加容器的可用宽度来实现,此时 ul 的宽度就相当于 100% + 20px
100% + 20px
ul { margin-right: -20px; } ul > li { float: left; width: 100px; margin-right: 20px; }
对于外部尺寸,margin 属性的影响则更为广泛,只要元素具有块状特性,无论有没有设置 width/height,无论是水平方向还是垂直方向,即使发生了 margin 合并,margin 对外部尺寸都着着实实发生了影响
🌰 借助 margin 的外部尺寸特性来实现底部留白
只能使用子元素的 margin-bottom 来实现滚动容器的底部留白
margin-bottom
<div style="height:200px;"> <img height="300" style="margin:50px 0;"> </div>
🌰 利用 margin 外部尺寸实现等高布局
针对具有块状特性的元素而言,垂直方向 margin 无法改变元素的内部尺寸,但却能改变外部尺寸
默认情况下,垂直方向块级元素上下距离是 0,一旦 margin-bottom: -9999px 就意味着后面所有元素和上面元素的空间距离变成了-9999px,也就是后面元素都往上移动了 9999px
margin-bottom: -9999px
-9999px
9999px
此时,通过神来一笔 padding-bottom: 9999px 增加元素高度,这正负一抵消,对布局层并无影响,但却带来了我们需要的东西——视觉层多了 9999px 高度的可使用的背景色,需要配合父级 overflow: hidden 把多出来的色块背景隐藏掉,于是实现了视觉上的等高布局效果
padding-bottom: 9999px
overflow: hidden
如果需要有子元素定位到容器之外,父级的 overflow: hidden 是一个棘手的限制;其次,当触发锚点定位或者使用DOM.scrollIntoview() 方法的时候,可能就会出现奇怪的定位问题
DOM.scrollIntoview()
.column-box { overflow: hidden; } .column-left, .column-right { margin-bottom: -9999px; padding-bottom: 9999px; }
内联元素垂直方向的 margin 是没有任何影响的,既不会影响外部尺寸,也不会影响内部尺寸,有种石沉大海的感觉
对于水平方向,由于内联元素宽度表现为“包裹性”,也不会影响内部尺寸
和 padding 属性一样,margin 的百分比值无论是水平方向还是垂直方向都是相对于宽度计算的
元素设置 margin 在垂直方向上无法改变元素自身的内部尺寸,往往需要父元素作为载体
此外,由于 margin 合并的存在,垂直方向往往需要双倍尺寸才能和 padding 表现一致
块级元素的上外边距(margin-top)与下外边距(margin-bottom)有时会合并为单个外边距,这样的现象称为“margin 合并”
margin-top
margin 合并的意义:
margin 合并的 3 种场景
1、相邻兄弟元素 margin 合并
<p>第一行</p> <p>第二行</p> <style> p { margin: 1em 0; outline: 1px solid red;} </style>
2、父级和第一个/最后一个子元素
<!-- 三种写法,无论是 son 还是 father 距离上边的距离都是 80px --> <div class="father"> <div class="son" style="margin-top:80px;"></div> </div> <div class="father" style="margin-top:80px;"> <div class="son"></div> </div> <div class="father" style="margin-top:80px;"> <div class="son" style="margin-top:80px;"></div> </div>
解决父子 margin 合并:
对于 margin-top 合并,可以进行如下操作(满足一个条件即可):
border-top
padding-top
对于 margin-bottom 合并,可以进行如下操作(满足一个条件即可):
border-bottom
padding-bottom
3、空块级元素的 margin 合并
因为垂直方向的上下 margin 值合二为一了,所以垂直方向的外部尺寸只有水平方向的一半。
<!-- 此时 .father 所在的这个父级元素高度仅仅是 1em,因为 .son 这个空元素的 margin-top 和 margin-bottom 合并在一起了 --> <div class="father"> <div class="son"></div> </div> <!-- 此时第一行和第二行之间的距离还是 1em,中间看上去隔了一个 <div> 元素,但对最终效果却没有任何影响 --> <p>第一行</p> <div></div> <p>第二行</p> <style> div { outline: 1px solid red; } .father { overflow: hidden; } .son { margin: 1em 0; } p { margin: 1em 0; } </style>
如果不希望空元素有 margin 合并,可以进行如下操作:
如果同号,取绝对值最大的那个
如果异号,则 margin 结果为相加的值
margin:auto 的填充规则如下:
margin:auto
✨ margin 属性的 auto 计算就是为块级元素左中右对齐而设计的,和内联元素使用 text-align 控制左中右对齐正好遥相呼应(对于替换元素,如果我们设置 display: block,则 margin: auto 的计算规则同样适合)
text-align
.container { margin: 0 auto; width: 200px; }
触发 margin: auto 计算有一个前提条件,就是 width 或 height 为 auto 时,元素是具有对应方向的自动填充特性的,需要 margin: auto 可以让元素在垂直方向居中:
/* 第一种 */ .father { height: 200px; writing-mode: vertical-lr; /* 更改文档流方向 */ } .son { height: 100px; 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: auto; }
table-row
table-caption
margin-right
✨ 块级元素负责结构,内联元素接管内容,而 CSS 世界是面向图文混排,也就是内联元素设计的
默认空 div 的高度是 0
div
对于非替换元素的纯内联元素,他的可视高度完全由 line-height 决定,padding、border 属性对它的可视高度没有任何影响
line-height 不可以影响替换元素(如图片的高度)
对于块级元素,line-height 对其本身是没有任何作用的
默认值为 normal
normal
font-family
数值:如 line-height: 1.5,其最终的计算值是和当前 font-size 相乘后的值
line-height: 1.5
1.5
百分比值:如 line-height: 150%,其最终的计算值是和当前 font-size 相乘后的值
line-height: 150%
长度值:也就是带单位的值,如 line-height: 21px 或者 line-height: 1.5em 等
line-height: 21px
line-height: 1.5em
看一下示例代码:
<div class="box"> <span>内容...</span> </div> <div class="box1"> <span>内容...</span> </div> <style> .box { line-height: 96px; } .box span { line-height: 20px; } .box1 { line-height: 20px; } .box1 span { line-height: 96px; } </style>
会发现 .box 和 .box1 全都是 96px 高
.box1
✨ 无论内联元素 line-height 如何设置,最终父级元素的高度都是由数值大的那个 line-height 决定的,我称之为“内联元素 line-height 的大值特性”
解释:幽灵节点!!!
line-height: 96px
96px
line-height: 20px
display: inline-block
🌰 要让单行文字垂直居中,只需要 line-height 这一个属性就可以,并不需要依靠 height 属性
.title { line-height: 24px; }
line-height 可以让单行或多行元素近似垂直居中(通过 line-height 设置的垂直居中,并不是真正意义上的垂直居中)
🌰 行高实现多行文本或者图片等替换元素的垂直居中效果
<style> .box { line-height: 120px; background-color: #f0f3f9; } .content { display: inline-block; line-height: 20px; margin: 0 20px; vertical-align: middle; } </style> <div class="box"> <div class="content">基于行高实现的...</div> </div>
实现原理
.content
vertical-align: middle
📌 凡是 line-height 起作用的地方 vertical-align 也一定起作用
在各种内联相关模型中,凡是涉及垂直方向的排版或者对齐的,都离不开最基本的基线(baseline)
字母 x 的下边缘(线)就是我们的基线
x-height
vertical-align: middle 中 middle 指的是基线往上1/2 x-height 高度。我们可以近似理解为字母 x 交叉点那个位置。
middle
1/2 x-height
vertical-align: middle 并不是绝对的垂直居中对齐,我们平常看到的 middle 效果只是一种近似效果,因为不同的字体在行内盒子中的位置是不一样的。
对于内联元素垂直居中应该是对文字,而非居外部的块级容器所言。
ex
🌰 应用:小图标对齐
.icon-arrow { display: inline-block; width: 20px; height: 1ex; background: url(arrow.png) no-repeat center; }
内联元素默认是基线对齐的,而基线就是 x 的底部,而 1ex 就是一个x的高度。设想一下,假如图标高度就是 1ex ,同时背景图片居中,岂不是图标和文字天然垂直居中,而且完全不受字体和字号的影响?因为 ex 就是一个相对于字体和字号的单位。
1ex
inline- block
<td>
除去 inherit 这类全局属性值不谈,可以把 vertical-align 属性值分为以下4类:
inherit
线类,如 baseline(默认值)、top、middle、bottom
top
bottom
overflow
visible
vertical-align: top
<tr>
font-size: 0
12px
14px
2px
文本类,如 text-top、text-bottom
text-top
text-bottom
vertical-align: text-top
vertical-align: text-bottom
sub
super
vertical-align: super
vertical-align: sub
数值百分比类,如 20px、2em、20% 等
20px
2em
20%
vertical-align: baseline
vertical-align: 0
✨ 对于内联元素,如果遇到不太好理解的现象,请一定要意识到,有个“幽灵空白节点”以及无处不在的 vertical-align 属性
不同属性值定义完全不同,且很多属性 table-cell 元素有着不同的定义;同时最终表现与字符 x、line-height,和 font-size、font-family 属性密切相关
🌰 基于 20px 图标对齐的处理技巧
.icon { display: inline-block; width: 20px; height: 20px; background: url(sprite.png) no-repeat; white-space: nowrap; letter-spacing: -1em; text-indent: -999em; } .icon:before { content: '\3000'; } /* 具体图标 */ .icon-xxx { background-position: 0 -20px; } ...
🌰 基于 vertical-align 属性的水平垂直居中弹框
无论浏览器尺寸是多大,也无论弹框尺寸是多少,弹框永远都是居中的
<div class="container"> <div class="dialog"></div> </div> <style> .container { position: fixed; top: 0; right: 0; bottom: 0; left: 0; background-color: rgba(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>
CSS 世界中正常的流内容或者流布局虽然也足够强大,但是实现的总是方方正正、规规矩矩的效果,有时候需要一些特殊的布局表现,例如,文字环绕效果,或者元素固定在某个位置,浮动和定位就在这里生效了
浮动的本质就是为了实现文字环绕效果而设计的
纯浮动布局容错性差,容易出现比较严重的布局问题,也容易出现意料之外的情况,这里的意料之外除了 float 属性自身特性(如父元素高度塌陷)导致的布局问题外,还包括诸多兼容性问题
float
margin-left
利用 float 破坏 CSS 正常流的特性,实现两栏或多栏的自适应布局
🌰 一侧定宽的两栏自适应布局
<div class="father"> <div class="menu"></div> <div class="content">this is content … Lorem100</div> </div> <style> .father { overflow: hidden; } .father .menu { width: 60px; height: 64px; float: left; background: #eee;} .father .content { margin-left: 70px; background: #eee;} </style>
左侧定宽且浮动,右侧元素 margin-left 比左侧宽多 10 像素,不会发生环绕,且是自适应的
语法 clear: none | left | right | both,基本使用 both 就可以了
clear: none | left | right | both
both
clear: both 的作用本质是让自己不和 float 元素在一行显示,并不是真正意义上的清除浮动,而是抗浮动,float 一些特性仍存在:
clear: both
clear 属性只有块级元素才有效,因此经常这样写:
.clearfix::after { content: ''; /* 默认是内联 */ display: table; /* block list-item 也可以 */ clear: both; }
clear: both 只能在一定程度上消除浮动的影响,要想完美地去除浮动元素的 影响,还需要使用其他 CSS 声明
BFC 全称是 Block Formatting Context,块级格式化上下文
BFC 表现原则:
BFC 形成条件:
<html>
scroll
hidden
position
relative
一般认为使用 BFC 特性清除浮动的影响要比使用 clear 更优,但是使用不同属性也有不同的效果:
float: left
position: absolute
所以好用一点的还是:overflow: hidden
overflow 设置 hidden、auto 或scroll,利用 BFC 的“结界”特性彻底解决浮动对外部或兄弟元素的影响,能够清除浮动的影响和解决 margin 嵌套合并
设置 overflow: hidden 之后,元素会把超出部分进行裁剪
裁剪的边界是 border 的内边缘
visible 是默认值;hidden 会进行裁剪;scroll 滚动条会一直出现;auto 当内容少时没有滚动条,当内容超出时滚动条出现
如果 overflow-x 和 overflow-y 属性中的一个值设置为 visible 而另外一个设置为 scroll、auto 或 hidden,则 visible 的样式表现会如同 auto
overflow-x
overflow-y
除非 overflow-x 和 overflow-y 的属性值都是 visible,否则 visible 会当成 auto 来解析
永远不可能实现一个方向溢出剪裁或滚动,另一方向内容溢出显示的效果
HTML 中有两个标签是默认可以产生滚动条的,一个是根元素 <html>,另一个是文本域 <textarea>(这两个默认的是 auto)
在 PC 端,无论是什么浏览器,默认滚动条均来自 <html>,而不是标签 <body>
<body>
去除页面默认滚动条:html { overflow: hidden; }
html { overflow: hidden; }
PC 端滚动条会占用容器的可用宽度或高度(默认是 17px)
17px
移动端则不一定
document.documentElement.scrollTop
document.body.scrollTop
滚动条可以自定义,Chrome 下:
::-webkit-scrollbar
::-webkit-scrollbar-button
::-webkit-scrollbar-track
::-webkit-scrollbar-track-piece
::-webkit-scrollbar-thumb
::-webkit-scrollbar-corner
🌰 单行文字溢出点点点
.ell { text-overflow: ellipsis; white-space: nowrap; overflow: hidden; }
🌰 多行文本溢出省略
.ell { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; /* 几行就设几 */ }
float: right
absolute
fixed
position: fixed
left/top/right/bottom
relative>overflow>absolute
relative.overflow>absolute
overflow>relative>absolute
overflow>absolute
transform
clip
clip: rect(top, right, bottom, left)
clip: rect(top right bottom left)
h1 { position: absolute; clip: rect(0 0 0 0); }
text-indent
.box { position: absolute; left: 0; right: 0; top: 0; bottom: 0; margin: 30px; }
.element { width: 300px; height: 200px; position: absolute; left: 0; right: 0; top: 0; bottom: 0; margin: auto; }
relative/absolute/fixed
top/bottom
left/right
left
position: fixed 固定定位元素的“包含块”是根元素,我们可以将其近似看成 <html> 元素
🌰 模态框的蒙层无法覆盖浏览器右侧的滚动栏,并且鼠标滚动的时候后面的背景内容依然可以被滚动,并没有被锁定
position: fixed 蒙层之所以出现背景依然滚动,那是因为滚动元素是根元素,正好是 position: fixed 的“包含块”。所以,如果希望背景被锁定,让页面滚动条由内部的普通元素产生即可
移动端项目,阻止 touchmove 事件的默认行为可以防止滚动;如果是桌面端项目,可以让根元素直接 overflow: hidden,并且使用同等宽度的透明边框填充消失的滚动条
touchmove
在蒙层显示的同时执行下面的 JavaScript 代码
var widthBar = 17, root = document.documentElement; if (typeof window.innerWidth == 'number') { widthBar = window.innerWidth - root.clientWidth; } root.style.overflow = 'hidden'; root.style.borderRight = widthBar + 'px solid transparent';
隐藏的时候执行下面的 JavaScript 代码
var root = document.documentElement; root.style.overflow = ''; root.style.borderRight = '';
“层叠规则”,指的是当网页中的元素发生层叠时的表现规则
层叠上下文,英文称作 stacking context,是 HTML 中的一个三维的概念
如果一个元素含有层叠上下文,我们可以理解为这个元素在 z 轴上就“高人一等”
层叠水平,英文称作 stacking level,决定了同一个层叠上下文中元素在 z 轴上的显示顺序
所有的元素都有层叠水平,包括层叠上下文元素,也包括普通元素
然而,对普通元素的层叠水平探讨只局限在当前层叠上下文元素中
某些情况下 z-index 确实可以影响层叠水平,但是只限于定位元素以及 flex 盒子的孩子元素;而层叠水平所有的元素都存在
z-index
flex
层叠顺序,英文称作 stacking order,表示元素发生层叠时有着特定的垂直显示顺序。
CSS 2.1 下,层叠顺序规则如下图所示:
(1)位于最下面的 background/border 特指层叠上下文元素的边框和背景色。每一个层叠顺序规则仅适用于当前层叠上下文元素的小世界。
background/border
(2)inline 水平盒子指的是包括 inline/inline-block/inline-table 元素的“层叠顺序”,它们都是同等级别的。
inline/inline-block/inline-table
(3)单纯从层叠水平上看,实际上 z-index: 0 和 z-index: auto 是可以看成是一样的。
z-index: 0
z-index: auto
background/border为装饰属性,浮动和块状元素一般用作布局,而内联元素都是内容
(1)谁大谁上:当具有明显的层叠水平标识的时候,如生效的 z-index 属性值,在同一个层叠上下文领域,层叠水平值大的那一个覆盖小的那一个。
(2)后来居上:当元素的层叠水平一致、层叠顺序相同的时候,在 DOM 流中处于后面的元素会覆盖前面的元素。
1、根层叠上下文
根层叠上下文指的是页面根元素,可以看成是元素。因此,页面中所有的元素一定处于至少一个“层叠结界”中。
2、定位元素与传统层叠上下文
对于 position 值为 relative/absolute 以及 Firefox/IE 浏览器(不包括 Chrome 浏览 器)下含有 position: fixed 声明的定位元素,当其 z-index 值不是 auto 的时候,会创建层叠上下文。
relative/absolute
3、CSS3 与新时代的层叠上下文
(1)元素为 flex 布局元素(父元素 display: flex|inline-flex),同时 z-index 值不是 auto (2)元素的 opacity 值不是 1 (3)元素的 transform 值不是 none (4)元素 mix-blend-mode 值不是 normal (5)元素的 filter 值不是 none (6)元素的 isolation 值是 isolate (7)元素的 will-change 属性值为上面 2~6 的任意一个(如 will-change: opacity、will-change: transform 等) (8)元素的 -webkit-overflow-scrolling 设为 touch
display: flex|inline-flex
opacity
mix-blend-mode
filter
isolation
isolate
will-change
will-change: opacity
will-change: transform
-webkit-overflow-scrolling
touch
(1)如果层叠上下文元素不依赖 z-index 数值,则其层叠顺序是 z-index: auto,可看成 z-index: 0 级别;
(2)如果层叠上下文元素依赖 z-index 数值,则其层叠顺序由 z-index 值决定。
元素一旦成为定位元素,其 z-index 就会自动生效,此时其 z-index 就是默认的 auto,也就是 0 级别,根据上面的层叠顺序表,就会覆盖 inline 或 block 或 float 元素
而不支持 z-index 的层叠上下文元素天然是 z-index: auto 级别,也就意味着,层叠上下文元素和定位元素是 一个层叠顺序的,于是当它们发生层叠的时候,遵循的是“后来居上”准则
从图中可以看到 z-index 负值元素的层级是在层叠上下文元素上面、block 元素的下面,也就是 z-index 虽然名为负数层级,但依然无法突破当前层叠上下文所包裹的小世界
内联元素默认基线对齐,图片的基线可以看成是图片的下边缘,文字内容的基线是字符 x 下边缘
因此想让一个图片图标和文字对齐,可以设置图片的 vertical-align 的值为文字的行高 * -25% 或 .6ex
文字的行高 * -25%
.6ex
之前有说 1ex 指的是字符 x 的高度,而 1em 指的是一个子模的高度('M')
x
1em
在 CSS 中,1em 的计算值等同于当前元素所在的 font-size 计算值,可以将其想象成当前元素中(如果有)汉字的高度
em 相对于当前元素,rem 相对于根元素
rem
font-size 的关键词属性
larger
smaller
xx-large
x-large
<h2>
large
<h3>
<h4>
small
<h5>
x-small
<h6>
xx-small
桌面 Chrome 浏览器下有个 12px 的字号限制,如果 font-size: 0 的字号表现就是 0,那么文字会直接被隐藏掉,并且只能是 font-size: 0,哪怕设置成 font-size: 0.0000001px,都还是会被当作 12px 处理的
font-size: 0.0000001px
据我测试,最新版的 Chrome 浏览器已经没有这个限制了
font-family 默认值由操作系统和浏览器共同决定
font-family 支持两类属性值,一类是“字体名”,一类是“字体族”,如果字体名包含空格,需要使用引号包起来(可以不用区分大小写;如果有多个字体设定,从左往右依次寻找本地是否有对应的字体即可)
body { font-family: 'PingFang SC', 'Microsoft Yahei', simsun; }
字体族分类:
serif
sans-serif
monospace
cursive
fantasy
system-ui
serif 和 sans-serif 一定要写在最后,因为在大多数浏览器下,写在 serif 和 sans-serif 后面的所有字体都会被忽略
等宽字体一般用于展示代码、一些字符
1ch 表示一个 0 字符的宽度,所以 6 个 0 所占据的宽度就是 6ch,用这个单位和等宽字体可以实现数字/字母一个个出现的效果
1ch
6ch
/* 平常用的最多的 */ font-weight: normal; font-weight: bold; /* 相对于父级元素 */ font-weight: lighter; font-weight: bolder; /* 字重的精细控制 */ font-weight: 100; font-weight: 200; font-weight: 300; font-weight: 400; font-weight: 500; font-weight: 600; font-weight: 700; font-weight: 800; font-weight: 900; /* 400 等同于 normal,700 等同于 bold */
这些数值关键字浏览器都是支持的,之所以没有看到任何粗细的变化,是因为我们的系统里面缺乏对应粗细的字体
font-weight 要想真正发挥潜力,问题不在于 CSS 的支持,而在于是否存在对应的字体文件
font-weight
font-style: normal; font-style: italic; font-style: oblique;
italic 是使用当前字体的斜体字体,而 oblique 只是单纯地让文字倾斜
italic
oblique
如果当前字体没有对应的斜体字体,则退而求其次,解析为 oblique,也就是单纯形状倾斜
可以缩写在 font 属性中的属性非常多,包括 font-style、font-variant、 font-weight、font-size、line-height、font-family 等
font
font-style
font-variant
完整语法为:
font: [ [ font-style || font-variant || font-weight ]? font-size [ / line-height ]? font-family ] /* ||表示或,?和正则表达式中的?的含义一致,表示 0 个或 1 个 */
font-size 和 font-family 是必需的,是不可以省略的
font 还支持关键字属性值,使用关键字作为属性值的时候必须是独立的,只能使用一下值
font:caption | icon | menu | message-box | small-caption | status-bar
如果将 font 属性设置为上面的一个值,就等同于设置 font 为操作系统该部件对应的 font,也就是说直接使用系统字体
caption
icon
menu
message-box
small-caption
status-bar
@font-face 本质上就是一个定 义字体或字体集的变量,这个变量不仅仅是简单地自定义字体,还包括字体重命名、默认字体样式设置等
@font-face 规则支持的 CSS 属性有 font-family、src、font-style、font-weigh、unicode-range、font-variant、font-stretch 和 font-feature-settings,例如:
font-weigh
unicode-range
font-stretch
font-feature-settings
@font-face { font-family: 'example'; /* 给字体取个名字 */ src: url(example.ttf); /* 字体资源 */ font-style: normal; font-weight: normal; unicode-range: U+0025-00FF; font-variant: small-caps; font-stretch: expanded; font-feature-settings:"liga1" on; }
src 可以给多种字体格式,因为不同系统兼容性不同,我们可以优先使用 woff2,然后是 woff 格式字体
p { text-indent: 2em; }
text-indent 的百分比值是相对于当前元素的“包含块”计算的,而不是当前元素
默认值是 normal,计算值还是 0,支持负值
letter-spacing 作用于所有字符,但 word-spacing 仅作用于空格字符
letter-spacing
word-spacing
word-break 属性,语法如下:
word-break
word-break: normal; word-break: break-all; word-break: keep-all;
break-all
keep-all
word-wrap
word-wrap: normal; word-wrap: break-word;
break-word
word-break: break-all 和 word-wrap: break-word 效果区别
word-break: break-all
word-wrap: break-word
white-space 属性声明了如何处理元素内的空白字符,这类空白字符包括 Space(空格) 键、Enter(回车)键、Tab(制表符)键产生的空白
white-space
pre
nowrap
pre-wrap
pre-line
white-space 的功能分 3 个维度,分别是:是否合并空白字符,是否合并换行符,以及文本是否自动换行
当 white-space 设置为 nowrap 的时候,元素的宽度此时表现为“最大可用宽度”,换行符和一些空格全部合并,文本一行显示
text-overflow: ellipsis
text-align: justify 两端对齐,除了实现文本的两端对齐,还可以实现容错性更强的两端对齐布局效果
text-align: justify
在默认设置下,text-align: justify 要想有两端对齐的效果,需要满足两点:一是有分隔点,如空格;二是要超过一行,此时非最后一行内容会两端对齐
所以可以把子元素设置为 inline-block,在容器上设置伪元素且设置内敛快宽度撑满
text-decoration 属性用于设置或删除文本装饰,装饰线是一条横穿文本基线的线
text-decoration
text-decoration 属性支持的属性值有 none、underline、overline、line-through、blink,其中 blink 已经被废弃
underline
overline
line-through
blink
下划线可能会和文字重叠,所以一般用 border-bottom 模拟下划线
a { text-decoration: none; border-bottom: 1px solid currentColor; padding-bottom: .2em; }
text-transform 也是为英文字符设计的,要么全大写 text-transform: uppercase, 要么全小写 text-transform: lowercase
text-transform
text-transform: uppercase
text-transform: lowercase
table- cell
inline-block/inline-table
visibility
display: none
🌰 修改价格前面的美元符号
/* .price{$13.50} */ .price::first-letter { margin-right: 5px; font-size: .8em; vertical-align: -2px; }
🌰 适合单行的使用了 currentColor 的场景
<button class="btn-normal green">确定</button> <button class="btn-normal red">取消</button> <style> .green { color: #1E887D; } .red { color: red; } button { background: currentColor; } button::first-line { color: white; } </style>
red
green
blue
purple
transparent
rgb()
rgba()
#000
#fefefe
#00000011
hsl()
hsla()
当我们使用 background 属性的时候,实际上使用的是一系列 background 相关属性的集合,包括:
background-image: none
background-position: 0% 0%
background-repeat: repeat
background-attachment: scroll
background-size: auto auto
background-origin: padding-box
background-clip: border-box
属性值可以是具体数值,也可以是百分比值,还可以是 left、 top、right、center 和 bottom 等关键字(CSS 中几乎带 position 的都是这样)
right
center
如果缺省偏移关键字,则会认为是 center,因此 background-position:top center 可以直接写成 background-position:top
background-position:top center
background-position:top
还支持同时出现 3 个值或 4 个值,作用是指定定位的偏移计算从哪个方位算起 background-position: right 40px bottom 20px; 表示距离右边缘 40 像素,距离底边缘 20 像素
background-position: right 40px bottom 20px;
也支持百分比值,positionX = (容器的宽度 - 图片的宽度) * percentX;、positionY = (容器的高度 - 图片的高度) * percentY;
positionX = (容器的宽度 - 图片的宽度) * percentX;
positionY = (容器的高度 - 图片的高度) * percentY;
background-repeat支持 repeat、repeat-x、repeat-y 这几个值
background-repeat
repeat
repeat-x
repeat-y
其中 repeat 是默认值,表示在水平和垂直方向都重复,repeat-x 表示在水平方向重复,repeat-y 表示在垂直方向重复
支持 scroll 和 fixed 两个属性值
其中 scroll 是默认值,背景图片会跟着页面滚动
fixed 表示背景相对于当前文档视区定位,也就是页面再怎么滚动背景图片位置依旧纹丝不动
background-color 背景色永远是最低的(无论是单背景图还是多背景图,背景色一定是在最底下的位置)
background-color
设置了背景色的元素,在激活状态(:active/:hover)的时候,可以使用背景图片设置渐变,这样最底部还是原来的背景色,而渐变色是在背景色上层
:active
:hover
a[href]:active, button:active { background-image: linear-gradient(to top, rgba(0,0,0,.05), rgba(0,0,0,.05)); }
使用 CSS 让元素不可见的方法很多,剪裁、定位到屏幕外、明度变化等都是可以的
如果希望元素不可见,同时不占据空间,辅助设备无法访问,同时不渲染,可以使用 <script> 标签隐藏
<script>
<script type="text/html"> <img src="1.jpg"> </script>
此时,图片 1.jpg 是不会有请求的
<script> 标签是不支持嵌套的,因此,如果希望在 <script> 标签中再放置其他不渲染的模板内容,可以试试使用 <textarea> 元素
<script type="text/html"> <img src="1.jpg"> <textarea style="display:none;"> <img src="2.jpg"> </textarea> </script>
图片 2.jpg 也是不会有请求的,<script> 标签隐藏内容获取使用 script.innerHTML,<textarea> 使用textarea.value
script.innerHTML
textarea.value
如果希望元素不可见,同时不占据空间,辅助设备无法访问,但资源有加载,DOM 可访问,则可以直接使用 display: none 隐藏
el { display: none; }
display 计算值是 none 则该元素以及所有后代元素都隐藏
Chrome 和 Safari 浏览器,若父元素 display: none,图片不加载,若本身背景图所在元素隐藏,则图片依旧会去加载
HTML 中有很多标签和属性天然 display: none,如 <style>、<script> 和 <dialog> 元素,如果这些标签在 <body> 元素中,那么设置 display: block 可以让标签内的内容显示在页面中(设置 contenteditable = "true" 可以实时编辑预览)
<style>
<dialog>
contenteditable = "true"
有的属性也是自带 display: none 的,例如 <input type="hidden" name="id" value="1">、<div hidden>None</div> (如果不放心可以在 CSS 加一条 [hidden]{ display: none })
<input type="hidden" name="id" value="1">
<div hidden>None</div>
[hidden]{ display: none }
display: none 显隐控制并不会影响 CSS3 animation 动画的实现,但是会影响 CSS3 transition 过渡效果执行(因此 transition 一般搭配 visibility 和 opacity 使用)
animation
transition
对于计数器列表元素,如果设置 display:none,则该元素不加入计数队列(例如原来 10 个有序列表,将第 2 个设置了 display: none,那么这个元素会消失,且第 3 个会变成 2,总计数是 9)
display:none
如果希望元素不可见,同时不占据空间,辅助设备无法访问,但显隐的时候可以有 transition 淡入淡出效果,则可以使用 visibility
.hidden { position: absolute; visibility: hidden; }
如果希望元素不可见,不能点击,辅助设备无法访问,但占据空间保留,则可以使用 visibility:hidden 隐藏
visibility:hidden
el { visibility: hidden; }
父元素设置 visibility:hidden,子元素也会看不见,究其原因是继承性,子元素继承了 visibility:hidden,但是,如果子元素设置了 visibility:visible,则子元素又会显示出来
visibility:visible
visibility:hidden 不会影响计数器的计数,这和 display:none 完全不一样
如果希望元素不可见,不能点击,不占据空间,但键盘可访问,则可以使用 clip 剪裁隐藏
.clip { position: absolute; clip: rect(0 0 0 0); } .out { position: relative; left: -999em; }
如果希望元素不可见,不能点击,但占据空间,且键盘可访问,则可以试试 relative 隐藏。例如,如果条件允许,也就是和层叠上下文之间存在设置了背景色的父元素,则也可以使用更友好的 z-index 负值隐藏
.lower { position: relative; z-index: -1; }
如果希望元素不可见,但可以点击,而且不占据空间,则可以使用透明度
.opacity { position: absolute; opacity: 0; filter: Alpha(opacity=0); }
如果单纯希望元素看不见,但位置保留,依然可以点可以选,则直接让透明度为 0
.opacity { opacity: 0; filter: Alpha(opacity=0); }
outline 表示元素的轮廓,语法和 border 属性非常类似,分宽度、类型和颜色,支持的关键字和属性值与 border 属性一模一样
.outline { outline: 1px solid #000; }
表单按钮 focus 的时候会显示轮廓,按 Tab 可以聚焦到下一个元素,按 Enter 相当于鼠标点击(不要把全局的轮廓都去掉,只去掉需要的就可以)
focus
.input { outline: 0; /* 或者 none */ } .input:focus { border-color: Highlight; }
outline 是一个真正意义上不占任何空间的属性
🌰 图片镂空效果
<div class="crop"> <div class="crop-area"></div> <img src="1.png" alt="1"> </div> <style> .crop { overflow: hidden; } .crop > .crop-area { width: 80px; height: 80px; outline: 256px solid rgba(0,0,0,.5); /* 宽度比容器要大 */ cursor: move; } </style>
常规
cursor: auto
cursor
cursor: default
cursor: none
mousemove
链接和状态
cursor: pointer
cursor: help
cursor: progress
body { cursor: progress }
document.body.style.cursor = 'auto'
cursor: wait
cursor: context-menu
选择
cursor: text
cursor: vertical-text
cursor: crosshair
cursor: cell
拖曳
cursor: move
cursor: copy
cursor: alias
cursor: no-drop
cursor: not-allowed
滚动
cursor: all-scroll
拉伸
cursor: col-resize
cursor: row-resize
缩放
cursor: zoom-in
cursor: zoom-out
抓取
cursor: grab
cursor: grabbing
除了自带的还可以自定义光标:
.cur-none { cursor: url(transparent.cur); }
通过属性 direction 改变文档流的水平方向
direction
direction: ltr; // 默认值 direction: rtl;
direction 属性默认有这么一个特性,即可以改变替换元素或者 inline-block/ inline-table 元素的水平呈现顺序
inline-block/ inline-table
HTML 中可以改变顺序
<p dir="rtl"> <img src="1.jpg"> <img src="2.jpg"> </p>
按钮的顺序就可以通过这个改变
文字省略也可以用这个改变到前面去
<p class="ell" dir="ltr">这个是默认的,省略号会在这里显示<p> <p class="ell" dir="rtl">省略号会在前面显示,这里的文字会完整显示出来<p> <style> .ell { width: 240px; white-space: nowrap; text-overflow: ellipsis; overflow: hidden; } </style>
direction 属性还可以轻松改变表格中列的呈现顺序(左边的单元格到右边)
directionL:rtl 还可以让 text-justify 两端对齐元素,最后一行落单的元素右对齐
directionL:rtl
text-justify
只要是内联元素,只要与书写流相关,都可以试试 direction 属性
搭配 unicode-bidi 可以改变文字的方向
unicode-bidi
unicode-bidi: normal; // 默认值 unicode-bidi: embed; /* 如果是被下面的声明嵌套的,那么方向会相反 */ unicode-bidi: bidi-override; /* 强制所有的字符按照 direction 的方向排列 */
writing-mode 原本是为控制内联元素的显示而设计的(即所谓的垂直文本布局),用来实现文字竖向呈现
/* 关键字值 */ writing-mode: horizontal-tb; /* 默认值 文本流是水平方向,元素是从上往下的 */ writing-mode: vertical-rl; /* 文本是垂直方向,阅读的顺序是从右往左 */ writing-mode: vertical-lr; /* 文本是垂直方向,阅读顺序是从左往由 */ writing-mode: inherit; writing-mode: initial; writing-mode: unset;
writing-mode 将页面默认的水平流改成了垂直流
.vertical-mode { writing-mode: tb-rl; -webkit-writing-mode: vertical-rl; writing-mode: vertical-rl; }
text-align: center
title: CSS 世界笔记 date: 2022-10-12 20:32 updated: 2022-10-12 20:32 cover: //cdn.wallleap.cn/img/pic/illustrtion/202210121558633.jpg category: 技术杂谈 tags:
前端 description: CSS 世界笔记
本文由个人学习张鑫旭老师的《CSS 世界》整理而来,通过阅读这本书,发现了很多之前没注意到的细节,文中加入了自己的想法和理解,舍弃了有关 IE 兼容性的问题,建议有一定 CSS 基础的同学阅读,如有错误请指正。
基本概念
层叠样式表
CSS 全称是 Cascading Style Sheets,翻译成中文就是“层叠样式表”,所谓“层叠”,顾名思义,就是样式可以层层累加,比方说页面元素都继承了 12 像素的大小,某标题就可以设置成 14 像素进行叠加。这种层叠策略对于样式的显示是相当的灵活。
CSS 规则集
CSS 是由一个个规则集(ruleset)组成的,规则集包括选择器和声明块两部分
,
分隔{}
包括起来的内容,其中每一条是一个声明(Declaration),声明是一组键值对(使用冒号隔开,左边的是键,右边的是值),每条声明用;
隔开其他概念:
/* */
之间,不支持类似/* 注释1 /* 注释2 */ */
的嵌套rgba
和hsla
)、背景图片地址(url
)、元素属性值、计算(calc
)和过渡效果等,如rgba(0,0,0,.5)
、url('css-world.png')
、attr('href')
和scale(-1)
@
字符开始的一些规则,像@media
、@font-face
、@page
或者@support
,诸如此类选择器
选择器是用来瞄准(选择)目标元素的东西,例如,上面的
.selector
就是一个选择器.
这个点号开头的选择器。很多元素可以应用同一个类选择器。 “类”,天生就是被公用的命。#
打头,权重相当高。ID 一般指向唯一元素。但是,在 CSS 中,ID 样式出现在多个不同的元素上并不会只渲染第一个,而是雨露均沾。但显然不推荐这么做。[]
的选择器,形如[title]{}
、[title="css-world"]{}
、[title~="css-world"]{}
、[title^= "css-world"]{}
和[title$="css-world"]{}
等。:
的选择器,如:first-child
或:last-child
等。::first-line
、::first-letter
、::before
和::after
。`、
>、
~,还有
+`等,这些都是非常常用的选择器。>
连接。~
连接。+
连接。CSS 世界中的“未定义行为”
Web 应用场景千变万化,Web 标准也是不可能面面俱到的,也会存在规范描述以外的场景,此时,各大浏览器厂家只能根据自己的理解与喜好去实现,一旦个性化就会出现差异,就比如 Firefox 和 IE/Chrome 浏览器表现不一样。
实际上,此时遇到的表现差异并不是浏览器的 bug,用计算机领域的专业术语描述应该是“未定义行为”(undefined behavior)。
CSS 世界的“世界观”
文档流
“流”实际上是 CSS 世界中的一种基本的定位和布局机制,可以理解为现实世界的一套物理规则,“流”跟现实世界的“水流”有异曲同工的表现。
所谓“流”,就是 CSS 世界中引导元素排列和定位的一条看不见的“水流”。
CSS 世界构建的基石是 HTML,而 HTML 最具代表的两个基石
<div>
和<span>
正好是 CSS 世界中块级元素和内联级元素的代表,它们对应的正是图 1-3 所示的盛水容器中的水和木头,其特性表现也正如现实世界的水和木头,如图 1-4 所示。流是如何影响整个 CSS 世界的?
CSS 世界的基石——HTML 元素
HTML 常见的标签有
<div>
、<p>
、<li>
和<table>
以及<span>
、<img>
、<strong>
和<em>
等。虽然标签种类繁多,但通常我们就把它们分为两类:块级元素(block-level element)和内联元素(inline element)。
块级元素
块级元素占据其父元素(容器)的整个水平空间(一般独占一行),垂直空间等于其内容高度,常见的块级元素有
<div>
、<li>
和<table>
等。这些元素的
display
属性值默认是block
、table
、list-item
等。正是由于“块级元素”具有换行特性,因此理论上它都可以配合
clear
属性来清除浮动带来的影响。内联元素
内联元素又叫行内元素,指只占据它对应标签的边框所包含的空间的元素,这些元素如果父元素宽度足够则并排在一行显示的,如
span
、a
、em
、i
、img
、td
等。“内联元素”的“内联”特指后文提到的“外在盒子”,这些元素的
display
值默认是inline
、inline-block
、inline-table
、table-cell
等。CSS 盒模型
外在盒子和内在盒子
每个元素都两个盒子,外在盒子和内在盒子
inline
、block
和run-in
三种水平(其中run-in
鲜有人使用,且有淘汰风险,可以忽略)width
和height
是作用在这个盒子的)content-box
、padding-box
、border-box
和margin box
(margin
的背景永远是透明的)按照
display
的属性值不同,外在盒子和内在盒子组成不同block
的元素的盒子实际由外在的“块级盒子”和内在的“块级容器盒子”组成,所以独占一行且可设置宽高inline-block
的元素则由外在的“内联盒子”和内在的“块级容器盒子”组成,没有独占一行但可设置宽高inline
的元素则内外均是“内联盒子”,设置宽高无效且不会独占一行标准盒模型和怪异盒模型
可以通过设置
box-sizing
属性修改盒模型w3c 标准盒模型:
box-sizing: content-box
此模式下width
属性值为content
的宽度(这个是浏览器默认值)IE 盒模型:
box-sizing: border-box
此模式下width
属性值为border
+padding
+content
的宽度总和(具有继承性,实际开发时根据情况灵活设置)有 content 和 border,那有没有可能还有其他的?
内联盒模型
这里介绍的“内联盒模型”是简易版
内容区域(content area)
inline-box
又名内联盒子<span>
标签包裹文字会形成内联盒子anonymous inline box
匿名内联盒子line-box
名为行框盒子vertical-align
属性的影响)container-box
就是包含块的意思strut
“幽灵空白节点”基本尺寸
width 和 height
因为块级元素的流体特性主要体现在水平方向上,所以我们这里先着重讨论
width
width
/height
的默认值是auto
,由”浏览器决定“,基于元素的类型和父元素的宽度来计算max-width
和max-height
的初始值是none
虽然 MDN 和 W3C 维基的文档上都显示
min-width
/min-height
的初始值是0
,但是,根据作者的分析和测试,所有浏览器中的min-width
/min-height
的初始值都是auto
(❓ 这里我没有太理解嘿,盒子默认没有内容,高度就是 0,有了内容,盒子高度由内容决定,min-height
始终为 0 也是合理的)深藏不露的
width: auto
width
的默认值是auto
,它至少包含了以下 4 种不同的宽度表现:<div>
、<p>
这些元素的宽度默认是 100% 于父级容器的fill-available
inline-block
元素或table
元素shrink-to-fit
,直译为“收缩到合适”,有那么点儿意思,但不够形象,我一直把这种现象称为“包裹性”fit-content
指的就是这种宽度表现table-layout
为auto
的表格中,文字可能会出现“一柱擎天”的现象(自动换行变成一束)!width
相关设置,否则上面 3 种情况尺寸都不会主动超过父级容器宽度的white-space: nowrap
,则表现为“恰似一江春水向东流,流到断崖也不回头”相对简单而单纯的
height: auto
CSS 的默认流是水平方向的,宽度是稀缺的,高度是无限的,宽度的分配规则就比较复杂,高度就显得比较随意
height:auto
的表现:有几个元素盒子,每个多高,然后一加,就是最终的高度值了(由内容高度决定)不一定能生效的
height: 100%
height
和width
还有一个比较明显的区别就是对百分比单位的支持对于
width
属性,就算父元素width
为auto
,其百分比值也是支持的;但是,对于height
属性,如果父元素height
为auto
,只要子元素在文档流中,其百分比值完全就被忽略了让元素支持
height:100%
效果:设定显式的高度值,对于普通文档流中的元素,百分比高度值要想起作用,其父级必须有一个可以生效的高度值!
使用绝对定位,绝对定位的元素的百分比高度值是相对于最近的非
static
定位的祖先元素计算的min-width/max-width 和 min-height/max-min-height
CSS 世界中,
min-width
/max-width
和min-height
/max-height
属性间,以及与width
和height
之间有一套相互覆盖的规则:超越!important
,超越最大!important
指的是max-width
会覆盖width
min-width
覆盖max-width
🌰 例子1:图片最后呈现的宽度是
256px
🌰 例子2:最小宽度比最大宽度设置得还大,此时,“超越最大”规则,
min-width
活下来,max-width
被忽略,.container
元素表现为至少 1400 像素宽展开后的
max-height
值,我们只需要设定为保证比展开内容高度大的值就可以,但是,如果max-height
值太大,在收起的时候可能会有“效果延迟”的问题玩转盒模型
盒尺寸中的 4 个盒子 content box、padding box、border box 和 margin box 分别对应 CSS 世界中的
content
、padding
、border
和margin
属性content 与替换元素
CSS 的
content
CSS 属性用于在元素的::before
和::after
伪元素中插入内容使用
content
属性插入的内容都是匿名的可替换元素,它们不属于文档的一部分,因此不会被 CSS 选择器选中,也不会被 JavaScript 的document.querySelector()
方法选中可替换元素
根据“外在盒子”是内联还是块级我们可以把元素分为内联元素和块级元素
而根据是否具有可替换内容,我们也可以把元素分为替换元素和非替换元素
替换元素:通过修改某个属性值(例如
value
、src
等)呈现的内容就可以被替换的元素就称为“替换元素”,<img>
、<object>
、<video>
、<iframe>
或者表单元素<textarea>
和<input>
都是典型的替换元素vertical-align
的默认值的baseline
,但是替换元素不适用)非替换元素:内容不可替换,除了上述的元素基本都是非替换元素
替换元素的尺寸:从内而外分为 3 类——固有尺寸、HTML 尺寸和 CSS 尺寸
<img>
的width
和height
属性、<input>
的size
属性、<textarea>
的cols
和rows
属性等width
和height
或者max-width
/min-width
和max-height
/min-height
设置的尺寸,对应盒尺寸中的 content box替换元素的尺寸计算规则:
video
/canvas
/iframe
在现代浏览器下的尺寸表现为300x150px
,图片除外)img
标签设置display: block
但是尺寸还是按照上述规则计算)Web 开发的时候,为了提高加载性能以及节约带宽费用,首屏以下的图片就会通过滚屏加载的方式异步加载,当图片的
src
属性缺省的时候,图片不会有任何请求在 Chrome 浏览器下,所有的元素都支持
content
属性直接使用
content
属性添加图片路径,视觉上和src
引入路径一致;如果图片原来是有src
地址的,我们也是可以使用content
属性把图片内容给置换掉的content
属性改变的仅仅是视觉呈现,当我们以右键或其他形式保存这张图片的时候,所保存的还是原来src
对应的图片可前往 content 属性测试 - JS Bin 查看
使用
content
属性,我们还可以让普通标签元素变成替换元素之前实现网站主标题处仅显示 logo,不显示文字(视觉上展示图片,SEO 仍索引标题文字)是这样实现的:
我们可以通过添加
content
属性实现,代码更简洁但效果相同传统 CSS 代码的
<h1>
是一个普通元素,因此需要设定尺寸隐藏文字但是,下面使用
content
属性实现,<h1>
分分钟就变成了替换元素,文字自动被替换,同时尺寸规则就是替换元素的尺寸规则,完美适应原始图片大小查看:H1 title - JS Bin
在 CSS 世界中,我们把
content
属性生成的对象称为“匿名替换元素”(anonymous replaced element)content
生成的文本是无法选中、无法复制的,对可访问性和 SEO 都很不友好,content
属性只能用来生成一些无关紧要的内容,如装饰性图形或者序号之类:empty
伪类(元素里面无内容的时候进行匹配)content
动态生成值无法获取,例如计数器属性content 内容生成技术
在实际项目中,
content
属性几乎都是用在::before
/::after
这两个伪元素中,因此,“content 内容生成技术”有时候也称 “::before/::after 伪元素技术”。:before
伪元素用于辅助实现底对齐,:after
伪元素用于辅助实现两端对齐使用这种方式,需要注意 HTML 代码有些地方不能换行或者空格,有些地方则必须要换行或者有空格
除常规字符之外,我们还可以插入 Unicode 字符,例如换行符
常规实现:
自带属性
quotes
:可以任意指定
quotes
的字符,CSS 中还有 no-open-quote 和 no-close-quote 关键字,顾名思义,引号不需要了CSS 函数
counter()
,返回一个代表计数器的当前值的字符串。它通常和伪元素搭配使用,但是理论上可以在支持<string>
值的任何地方使用。 可以直接看这篇文章:使用 CSS 计数器更改有序列表序号样式初始化/重置计数器:
counter-reset: name 初始值
计数器递增:
counter-increment: name 递增值
显示计数:
content: counter(name, style)
/content: counters()
各种 content 内容生成语法是可以混合在 一起使用的
温和的 padding 属性
”温和”指的是我们在使用
padding
进行页面开发的时候很少会出现意想不到的情况。padding
指盒子的内补间(内边距)box-sizing
是content-box
,所以使用padding
会增加元素的尺寸box-sizing: border-box
,padding
小的时候元素尺寸就不会变化;但是,如果padding
值足够大,那么这个盒子还是会被撑大的(取大的值)padding
在垂直方向同样会影响布局,只是因为内联元素没有可视宽度和可视高度的说法(clientHeight
和clientWidth
永远是 0),垂直方向的行为表现完全受line-height
和vertical-align
的影响,视觉上并没有改变和上一行下一行内容的间距,因此,给我们的感觉就会是垂直padding
没有起作用padding
不会加入行盒高度的计算,margin
和border
也都是如此,都是不计算高度,但实际上在内联盒周围发生了渲染padding
百分比值无论是水平方向还是垂直方向均是相对于宽度计算的padding
会断行(padding
区域是跟着内联盒模型中的行框盒子走的)padding
会让“幽灵空白节点”显现,也就是规范中的“strut”出现(内联元素默认的高度完全受font-size
大小控制,可以把font-size
设为 0,但是不建议)ol
/ul
列表内置padding-left
,但是单位是px
,如果列表中的字体大小很小,则元素的项目符号(如点或数字)就会离元素的左边缘距离很开;如果font-size
比较大,则项目符号可能跑到列表元素的外面padding
<input>
/<textarea>
输入框内置padding
<button>
按钮内置padding
,按钮元素的padding
最难控制!Chrome 下button { padding: 0; }
就可以了,Firefox 下可以试试button::-moz-focus-inner { padding: 0; }
<select>
下拉内置padding
,如 Firefox、IE8 及以上版本浏览器可以设置padding
<radio>
/<checkbox>
单复选框无内置padding
<label>
元素去模拟button
、checkbox
、radio
(这些元素隐藏,<label>
元素的for
属性值和元素的id
值对应即可)CSS 中还有很多其他场景或属性会出现这种不影响其他元素布局而是出现层叠效果的现象,可以分为两类
box-shadow
以及outline
inline
元素的padding
层叠判断:如果父容器
overflow:auto
,层叠区域超出父容器的时候,没有滚动条出现,则是纯视觉的;如果出现滚动条,则会影响尺寸、影响布局除了使用
padding
,也可以使用透明的border
功勋卓越的 border 属性
border
就是“边框”,border
属性在图形构建、体验优 化以及网页布局这几块大放异彩,同时保证其良好的兼容性和稳定的特性表现border-width
却不支持百分比,主要是因为没有需要使用百分比值的场景(outline
、box-shadow
、text-shadow
这些也不支持百分比,原因相同)border-width
除了常见的数字+长度单位(0 的时候可以省略长度单位)还支持若干关键字thin
:薄薄的,等同于1px
medium
(默认值):薄厚均匀,等同于3px
(这个是因为border-style: double
至少3px
才有效果)thick
:厚厚的,等同于4px
border-style
的默认值是none
,因此设定了border-width
和border-color
之后并不会有边框显示border-style: solid
:实线边框border-style: dashed
:虚线边框,虚线颜色区的宽高比以及颜色区和透明区的宽度比例在不同浏 览器下是有差异的border-style: dotted
:虚点边框,在表现上同样有兼容性差异border-style: double
:双实线边框,border-width
大小不同,其表现不同(表现规则:双线宽度永远相等,中间间隔±1)inset
(内凹)、outset
(外凸)、groove
(沟槽)、ridge
(山脊)风格老土过时,且浏览器表现形式不一,因此,它们没有任何实用价值,但是他们的出现无形中规范了实线边框的转角连接规则border-color
颜色值的时候,会使用当前元素的color
计算值作为边框色(outline
、box-shadow
和text-shadow
也是这样),可以不设定边框颜色,hover
时只修改color
值,悬浮时它和它的伪元素边框颜色值也会变化currentColor
关键字:当前元素的color
计算值假设现在有一个宽度不固定的元素,我们需要在距离右边缘 50 像素的位置设置一个背景图片,可以使用透明边框(默认
background
背景图片是相对于 padding box 定位的,也就是说,background-position: 100%
的位置计算默认是不会把border-width
计算在内的):可以在 icon 外嵌套一层标签或者在 icon 上使用
padding
或透明border
border
属性可以轻松实现兼容性非常好的三角图形效果,其底层原因受inset
/outset
等看上去没有实用价值的border-style
属性影响,这一转角规则也被solid
类型的边框给沿用了,只要是与三角形或者梯形相关的图形,都可以使用border
属性来模拟如下:左侧深色背景区域是由
border-left
属性生成的,元素边框高度总是和元素自身高度保持一致,因此可以巧妙地实现等高布局效果激进的 margin 属性
方便后面理解,先看下元素尺寸相关概念:
padding
和border
,也就是元素的 border box 的尺寸。在原生的 DOM API 中写作offsetWidth
和offsetHeight
,所以,有时候也成为“元素偏移尺寸”。padding
但不包括border
,也就是元素的 padding box 的尺寸。在原生的 DOM API 中写作clientWidth
和clientHeight
,所以,有时候也称为“元素可视尺寸”。padding
和border
,还包括margin
, 也就是元素的 margin box 的尺寸。没有相对应的原生的 DOM API。外部尺寸的大小有可能是负数,可以理解成元素占据的空间尺寸。margin 与元素的内部尺寸
margin
同样可以改变元素的可视尺寸,但是和padding
几乎是互补态势padding
,元素设定了width
或者保持“包裹性”的时候,会改变元素可视尺寸margin
则相反,元素设定了width
值或者保持“包裹性”的时候,margin
对尺寸没有影响(宽度设定,margin
就无法改变元素尺寸);只有元素是“充分利用可用空间”状态的时候,margin
才可以改变元素的可视尺寸(只要元素的尺寸表现符合“充分利用可用空间”,无论是垂直方向还是水平方向,都可以通过margin
改变尺寸)对于普通块状元素,在默认的水平流下,
margin
只能改变左右方向的内部尺寸,垂直方向则无法改变但是,对于具有拉伸特性的绝对定位元素,则水平或垂直方向都可以
使用
writing-mode
改变流向为垂直流,则水平方向内部尺寸无法改变,垂直方向可以改变(这是由margin: auto
的计算规则决定的)以下案例文字内容就会根据
.box
盒子的宽度变化而自动排列,形成自适应布局效果,无论盒子是 200 像素还是 400 像素,布局依然良好,不会像纯浮动布局那样发生错位图片右侧定位,但是按 HTML 顺序
列表块两端对齐,一行显示 3 个,中间有 2 个 20 像素的间隙
还可以通过给父容器添加
margin
属性,增加容器的可用宽度来实现,此时ul
的宽度就相当于100% + 20px
margin 与元素的外部尺寸
对于外部尺寸,
margin
属性的影响则更为广泛,只要元素具有块状特性,无论有没有设置width
/height
,无论是水平方向还是垂直方向,即使发生了margin
合并,margin
对外部尺寸都着着实实发生了影响只能使用子元素的
margin-bottom
来实现滚动容器的底部留白针对具有块状特性的元素而言,垂直方向
margin
无法改变元素的内部尺寸,但却能改变外部尺寸默认情况下,垂直方向块级元素上下距离是 0,一旦
margin-bottom: -9999px
就意味着后面所有元素和上面元素的空间距离变成了-9999px
,也就是后面元素都往上移动了9999px
此时,通过神来一笔
padding-bottom: 9999px
增加元素高度,这正负一抵消,对布局层并无影响,但却带来了我们需要的东西——视觉层多了9999px
高度的可使用的背景色,需要配合父级overflow: hidden
把多出来的色块背景隐藏掉,于是实现了视觉上的等高布局效果如果需要有子元素定位到容器之外,父级的
overflow: hidden
是一个棘手的限制;其次,当触发锚点定位或者使用DOM.scrollIntoview()
方法的时候,可能就会出现奇怪的定位问题内联元素垂直方向的
margin
是没有任何影响的,既不会影响外部尺寸,也不会影响内部尺寸,有种石沉大海的感觉对于水平方向,由于内联元素宽度表现为“包裹性”,也不会影响内部尺寸
margin 的百分比值
和
padding
属性一样,margin
的百分比值无论是水平方向还是垂直方向都是相对于宽度计算的元素设置
margin
在垂直方向上无法改变元素自身的内部尺寸,往往需要父元素作为载体此外,由于
margin
合并的存在,垂直方向往往需要双倍尺寸才能和padding
表现一致margin 合并场景
块级元素的上外边距(
margin-top
)与下外边距(margin-bottom
)有时会合并为单个外边距,这样的现象称为“margin 合并”margin
合并的就是垂直方向margin 合并的意义:
margin
合并其作用和em
类似,都是让图文信息的排版更加舒服自然margin
合并使得在页面中任何地方嵌套或直接放入任何裸<div>
,都不会影响原来的块状布局margin
合并的意义在于可以避免不小心遗落或者生成的空标签影响排版和布局margin 合并的 3 种场景
1、相邻兄弟元素
margin
合并2、父级和第一个/最后一个子元素
解决父子
margin
合并:对于
margin-top
合并,可以进行如下操作(满足一个条件即可):border-top
值padding-top
值对于
margin-bottom
合并,可以进行如下操作(满足一个条件即可):border-bottom
值padding-bottom
值height
、min-height
或max-height
3、空块级元素的
margin
合并因为垂直方向的上下 margin 值合二为一了,所以垂直方向的外部尺寸只有水平方向的一半。
如果不希望空元素有
margin
合并,可以进行如下操作:border
padding
height
或者min-height
margin 合并的计算规则
如果同号,取绝对值最大的那个
如果异号,则
margin
结果为相加的值margin: auto
margin:auto
的填充规则如下:auto
,则auto
为剩余空间大小auto
,则平分剩余空间。触发
margin: auto
计算有一个前提条件,就是width
或height
为auto
时,元素是具有对应方向的自动填充特性的,需要margin: auto
可以让元素在垂直方向居中:writing-mode
改变文档流的方向margin: auto
居中margin 无效情形
display
计算值inline
的非替换元素的垂直margin
是无效的margin
有效,并且没有margin
合并的问题,所以图片永远不会发生margin
合并display
计算值是table-cell
或table-row
的元素的margin
都是无效的table-caption
、table
或者inline-table
则没有此问题,可以通过margin
控制外间距,甚至::first-letter
伪元素也可以解析margin
margin
合并的时候,更改margin
值可能是没有效果的(例如父子有一个margin
值很大,只要另一个值比他小那一直是无效的)margin
值“无效”margin-bottom
或者宽度定死的子元素的margin-right
的定位“失效”margin
无效margin
无效内联元素与流
行高 line-height
line-height 对元素高度的影响
默认空
div
的高度是0
line-height
属性决定的对于非替换元素的纯内联元素,他的可视高度完全由
line-height
决定,padding
、border
属性对它的可视高度没有任何影响line-height
之所以起作用,就是通过改变“行距”来实现的line-height
-font-size
(行距 = 行高 − em-box)line-height
直接决定了最终的高度line-height
不可以影响替换元素(如图片的高度)0
的“幽灵空白节点”,其内联特性表现和普通字符一模一样line-height
只能决定最小高度,对最终的高度表现有望尘莫及之感line-height
影响vertical-align
属性在背后作祟对于块级元素,
line-height
对其本身是没有任何作用的line-height
,块级元素的高度跟着变化实际上是通过改变块级元素里面内联级别元素占据的高度实现的line-height
、height
和min-height
以及盒模型中的margin
、padding
和border
等属性改变占据的高度,所有这一切就构成了 CSS 世界完整的高度体系line-height 属性值
默认值为
normal
normal
实际上是一个和font-family
有着密切关联的变量值line-height
都是有差异的数值:如
line-height: 1.5
,其最终的计算值是和当前font-size
相乘后的值1.5
)百分比值:如
line-height: 150%
,其最终的计算值是和当前font-size
相乘后的值长度值:也就是带单位的值,如
line-height: 21px
或者line-height: 1.5em
等内联元素 line-height 的“大值特性”
看一下示例代码:
会发现
.box
和.box1
全都是 96px 高解释:幽灵节点!!!
line-height
的,<span>
元素上的line-height
也确实覆盖了.box
元素<span>
元素的前方.box
元素设置line-height: 96px
时,“字符”高度96px
.box1
设置line-height: 20px
时,<span>
元素的高度则变成了96px
,而行框盒子的高度是由高度最高的那个“内联盒子”决定的<span>
元素display: inline-block
,创建一个独立的“行框盒子”,这样<span>
元素设置的line-height: 20px
就可以生效了,这也是下文多行文字垂直居中示例中这么设置的原因利用 line-height 实现文本居中
line-height
可以让单行或多行元素近似垂直居中(通过line-height
设置的垂直居中,并不是真正意义上的垂直居中)实现原理
display
为inline-block
line-height
为正常的大小vertical-align
属性,以及产生一个非常关键的“行框盒子”(让幽灵空白节点撑起高度).content
元素设置vertical-align: middle
来调整多行文本的垂直位置垂直对齐 vertical-align
字母 x
在各种内联相关模型中,凡是涉及垂直方向的排版或者对齐的,都离不开最基本的基线(baseline)
line-height
行高的定义就是两基线的间距vertical-align
的默认值就是基线,其他中线顶线一类的定义也离不开基线x-height
指的就是小写字母 x 的高度,术语描述就是基线和等分线(mean line)(也称作中线,midline)之间的距离。vertical-align: middle
中middle
指的是基线往上1/2 x-height
高度。我们可以近似理解为字母 x 交叉点那个位置。vertical-align: middle
并不是绝对的垂直居中对齐,我们平常看到的 middle 效果只是一种近似效果,因为不同的字体在行内盒子中的位置是不一样的。对于内联元素垂直居中应该是对文字,而非居外部的块级容器所言。
ex
是 CSS 中的一个相对单位,指的是小写字母 x 的高度,即x-height
ex
不受字体和字号影响的内联元素的垂直居中对齐效果🌰 应用:小图标对齐
内联元素默认是基线对齐的,而基线就是 x 的底部,而
1ex
就是一个x的高度。设想一下,假如图标高度就是1ex
,同时背景图片居中,岂不是图标和文字天然垂直居中,而且完全不受字体和字号的影响?因为ex
就是一个相对于字体和字号的单位。vertical-align 作用的前提
display
值为table-cell
的元素vertical-align
属性只能作用在display
计算值为inline
、inline- block
,inline-table
或table-cell
的元素上<span>
、<strong>
、<em>
等内联元素,<img>
、<button>
、<input>
等替换元素,非 HTML 规范的自定义标签元素,以及<td>
单元格,都是支持vertical-align
属性的,其他块级元素则不支持display
属性的计算值,从而导致vertical-align
不起作用vertical-align: middle
起作用了table-cell
元素设置vertical-align
垂直对齐的是子元素,但是其作用的并不是子元素,而是table-cell
元素自身vertical-align 属性值
除去
inherit
这类全局属性值不谈,可以把vertical-align
属性值分为以下4类:线类,如
baseline
(默认值)、top
、middle
、bottom
baseline
,内联元素默认都是沿着字母 x 的下边缘对齐的inline-block
元素,如果里面没有内联元素,或者overflow
不是visible
,则该元素的基线就是其margin
底边缘;否则其基线就是元素里面最后一行内联元素的基线vertical-align: top
就是垂直上边缘对齐(bottom
则相反)table-cell
元素:元素底padding
边缘和表格行的顶部对齐(类似<td>
元素,则和<tr>
元素上边缘对齐)line-height
和vertical-align: middle
实现的多行文本或者图片的垂直居中全部都是“近似垂直居中”1/2 x-height
处对齐(可以看作是 x 的交叉位置)table-cell
元素:单元格填充盒子相对于外面的表格行居中对齐font-size
越大偏移越明显,这才导致默认状态下的vertical-align: middle
实现的都是“近似垂直居中”font-size: 0
,整个字符 x 缩小成了一个看不见的点,根据line-height
的半行间距上下等分规则,这个点就正好是整个容器的垂直中心位置font-size
可能就12px
或14px
,虽然最终的效果是“近似垂直居中”,但偏差也就1px
~2px
的样子,普通用户其实是很难觉察到其中的差异的文本类,如
text-top
、text-bottom
vertical-align: text-top
:盒子的顶部和父级内容区域的顶部对齐(“父级内容区域”指的就是在父级元素当前font-size
和font-family
下应有的内容区域大小)vertical-align: text-bottom
:盒子的底部和父级内容区域的底部对齐sub
、super
两个值,分别表示下标和上标vertical-align: super
:提高盒子的基线到父级合适的上标基线位置vertical-align: sub
:降低盒子的基线到父级合适的下标基线位置数值百分比类,如
20px
、2em
、20%
等vertical-align
的计算值如果是负值,往下偏移,如果是正值,往上偏移vertical-align: baseline
等同于vertical-align: 0
)vertical-align
属性的百分比值是相对于line-height
的计算值计算的(margin
和padding
是相对于宽度计算的,line-height
是相对于font-size
计算的)无处不在的 vertical-align
不同属性值定义完全不同,且很多属性
table-cell
元素有着不同的定义;同时最终表现与字符 x、line-height
,和font-size
、font-family
属性密切相关20px
overflow: hidden
保证基线为里面字符的基线,但是要让里面潜在的字符不可见无论浏览器尺寸是多大,也无论弹框尺寸是多少,弹框永远都是居中的
流的破坏与保护
CSS 世界中正常的流内容或者流布局虽然也足够强大,但是实现的总是方方正正、规规矩矩的效果,有时候需要一些特殊的布局表现,例如,文字环绕效果,或者元素固定在某个位置,浮动和定位就在这里生效了
浮动 float
浮动的本质就是为了实现文字环绕效果而设计的
纯浮动布局容错性差,容易出现比较严重的布局问题,也容易出现意料之外的情况,这里的意料之外除了 float 属性自身特性(如父元素高度塌陷)导致的布局问题外,还包括
诸多兼容性问题float 的特性
none
时它的display
计算值就是block
或table
(display
值中除了inline-table
将转换成table
外,其他的都是block
)margin
合并float 的作用机制
float
有一个特性表现:会让父元素的高度塌陷float
属性让父元素高度塌陷的原因就是为了实现文字环绕效果margin-left
设置无穷大,和浮动元素在同一水平线上因为被约束也不会往它左边走float 与流体布局
利用
float
破坏 CSS 正常流的特性,实现两栏或多栏的自适应布局左侧定宽且浮动,右侧元素
margin-left
比左侧宽多 10 像素,不会发生环绕,且是自适应的清除浮动
clear
语法
clear: none | left | right | both
,基本使用both
就可以了clear: both
的作用本质是让自己不和float
元素在一行显示,并不是真正意义上的清除浮动,而是抗浮动,float
一些特性仍存在:clear: both
元素前面的元素就是float
元素,则margin-top
负值即使设置成-9999px
,也不见任何效果。clear: both
后面的元素依旧可能会发生文字环绕的现象。clear 属性只有块级元素才有效,因此经常这样写:
BFC
clear: both
只能在一定程度上消除浮动的影响,要想完美地去除浮动元素的 影响,还需要使用其他 CSS 声明BFC 全称是 Block Formatting Context,块级格式化上下文
BFC 表现原则:
clear
了)BFC 形成条件:
<html>
根元素float
值不为 noneoverflow
的值为auto
、scroll
或hidden
display
的值为table-cell
、table-caption
或inline-block
position
的值不为static
和relative
一般认为使用 BFC 特性清除浮动的影响要比使用
clear
更优,但是使用不同属性也有不同的效果:float: left
:虽然产生了 BFC 特性,但是浮动元素有破坏性和包裹性,失去了元素本身的流体自适应性,无法用来实现自动填满容器的自适应布局position: absolute
:使用这个属性元素完全脱离文档流overflow: hidden
:这个本身还是普通的元素,块状元素的流体特性仍然保留display: inline-block
:会让元素尺寸包裹收缩,会失去水平方向的流动特性所以好用一点的还是:
overflow: hidden
overflow
生成 BFC 特性
overflow
设置hidden
、auto
或scroll
,利用 BFC 的“结界”特性彻底解决浮动对外部或兄弟元素的影响,能够清除浮动的影响和解决margin
嵌套合并裁剪特性
设置
overflow: hidden
之后,元素会把超出部分进行裁剪裁剪的边界是 border 的内边缘
滚动条
visible
是默认值;hidden
会进行裁剪;scroll
滚动条会一直出现;auto
当内容少时没有滚动条,当内容超出时滚动条出现如果
overflow-x
和overflow-y
属性中的一个值设置为visible
而另外一个设置为scroll
、auto
或hidden
,则visible
的样式表现会如同auto
除非
overflow-x
和overflow-y
的属性值都是visible
,否则visible
会当成auto
来解析永远不可能实现一个方向溢出剪裁或滚动,另一方向内容溢出显示的效果
HTML 中有两个标签是默认可以产生滚动条的,一个是根元素
<html>
,另一个是文本域<textarea>
(这两个默认的是auto
)在 PC 端,无论是什么浏览器,默认滚动条均来自
<html>
,而不是标签<body>
去除页面默认滚动条:
html { overflow: hidden; }
PC 端滚动条会占用容器的可用宽度或高度(默认是
17px
)移动端则不一定
html { overflow: hidden; }
在移动端基本无效document.documentElement.scrollTop
获取,但是在移动端, 可能就要使用document.body.scrollTop
获取滚动条可以自定义,Chrome 下:
::-webkit-scrollbar
::-webkit-scrollbar-button
::-webkit-scrollbar-track
::-webkit-scrollbar-track-piece
::-webkit-scrollbar-thumb
::-webkit-scrollbar-corner
文本溢出
定位也能破坏流
absolute 绝对定位
position: absolute
和float: left
、float: right
一样,都有“块状化”、“包裹性”和“破坏性”等特性absolute
和float
同时存在时,float
属性是没有任何效果的position
属性值为absolute
或fixed
,其display
计算值就是block
或者table
display: inline-block
声明具有“包裹性”,因此使用决定定位之后就不需要加这个了)absolute
的自适应性最大宽度往往不是由父元素决定的,而是由包含块(containing block)决定的position
不为static
的祖先元素计算的position
是relative
或者static
,则“包含块” 由其最近的块容器祖先盒的 content box 边界形成position: fixed
,则“包含块”是“初始包含块”position: absolute
,则“包含块”由最近的position
不为static
的祖先元素建立white-space: nowrap
,让宽度表现从“包裹性”变成“最大可用宽度”absolute
是非常独立的 CSS 属性值,其样式和行为表现不依赖其他任何 CSS 属性就可以完成left/top/right/bottom
属性设置,并且其祖先元素全部都是非定位元素,其位置还是当前位置margin
实现一些小的图标、提示性文字、下拉列表、导航二级菜单等静态交互效果上text-align
居然可以改变absolute
元素的位置(本质上是“幽灵空白节点”和“无依赖绝对定位”共同作用的结果),只有原本是内联水平的元素绝对定位后可以受text-align
属性影响overflow
属性剪裁,尤其当overflow
在绝对定位元素及其包含块之间的时候(如果overflow
不是定位元素,同时绝对定位元素和overflow
容器之间也没有定位元素,则overflow
无法对absolute
元素进行剪裁)overflow
元素父级是定位元素(relative
)也不会剪裁(relative>overflow>absolute
)overflow
属性所在的元素同时也是定位元素,里面的绝对定位元素会被剪裁(relative.overflow>absolute
)overflow
元素和绝对定位元素之间有定位元素,也会被剪裁(overflow>relative>absolute
)overflow
的属性值不是hidden
而是auto
或者scroll
,即使绝对定位元素高宽比overflow
元素高宽还要大,也都不会出现滚动条,也不跟着非绝对定位元素滚动(overflow>absolute
)position: fixed
固定定位元素的包含块是根元素,因此,除非是窗体滚动,否则上面讨论的所有overflow
剪裁规则对固定定位都不适用transform
除了改变overflow
属性原有规则,对层叠上下文以及position: fixed
的渲染都有影响。因此,当遇到absolute
元素被剪裁或者fixed
固定定位失效时,可以看看是不是transform
属性在作祟clip
属性要想起作用,元素必须是绝对定位或者固定定位,也就是position
属性值必须是absolute
或者fixed
clip: rect(top, right, bottom, left)
或clip: rect(top right bottom left)
position: fixed
元素,就要用到clip
属性了<h1>
中的网站标题可以h1 { position: absolute; clip: rect(0 0 0 0); }
,就可以不用text-indent
之类的隐藏了clip
进行剪裁的元素其clientWidth
和clientHeight
包括样式计算的宽高都还是原来的大小clip
隐藏仅仅是决定了哪部分是可见的,非可见部分无法响应点击事件等absolute
遇到left/top/right/bottom
属性的时候,absolute
元素才真正变成绝对定位元素.box { position: absolute; left: 0; right: 0; top: 0; bottom: 0; margin: 30px; }
height
百分比值可以生效了)margin
负值可以让元素的尺寸更大margin: auto
的填充规则和普通流体元素的一模一样:auto
,auto
为剩余空间大小auto
,则平分剩余空间margin: auto
的自动分配特性实现居中.element { width: 300px; height: 200px; position: absolute; left: 0; right: 0; top: 0; bottom: 0; margin: auto; }
relative 相对定位
relative/absolute/fixed
都能对absolute
的“包裹性”以及“定位”产生限制,但只有relative
可以让元素依然保持在正常的文档流中relative
的定位有两大特性:一是相对自身;二是无侵入relative
进行定位偏移的时候,一般情况下不会影响周围元素的布局(margin
偏移后面的元素会跟着移动,而使用relative
定位后面的元素依然在原地纹丝不动,自身原本区域留出了一大块空白)left/top/right/bottom
的百分比值是相对于包含块计算的,而不是自身(top
和bottom
这两个垂直方向的百分比值计算跟height
的百分比值是一样的,都是相对高度计算的,如果包含块的高度是auto
,那么计算值是 0)top/bottom
和left/right
同时使用的时候,只有一个方向的定位属性会起作用,与文档流的顺序有关的,默认的文档流是自上而下、从左往右,因此top/bottom
同时使用的时候,top
生效;left/right
同时使用的时候,left
生效relative
的最小化影响原则relative
,如果想定位某些元素,看看能否使用“无依赖的绝对定位”relative
,则该relative
务必最小化(relative
尽量不要包裹到其他元素)fixed 固定定位
position: fixed
固定定位元素的“包含块”是根元素,我们可以将其近似看成<html>
元素position: fixed
蒙层之所以出现背景依然滚动,那是因为滚动元素是根元素,正好是position: fixed
的“包含块”。所以,如果希望背景被锁定,让页面滚动条由内部的普通元素产生即可移动端项目,阻止
touchmove
事件的默认行为可以防止滚动;如果是桌面端项目,可以让根元素直接overflow: hidden
,并且使用同等宽度的透明边框填充消失的滚动条在蒙层显示的同时执行下面的 JavaScript 代码
隐藏的时候执行下面的 JavaScript 代码
CSS 中的层叠规则
“层叠规则”,指的是当网页中的元素发生层叠时的表现规则
层叠上下文
层叠上下文,英文称作 stacking context,是 HTML 中的一个三维的概念
如果一个元素含有层叠上下文,我们可以理解为这个元素在 z 轴上就“高人一等”
层叠水平
层叠水平,英文称作 stacking level,决定了同一个层叠上下文中元素在 z 轴上的显示顺序
所有的元素都有层叠水平,包括层叠上下文元素,也包括普通元素
然而,对普通元素的层叠水平探讨只局限在当前层叠上下文元素中
某些情况下
z-index
确实可以影响层叠水平,但是只限于定位元素以及flex
盒子的孩子元素;而层叠水平所有的元素都存在元素的层叠顺序
层叠顺序,英文称作 stacking order,表示元素发生层叠时有着特定的垂直显示顺序。
CSS 2.1 下,层叠顺序规则如下图所示:
(1)位于最下面的
background/border
特指层叠上下文元素的边框和背景色。每一个层叠顺序规则仅适用于当前层叠上下文元素的小世界。(2)
inline
水平盒子指的是包括inline/inline-block/inline-table
元素的“层叠顺序”,它们都是同等级别的。(3)单纯从层叠水平上看,实际上
z-index: 0
和z-index: auto
是可以看成是一样的。background/border
为装饰属性,浮动和块状元素一般用作布局,而内联元素都是内容两条层叠领域的黄金准则
(1)谁大谁上:当具有明显的层叠水平标识的时候,如生效的
z-index
属性值,在同一个层叠上下文领域,层叠水平值大的那一个覆盖小的那一个。(2)后来居上:当元素的层叠水平一致、层叠顺序相同的时候,在 DOM 流中处于后面的元素会覆盖前面的元素。
层叠上下文的特性
层叠上下文的创建
1、根层叠上下文
根层叠上下文指的是页面根元素,可以看成是元素。因此,页面中所有的元素一定处于至少一个“层叠结界”中。
2、定位元素与传统层叠上下文
对于
position
值为relative/absolute
以及 Firefox/IE 浏览器(不包括 Chrome 浏览 器)下含有position: fixed
声明的定位元素,当其z-index
值不是auto
的时候,会创建层叠上下文。3、CSS3 与新时代的层叠上下文
(1)元素为
flex
布局元素(父元素display: flex|inline-flex
),同时z-index
值不是auto
(2)元素的opacity
值不是 1 (3)元素的transform
值不是none
(4)元素mix-blend-mode
值不是normal
(5)元素的filter
值不是none
(6)元素的isolation
值是isolate
(7)元素的will-change
属性值为上面 2~6 的任意一个(如will-change: opacity
、will-change: transform
等) (8)元素的-webkit-overflow-scrolling
设为touch
层叠上下文与层叠顺序
(1)如果层叠上下文元素不依赖
z-index
数值,则其层叠顺序是z-index: auto
,可看成z-index: 0
级别;(2)如果层叠上下文元素依赖
z-index
数值,则其层叠顺序由z-index
值决定。元素一旦成为定位元素,其
z-index
就会自动生效,此时其z-index
就是默认的auto
,也就是 0 级别,根据上面的层叠顺序表,就会覆盖inline
或block
或float
元素而不支持
z-index
的层叠上下文元素天然是z-index: auto
级别,也就意味着,层叠上下文元素和定位元素是 一个层叠顺序的,于是当它们发生层叠的时候,遵循的是“后来居上”准则从图中可以看到
z-index
负值元素的层级是在层叠上下文元素上面、block
元素的下面,也就是z-index
虽然名为负数层级,但依然无法突破当前层叠上下文所包裹的小世界文本
字号 font-size
内联元素默认基线对齐,图片的基线可以看成是图片的下边缘,文字内容的基线是字符 x 下边缘
因此想让一个图片图标和文字对齐,可以设置图片的
vertical-align
的值为文字的行高 * -25%
或.6ex
之前有说
1ex
指的是字符x
的高度,而1em
指的是一个子模的高度('M')在 CSS 中,
1em
的计算值等同于当前元素所在的font-size
计算值,可以将其想象成当前元素中(如果有)汉字的高度font-size
的关键词属性font-size
计算larger
:大一点,是元素的默认 font-size 属性值smaller
:小一点,是元素的默认 font-size 属性值xx-large
:好大好大,和<h1>
元素计算值一样x-large
:好大,和<h2>
元素计算值一样large
:大,和<h3>
元素计算值近似(“近似”指计算值偏差在 1 像素以内,下同)medium
:不上不下,是 font-size 的初始值,和<h4>
元素计算值一样small
:小,和<h5>
元素计算值近似x-small
:好小,和<h6>
元素计算值近似xx-small
:好小好小,无对应的 HTML 元素桌面 Chrome 浏览器下有个
12px
的字号限制,如果font-size: 0
的字号表现就是 0,那么文字会直接被隐藏掉,并且只能是font-size: 0
,哪怕设置成font-size: 0.0000001px
,都还是会被当作12px
处理的字体属性家族 font
font-family 字体家族
font-family
默认值由操作系统和浏览器共同决定font-family
支持两类属性值,一类是“字体名”,一类是“字体族”,如果字体名包含空格,需要使用引号包起来(可以不用区分大小写;如果有多个字体设定,从左往右依次寻找本地是否有对应的字体即可)字体族分类:
serif
:衬线字体(笔画开始、结束的地方有额外 装饰而且笔画的粗细会有所不同的字体,典型字体是“宋体”)sans-serif
:无衬线字体(没有这些额外的装饰,而且笔画的粗细差不多,黑体)monospace
:等宽字体cursive
:手写字体fantasy
:奇幻字体system-ui
:系统 UI 字体。serif
和sans-serif
一定要写在最后,因为在大多数浏览器下,写在serif
和sans-serif
后面的所有字体都会被忽略等宽字体一般用于展示代码、一些字符
1ch
表示一个 0 字符的宽度,所以 6 个 0 所占据的宽度就是6ch
,用这个单位和等宽字体可以实现数字/字母一个个出现的效果font-weight 字重
这些数值关键字浏览器都是支持的,之所以没有看到任何粗细的变化,是因为我们的系统里面缺乏对应粗细的字体
font-weight
要想真正发挥潜力,问题不在于 CSS 的支持,而在于是否存在对应的字体文件font-style 倾斜
italic
是使用当前字体的斜体字体,而oblique
只是单纯地让文字倾斜如果当前字体没有对应的斜体字体,则退而求其次,解析为
oblique
,也就是单纯形状倾斜font 属性
可以缩写在
font
属性中的属性非常多,包括font-style
、font-variant
、font-weight
、font-size
、line-height
、font-family
等完整语法为:
font-size
和font-family
是必需的,是不可以省略的font
还支持关键字属性值,使用关键字作为属性值的时候必须是独立的,只能使用一下值如果将
font
属性设置为上面的一个值,就等同于设置font
为操作系统该部件对应的font
,也就是说直接使用系统字体caption
:活动窗口标题栏使用的字体icon
:包含图标内容所使用的字体,如所有文件夹名称、文件名称、磁盘名称,甚至 浏览器窗口标题所使用的字体menu
:菜单使用的字体,如文件夹菜单message-box
:消息盒里面使用的字体small-caption
:调色板标题所使用的字体status-bar
:窗体状态栏使用的字体@font-face 规则
@font-face
本质上就是一个定 义字体或字体集的变量,这个变量不仅仅是简单地自定义字体,还包括字体重命名、默认字体样式设置等@font-face
规则支持的 CSS 属性有font-family
、src
、font-style
、font-weigh
、unicode-range
、font-variant
、font-stretch
和font-feature-settings
,例如:src
可以给多种字体格式,因为不同系统兼容性不同,我们可以优先使用 woff2,然后是 woff 格式字体文本的控制
text-indent 文本缩进
text-indent
的百分比值是相对于当前元素的“包含块”计算的,而不是当前元素letter-spacing 字符间距
默认值是
normal
,计算值还是 0,支持负值word-spacing 单词间距
letter-spacing
作用于所有字符,但word-spacing
仅作用于空格字符word-break 和 word-wrap
word-break
属性,语法如下:normal
:使用默认的换行规则break-all
:允许任意非 CJK(Chinese/Japanese/Korean)文本间的单词断行keep-all
:不允许 CJK 文本中的单词换行,只能在半角空格或连字符处换行。非 CJK 文本的行为实际上和normal
一致。word-wrap
normal
:就是大家平常见得最多的正常的换行规则break-word
:一行单词中实在没有其他靠谱的换行点的时候换行word-break: break-all
和word-wrap: break-word
效果区别word-break: break-all
的作用是所有的都换行,毫不留情,一点儿空隙都不放过word-wrap: break-word
则带有怜悯之心,如果这一行文字有可以换行的点,如空格或 CJK(中文/日文/韩文)之类的,就不打英文单词或字符的主意了,在这些换行点换行,至于对不对齐、好不好看则不关心,因此,很容易出现一片一片空白区域的情况。white-space
white-space
属性声明了如何处理元素内的空白字符,这类空白字符包括 Space(空格) 键、Enter(回车)键、Tab(制表符)键产生的空白normal
:合并空白字符和换行符pre
:空白字符不合并,并且内容只在有换行符的地方换行nowrap
:该值和 normal 一样会合并空白字符,但不允许文本环绕pre-wrap
:空白字符不合并,并且内容只在有换行符的地方换行,同时允许文本环绕pre-line
:合并空白字符,但只在有换行符的地方换行,允许文本环绕white-space 的功能分 3 个维度,分别是:是否合并空白字符,是否合并换行符,以及文本是否自动换行
当
white-space
设置为nowrap
的时候,元素的宽度此时表现为“最大可用宽度”,换行符和一些空格全部合并,文本一行显示inline-block
元素 都具有包裹性,当文本内容宽度超过包含块宽度的时候,就会发生文本环绕现象text-overflow: ellipsis
文字内容超出打点效果离不开white-space: nowrap
声明text-align 对齐
text-align: justify
两端对齐,除了实现文本的两端对齐,还可以实现容错性更强的两端对齐布局效果在默认设置下,
text-align: justify
要想有两端对齐的效果,需要满足两点:一是有分隔点,如空格;二是要超过一行,此时非最后一行内容会两端对齐所以可以把子元素设置为
inline-block
,在容器上设置伪元素且设置内敛快宽度撑满text-decoration
text-decoration
属性用于设置或删除文本装饰,装饰线是一条横穿文本基线的线text-decoration
属性支持的属性值有none
、underline
、overline
、line-through
、blink
,其中blink
已经被废弃下划线可能会和文字重叠,所以一般用
border-bottom
模拟下划线text-transform 字符大小写
text-transform
也是为英文字符设计的,要么全大写text-transform: uppercase
, 要么全小写text-transform: lowercase
::first-letter/::first-line 伪元素
::first-letter
首字符作为元素的假想子元素::first-letter
伪元素生效的前提display
计算值必须是block
、inline-block
、list-item
、table- cell
或者table-caption
::first-letter
伪元素存在的,常见的标点符号、各类括号和引号在::first-letter
伪元素眼中全部都是“辅助类”字符,要是只有这些内容那就选中不到,如果以这些字符开头,后面有其他的文字内容(数字、英文字母、中文、$、一些运算符以及空格),那么会选择第一个字符和之前的符号inline-block/inline-table
之类的元素存在::before
伪元素,且伪元素的是数字、英文字母、中文、$、一些运算符或空格,那么::first-letter
会选中伪元素中的第一个字符::first-letter
选中的元素,仅部分 CSS 属性可以支持margin
相关属性、所有padding
相关属性、所有border
相关属性、color
属性、text-decoration
、text-transform
、letter-spacing
、word-spacing
(合 适情境下)、line-height
、float
和vertical-align
(只有当float
为none
的时候)等属性支持,其他类似visibility
、display: none
都不支持::first-line
和::first-letter
伪元素一样,只能作用在块级元素上,也就是display
为block
、inline-block
、list-item
、table-cell
或者table-caption
的元素设置::first-line
才有效,table
、flex
之类都是无效的::first-line
和::first-letter
伪元素一样,仅支持部分 CSS 属性color
属性、所有背景相关属性、text-decoration
、text-transform
、letter-spacing
、word-spacing
、line-height
和vertical-align
等属性颜色和背景色
color
red
、green
、blue
、purple
等transparent
currentColor
变量:使用当前color
计算值/颜色值,border
、text-shadow
、box-shadow
颜色默认值就是这个rgb()
和rgba()
,都支持四个参数,rgb()
的第四个参数可以省略,rgb()
可以使用百分比,但是要么是百分比,要么全是整数#000
、#fefefe
、#00000011
hsl()
和hsla()
background
当我们使用
background
属性的时候,实际上使用的是一系列background
相关属性的集合,包括:background-image: none
background-position: 0% 0%
background-repeat: repeat
background-attachment: scroll
background-size: auto auto
background-origin: padding-box
background-clip: border-box
background-position
属性值可以是具体数值,也可以是百分比值,还可以是
left
、top
、right
、center
和bottom
等关键字(CSS 中几乎带position
的都是这样)如果缺省偏移关键字,则会认为是
center
,因此background-position:top center
可以直接写成background-position:top
还支持同时出现 3 个值或 4 个值,作用是指定定位的偏移计算从哪个方位算起
background-position: right 40px bottom 20px;
表示距离右边缘 40 像素,距离底边缘 20 像素也支持百分比值,
positionX = (容器的宽度 - 图片的宽度) * percentX;
、positionY = (容器的高度 - 图片的高度) * percentY;
background-repeat
background-repeat
支持repeat
、repeat-x
、repeat-y
这几个值其中
repeat
是默认值,表示在水平和垂直方向都重复,repeat-x
表示在水平方向重复,repeat-y
表示在垂直方向重复background-attachment
支持
scroll
和fixed
两个属性值其中
scroll
是默认值,背景图片会跟着页面滚动fixed
表示背景相对于当前文档视区定位,也就是页面再怎么滚动背景图片位置依旧纹丝不动background-color
background-color
背景色永远是最低的(无论是单背景图还是多背景图,背景色一定是在最底下的位置)设置了背景色的元素,在激活状态(
:active
/:hover
)的时候,可以使用背景图片设置渐变,这样最底部还是原来的背景色,而渐变色是在背景色上层元素的显示与隐藏
使用 CSS 让元素不可见的方法很多,剪裁、定位到屏幕外、明度变化等都是可以的
如果希望元素不可见,同时不占据空间,辅助设备无法访问,同时不渲染,可以使用
<script>
标签隐藏此时,图片 1.jpg 是不会有请求的
<script>
标签是不支持嵌套的,因此,如果希望在<script>
标签中再放置其他不渲染的模板内容,可以试试使用<textarea>
元素图片 2.jpg 也是不会有请求的,
<script>
标签隐藏内容获取使用script.innerHTML
,<textarea>
使用textarea.value
如果希望元素不可见,同时不占据空间,辅助设备无法访问,但资源有加载,DOM 可访问,则可以直接使用
display: none
隐藏display
计算值是none
则该元素以及所有后代元素都隐藏Chrome 和 Safari 浏览器,若父元素
display: none
,图片不加载,若本身背景图所在元素隐藏,则图片依旧会去加载HTML 中有很多标签和属性天然
display: none
,如<style>
、<script>
和<dialog>
元素,如果这些标签在<body>
元素中,那么设置display: block
可以让标签内的内容显示在页面中(设置contenteditable = "true"
可以实时编辑预览)有的属性也是自带
display: none
的,例如<input type="hidden" name="id" value="1">
、<div hidden>None</div>
(如果不放心可以在 CSS 加一条[hidden]{ display: none }
)display: none
显隐控制并不会影响 CSS3animation
动画的实现,但是会影响 CSS3transition
过渡效果执行(因此transition
一般搭配visibility
和opacity
使用)对于计数器列表元素,如果设置
display:none
,则该元素不加入计数队列(例如原来 10 个有序列表,将第 2 个设置了display: none
,那么这个元素会消失,且第 3 个会变成 2,总计数是 9)如果希望元素不可见,同时不占据空间,辅助设备无法访问,但显隐的时候可以有
transition
淡入淡出效果,则可以使用visibility
如果希望元素不可见,不能点击,辅助设备无法访问,但占据空间保留,则可以使用
visibility:hidden
隐藏父元素设置
visibility:hidden
,子元素也会看不见,究其原因是继承性,子元素继承了visibility:hidden
,但是,如果子元素设置了visibility:visible
,则子元素又会显示出来visibility:hidden
不会影响计数器的计数,这和display:none
完全不一样如果希望元素不可见,不能点击,不占据空间,但键盘可访问,则可以使用
clip
剪裁隐藏如果希望元素不可见,不能点击,但占据空间,且键盘可访问,则可以试试
relative
隐藏。例如,如果条件允许,也就是和层叠上下文之间存在设置了背景色的父元素,则也可以使用更友好的z-index
负值隐藏如果希望元素不可见,但可以点击,而且不占据空间,则可以使用透明度
如果单纯希望元素看不见,但位置保留,依然可以点可以选,则直接让透明度为 0
轮廓和光标
outline 轮廓
outline
表示元素的轮廓,语法和border
属性非常类似,分宽度、类型和颜色,支持的关键字和属性值与border
属性一模一样表单按钮
focus
的时候会显示轮廓,按 Tab 可以聚焦到下一个元素,按 Enter 相当于鼠标点击(不要把全局的轮廓都去掉,只去掉需要的就可以)outline
是一个真正意义上不占任何空间的属性cursor 光标
常规
cursor: auto
:cursor
默认值,光标形状根据内容类别浏览器自动进行处理cursor: default
:系统默认光标形状cursor: none
:让光标隐藏不见,看视频的时候,尤其全屏看视频的时候可以用这个(如果鼠标静止 3 秒不动,就设置页面或视频元素cursor: none
隐藏光标,如果有mousemove
行为,再显示即可)链接和状态
cursor: pointer
:光标表现为一只伸出食指的手,一般是出现在可以点击交互的元素上cursor: help
:帮助,通常是光标头上带了个问号,用在帮助链接 或者包含提示信息的问号小图标上cursor: progress
:表示进行中的意思,适合 loading 处理(点击一个按钮发送请求,请求发送出去、返回数据还没接收到的这段时间就可以用这个;页面加载中也可以用,body { cursor: progress }
,当 JavaScript 初始化完毕的时候执行document.body.style.cursor = 'auto'
)cursor: wait
,计算机死机时的光标,一般不用cursor: context-menu
,菜单列表、下拉列表都可以用选择
cursor: text
,文字可被选中,默认文本字符或者可输入的单复选框的光标就表现成这样,因为文字可以被选中cursor: vertical-text
,文字可以垂直选中,使用writing-mode
把文字排版从水平改为垂直的时候,文字的光标就自动表现为cursor: vertical-text
cursor: crosshair
,十字光标,通常用在像素级的框选或点选场合, 比方说自定义的取色工具cursor: cell
,单元格使用拖曳
cursor: move
,当前元素是可以移动的cursor: copy
,当前元素是可以被复制的cursor: alias
,当前元素是可以创建别名或者快捷方式的cursor: no-drop
,当前元素放开到当前位置是不允许的cursor: not-allowed
,当前行为是禁止的滚动
cursor: all-scroll
:表示上下左右都可以滚动拉伸
cursor: col-resize
,适用于移动垂直线条,如垂直参考线、移动改变左右分栏的宽度cursor: row-resize
,适用于移动水平线条缩放
cursor: zoom-in
,可以放大cursor: zoom-out
,可以缩小抓取
cursor: grab
,展开的手cursor: grabbing
,握紧的手除了自带的还可以自定义光标:
改变流向
direction
通过属性
direction
改变文档流的水平方向direction
属性默认有这么一个特性,即可以改变替换元素或者inline-block/ inline-table
元素的水平呈现顺序HTML 中可以改变顺序
按钮的顺序就可以通过这个改变
文字省略也可以用这个改变到前面去
direction
属性还可以轻松改变表格中列的呈现顺序(左边的单元格到右边)directionL:rtl
还可以让text-justify
两端对齐元素,最后一行落单的元素右对齐只要是内联元素,只要与书写流相关,都可以试试
direction
属性unicode-bidi
搭配
unicode-bidi
可以改变文字的方向writing-mode
writing-mode
原本是为控制内联元素的显示而设计的(即所谓的垂直文本布局),用来实现文字竖向呈现writing-mode
将页面默认的水平流改成了垂直流margin
合并margin: auto
实现居中text-align: center
也能让图片在垂直方向上居中了text-indent
可以实现文字下沉效果