css 基础

HTML 的一些重要概念

堆叠上下文

概念

堆叠上下文是 HTML 元素的三维概念,这些 HTML 元素在一条假想的相对于面向(电脑屏幕的)视窗或者网页的用户的 z 轴上延伸,HTML 元素依据其自身属性按照优先级顺序占用层叠上下文的空间。

简单来说,为了让 HTML 元素在网页上绘制时有个前后的顺序(z 轴),这时就要产生堆叠上下文来进行比较元素在 z 轴的位置。

创建堆叠上下文的元素
  • 根元素();
  • z-index 值不为 auto 且 position 值为 relative 或 absolute 的元素;
  • z-index 值不为 auto 的 flex 项(父元素为 flex 布局);
  • position 值为 fixed 或 sticky 的元素;
  • opacity 值小于 1 的元素;
  • transform、filter、perspective、clip-path 属性中任意一个不为 none 的元素;
  • will-change 值设定了任一属性而该属性在 non-initial 值时会创建层叠上下文的元素。

在层叠上下文中,子元素同样也按照上面解释的规则进行层叠。重要的是,其子级层叠上下文的 z-index 值是相对父级来说的。

堆叠水平

堆叠水平决定了同一个堆叠上下文中元素在 z 轴上的显示顺序,所有的元素都有堆叠水平,包括堆叠上下文元素。

层叠上下文的层级是 HTML 元素层级的一个子级,没有创建自己的层叠上下文的元素会被父层叠上下文同化

每个堆叠上下文独立于其它堆叠上下文,它们之间不能相互穿插,每个堆叠上下文都有自己的排列方式。
如果一个堆叠上下文元素的堆叠级别比另一个堆叠上下文元素的高,那么该堆叠上下文元素的子元素的堆叠级别也比另一个堆叠上下文元素的子元素高。

在 z 轴上从后往前堆叠的元素依次是:

  1. 层叠上下文根元素;

  2. position 不为 static/flex 布局子项 且 z-index 值小于 0 的元素

  3. 块级元素

  4. 浮动元素

  5. 行内元素

  6. position 不为 static/flex 布局子项 且 z-index 值为 auto/0 的元素

  7. position 不为 static/flex 布局子项 且 z-index 值大于 0 的元素

opacity 非 1 的元素、transform(filter 等)非 none 的元素它们的层级在上面的 6。


BFC

概念

BFC 全称是 Block Formatting Context,意思是块级格式化上下文。你可以把BFC看做一个容器,容器里边的元素不会影响到容器外部的元素。

特性
  1. BFC 是一个块级元素,其子元素在垂直方向上依次排列;

  2. BFC 是一个独立的容器,内部元素不会影响容器外部的元素;

  3. 属于同一个 BFC 的两个盒子,外边距 margin 会发生重叠,并且取最大外边距;

  4. BFC 的区域不会与 float box 重叠。

创建 BFC
  • float 的值不是 none;
  • position 的值为 absolute 或者 fixed;
  • display 的值是 inline-block、table-cell、flex、table-caption 或者 inline-flex;
  • overflow 的值不是 visible。
作用
避免 margin 重叠
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<html>
<body>
<div class="box1"></div>
<div class="box2"></div>
</body>

<style>
.box1, .box2 {
width: 200px;
height: 200px;
margin: 30px;
}
.box1 {
background-color: burlywood;
}
.box2 {
background-color: #000;
}
</style>
</html>

在浏览器中可以看到,box1 的下外边距与 box2 的上外边距重叠了。这时我们可以利用 BFC 容器内部元素不影响外部元素这条特性,将 box2 包裹在一个 BFC 容器内就可以了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<html>
<body>
<div class="box1"></div>
<div style="overflow: hidden;">
<div class="box2"></div>
</div>
</body>

<style>
.box1, .box2 {
width: 200px;
height: 200px;
margin: 30px;
}
.box1 {
background-color: burlywood;
}
.box2 {
background-color: #000;
}
</style>
</html>
清除浮动

让父元素成为一个 BFC即可。


回流与重绘

回流

当增加或删除 dom 节点,或者给元素修改宽高时,会改变页面布局,那么就会重新构造 dom 树然后再次进行渲染,这就是回流。

重绘

简单来说就是重新绘画,当给一个元素更换颜色、更换背景,虽然不会影响页面布局,但是颜色或背景变了,就会重新渲染页面,这就是重绘。

二者关系
  • 重绘不会引起 dom 结构和页面布局的变化,只是样式的变化,有重绘不一定有回流。
  • 回流则是会引起 dom 结构和页面布局的变化,有回流就一定有重绘。
性能优化
  1. 避免设置大量的 style 内联属性,通过设置 style 属性改变结点样式,每次设置都会触发 reflow,应使用 class 添加样式;

  2. 不要使用 table 布局,因为 table 中某个元素触发了 reflow,所有 table 元素都会触发 reflow;

  3. display:none 会造成重排;可以用 visibility:hidden 代替;

  4. 避免使用 css 表达式。


CSS 属性

从背景图片中截取一段小图

在制作网页的时候如果要使用一幅图的某一部分的时候,可以用css里有一个非常有用的功能:background-position。

如下图:

YaQmE8.jpg

当我们要使用其中的某一个小图片来作为超链接的按钮的时候,就可以使用background-position来实现。

工作原理

背景图片默认放置在div的左上角,通过background-position可以改变图片的位置。

background-position有两个参数,第一个参数是将图片从div的左上角向左移动多少尺寸,第二个参数是将图片向上移动多少尺寸。

例如选取上图中第二幅小图 ,小图的宽度为20px 高度为25px 则:

1
2
3
4
5
6
7
<style>
div {
width:20px;
height:25px;
background:url(image.png)no-reapte 0 25px;
}
</style>

消除a标签的默认留白间距

设置font-size: 0

1
2
3
4
<div class="demo">
<a href="#">底部链接1</a>
<a href="#">底部链接2</a>
</div>
1
2
3
4
5
6
.demo{
font-size: 0;
}
.demo a{
font-size: 14px;/*这里一定要设置,不然文本内容将不显示*/
}

如果是图片链接的话,则不需要设置.demo a


通过链接定位页面中的元素

通常情况下,将网站的导航放在左侧的栏中,有时用来定位页面中的元素。

想链接到同一个Web页面中的多个不同部分时,可以使用锚点来命名。如果想创建一个指向另一个Web页面中的某个特定部分的链接,可在目标页面的文件名和锚点名称之间用一个#分隔。

1、在被定位元素中添加id="fruit"属性,在导航链接中定义href="#fruit",便可以定位到id为fruit的div块。

2、要指向另一个Web页面中的某个特定部分,定义导航链接为href="index#fruit"


内部元素超出外部元素定义的范围

box-sizing属性:允许您以特定的方式定义匹配某个区域的特定元素。

1
box-sizing: content-box|border-box|inherit;
描述
content-box 这是由 CSS2.1 规定的宽度高度行为。宽度和高度分别应用到元素的内容框。在宽度和高度之外绘制元素的内边距和边框。
border-box 为元素设定的宽度和高度决定了元素的边框盒。就是说,为元素指定的任何内边距和边框都将在已设定的宽度和高度内进行绘制。通过从已设定的宽度和高度分别减去边框和内边距才能得到内容的宽度和高度。
inherit 规定应从父元素继承 box-sizing 属性的值。

可以通过将box-sizing: border-box把框内元素限制在框内。


隐藏浏览器滚动条

1
2
3
body::-webkit-scrollbar {
width: 0;
}

transition 同时指定多个属性过渡

1
transition: color 0.25s ease-in, border-color 0.25s ease-in;

防止图片溢出

1
2
3
img {
max-with: 100%
}

让元素的宽度自适应内容的宽度

让元素(div p 等)根据字数的变化自动变宽,且元素始终紧紧包裹着内容。可以通过将元素 display 设置为 table 即可:

1
display: table

选择相同元素的第 n 个元素

:nth-child(n) 选择器匹配属于其父元素的第 N 个子元素,不论元素的类型。n 可以是数字、关键词或公式。

下面我们来举例说明:

1
2
3
4
5
6
p:nth-child(1) // 匹配第一个 p 元素
p:nth-child(n) // 匹配每一个 p 元素
p:nth-child(n+4) // 匹配第 56,... 个 p 元素
p:nth-child(3n) // 匹配第 369,... 个 p 元素
p:nth-child(3n+1) // 匹配第 4710,... 个 p 元素
...

另外还有 :first-child 选择第一个元素;:last-child 选择最后一个元素;:nth-last-child(n) 选择倒数第 n 个元素。

一般我们在列表中会用到这个属性来消除边界元素的 margin。


object-fit

object-fit 属性指定元素的内容应该如何去适应指定容器的高度与宽度。常用于 imgvideo 标签。

  1. fill:不保证保持原有的比例,内容全部显示铺满容器。
  2. contain:保持原有尺寸比例,使图片的宽度完整的显示,高度自动缩放。
  3. cover:保持原有尺寸比例。高度铺满容器,宽度等比缩放,超出部分被剪掉。
  4. none:图片原有宽高不变,超出部分被剪掉,保留下来的内容使图片的正中央。

去除移动端点击时元素产生的背景色

1
-webkit-tap-highlight-color: transparent;

阻止选中文本

1
-webkit-user-select: none;

white-space

white-space 属性用于指定如何处理容器中的空白字符,例如:空格( )、换行(\n)、缩进(\t)等。

  • normal:忽略掉文本中多余的空格和回车符。
  • nowrap:忽略掉文本中多余的空格和回车符,并且文本在一行中显示。
  • pre:不忽略文本中多余的空格和回车符。但是文本只在回车符处进行换行,如果没有回车符,文本将会在一行中显示。
  • pre-wrap:不忽略空格和回车符,同时文本自动允许换行。
  • pre-line:忽略多余的空格,但不忽略回车符。
  • initial:继承父级属性。

word-spacing

设置单词之间的间距。


letter-spacing

设置字母之间的间距。


float 清除浮动

在父容器没有规定高度时,子容器设置了 float,那么子容器不能撑开父容器的高度。

解决方法:

(1)给父容器设置一个高度。

(2)通过伪元素清除浮动(推荐)。

1
2
3
4
5
6
7
8
9
10
.parent:after {
content: "";
display: block;
clear: both;
}
.children {
width: 100px;
height: 100px;
float: left;
}

(3)给父容器也设置 float。

(4)给父容器设置overflow: hidden/auto,触发其BFC。


自定义滚动条样式

  • ::-webkit-scrollbar 滚动条整体部分;
  • ::-webkit-scrollbar-thumb  滚动条里面的小方块,能向上向下移动(或往左往右移动,取决于是垂直滚动条还是水平滚动条);
  • ::-webkit-scrollbar-track  滚动条的轨道(里面装有Thumb);
  • ::-webkit-scrollbar-track-piece 内层轨道,滚动条没有滑块的轨道部分;
  • ::-webkit-scrollbar-button 滚动条的轨道的两端按钮,允许通过点击微调小方块的位置;
  • ::-webkit-scrollbar-corner 边角,即两个滚动条的交汇处;
  • ::-webkit-resizer 两个滚动条的交汇处上用于通过拖动调整元素大小的小控件。

::webkit-scrollbar 仅仅在支持 webkit 引擎的浏览器中生效(chrome、edge、safari)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
::-webkit-scrollbar {
width: 10px;
}
::-webkit-scrollbar-track {
border-radius: 5px;
background-color: rgb(200, 200, 200);
}
::-webkit-scrollbar-thumb {
border-radius: 5px;
background-color: #1095c1;
}
::-webkit-scrollbar-thumb:hover {
background-color: #000000;
}

box-shadow 阴影

语法
1
box-shadow: h-shadow v-shadow blur spread color inset;
  • h-shadow:水平方向阴影的偏移量;

  • v-shadow:垂直方向阴影的偏移量;

  • blur:阴影模糊半径;

  • spread:阴影扩展半径,其值可以为负,如果值为正,则整个阴影都延展扩大,反之则缩小;

  • color:阴影颜色;、

  • inset:如果不设值,其默认的投影方式是外阴影,如果取其唯一值 “inset”,就是将外阴影变成内阴影。

四边阴影

实现四边阴影只需将 h-shadow 和 v-shadow 设为 0 即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<html>
<body>
<div class="box"></div>
</body>

<style>
.box {
width: 200px;
height: 200px;
border: 1px solid rgba(0, 0, 0, 0.1);
border-radius: 5px;
box-shadow: 0 0 12px 0 rgb(240, 240, 240);
}
</style>
</html>
单(二、三)边阴影

实现三边阴影的原理是:将待实现阴影的元素包裹在一个 div 中,为该 div 设置 padding: 0 20px 20px 20px(没有阴影的一边 padding 为 0)和 overflow: hidden,这样 padding 为 0 的一边的阴影会因为超出父元素而被隐藏。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<html>
<body>
<div class="container">
<div class="box"></div>
</div>
</body>

<style>
.container {
width: 200px;
height: 200px;
padding: 0 20px 20px 20px;
overflow: hidden;
}
.box {
width: 100%;
height: 100%;
border: 1px solid rgba(0, 0, 0, 0.1);
border-radius: 5px;
box-shadow: 0 0 12px 0 rgb(240, 240, 240);
}
</style>
</html>

实现一边二边阴影只需改变父元素的 padding 即可。


css 文本超出隐藏并显示省略号

  • 使用 overflow:hidden; 把超出的部分隐藏

  • 使用 text-overflow:ellipsis; 将文本对象溢出时显示为省略号

超出一行隐藏并显示省略号:

1
2
3
overflow: hidden;
white-space: nowrap; // 使文本不换行
text-overflow: ellipsis;

超出两行或多行隐藏并显示省略号:

1
2
3
4
5
overflow: hidden;
text-overflow: ellipsis;
-webkit-line-clamp: 2;
display: -webkit-box;
-webkit-box-orient: vertical;
line-clamp

设置截断内容前的最大行数,然后在最后一行的末尾显示省略号。

它只有在 display 属性设置成 -webkit-box 或者 -webkit-inline-box 并且 -webkit-box-orient (en-US) 属性设置成 vertical时才会生效。


backdrop-filter

与 filter 属性用法一样,区别是该属性允许我们使用 css 对元素后面的内容应用过滤效果。
因为它适用于元素背后的所有元素,为了看到效果,必须使元素或其背景至少部分透明。

  • blur():模糊程度,单位 px;
  • brightness():亮度,值为 1 无变化;
  • contrast():对比度,值为 1 无变化;
  • drop-shadow():投影,语法与 box-shadow 相似(没有 spread 属性), 它作用于元素中的像素,可以让任意非透明的图形区域产生投影效果;
  • grayscale():灰度,值为 0 无变化,值为 1 完全转为灰度图;
  • hue-rotate():色调变化,单位 deg;
  • invert():反相,值为 0 无变化,值为 1 完全反相;
  • opacity():透明度,值为 0 完全透明;
  • saturate():饱和度,值为 1 无变化。

注意:火狐浏览器不支持。


inline/inline-block 高度问题

问题描述

用一个 div 包裹一个 img,然后设置 img 的高度,此时 div 的高度会被撑开,但是其高度会比 img 的高度多 3px 或 4px。

问题分析

这是因为 img 是行内块元素,它在块元素中默认有 3px 或者 4px 的空白(其实就是和文本的基线对齐不管有没有文本)。

解决方法
1
2
3
img {
display: block;
}

flex 布局不触发 overflow 的问题

现在有一个三段式布局:header、main、footer,固定 header 和 footer 的高度,通过 flex 使 main 自动撑开,当 main 中的内容超出时发生滚动,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<div class="container">
<header></header>
<main>
<div v-for="_ in 100">xxx</div>
</main>
<footer></footer>
</div>

<style>
.container {
display: flex;
flex-direction: column;
height: 100vh;
}
header, footer {
height: 50px;
}
main {
flex: 1;
overflow: auto;
}
</style>

会发现 main 并没有发生滚动,而是 container 发生了滚动。
然后我们在触发滚动的元素即列表外面再加一层 div,并同样设置 flex 为 1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<div class="container">
<header></header>
<main>
<div class="list-container">
<div v-for="_ in 100">xxx</div>
</div>
</main>
<footer></footer>
</div>

<style>
.container {
display: flex;
flex-direction: column;
height: 100vh;
}
header, footer {
height: 50px;
}
main {
flex: 1;
overflow: auto;
display: flex;
flex-direction: column;
}
.list-container {
flex: 1;
}
</style>

main 还是没有发生滚动。
此时只需为 main 元素添加 height: 0 即可。
如果不用 flex 布局,直接计算 main 的高度即可:

1
2
3
main {
height: calc(100vh - 50px - 50px);
}