HMTL + CSS
1. DIV+CSS布局的好处
- 代码精简,且结构与样式分离,易于维护
- 代码量减少,减少了大量的带宽,页面加载更快,提升了用户的体验
- 对SEO搜索引擎更加友好,H5新增了许多语义化标签
- 允许更多炫酷的页面效果,丰富了页面
- 符合W3C标准,保证网站不会因为网络应用的升级而被淘汰
缺点: 不同浏览器对web标准默认值不同,所以更容易出现对浏览器的兼容性问题。
2. HTML 标签语义化
2.1 HTML语义化背景介绍
HTML结构语义化,是最近几年才提出来的,以前的html结构,一打开就是一堆div+css,为了改变这种这种状况,开发者们和官方提出了让HTML结构语义化的概念,并且官方也在HTML5中给出了几个新的语义化标签。
2.2 什么是语义化,语义化之后文档会有什么效果
-
语义化,就是你写的HTML结构,是用相对应的有一定语义的标签表示的,因为HTML本身就是标记语言。不仅对自己来说,容易阅读,书写。别人看你的代码和结构也容易理解,甚至对一些不是做网页开发的人来说,也容易阅读。那么在开发的过程中,尽量使用官方有语义的标签,不要使用一堆无意义的标签去堆砌结构。
-
怎么知道自己的页面结构是否语义化,那就要看你的HTML结构,在去掉CSS样式表之后,是否依然能很好的呈现内容的结构,代码结构。也就是说,脱掉css的外衣,依然头是头,脚是脚。赤裸裸的完整的一篇文档。这也就是,语义化之后文档的效果。
-
其实语义化,也无非就是自己在使用标签的时候多使用有英文语义的标签,比如h标签,在HTML就是用来定义标题,还有p标签表示段落,table表格标签等等。
2.3 为什么要语义化
-
为了在没有CSS的情况下,页面也能呈现出很好地内容结构、代码结构
-
用户体验:例如title、alt用于解释名词或解释图片信息的标签尽量填写有含义的词语、label标签的活用
-
有利于SEO:和搜索引擎建立良好沟通,有助于爬虫抓取更多的有效信息:爬虫依赖于标签来确定上下文和各个关键字的权重
-
方便其他设备解析如屏幕阅读器、盲人阅读器、移动设备,以有意义的方式来渲染网页
-
便于团队开发和维护,语义化更具可读性,遵循W3C标准的团队都遵循这个标准,可以减少差异化
2.4 写 HTML 代码时,应该注意什么
-
尽可能少的使用无语义的标签div和span
-
在语义不明显时,既可以使用div或者p时,尽量用p,因为p在默认情况下有上下间距,对兼容特殊终端有利
-
不要使用纯样式标签,如:b、font、u等,改用css设置
-
需要强调的文本,可以包含在strong或em标签中,strong默认样式是加粗(不要用b),em是斜体(不要用i)。
<b>
是为了加粗而加粗,<strong>
是加强,表示该文本比较重要,提示终端,为了达到这个目的,浏览器等终端会将其加粗。 -
使用表格时,标题要用caption,表头用thead,主体部分用tbody包围,尾部用tfoot包围。表头和一般单元格要区分开,表头用th,单元格用td
-
表单域要用 fieldset 标签包起来,并用 legend 标签说明表单的用途
-
每个input标签对应的说明文本都需要使用label标签,并且通过为input设置id属性,在lable标签中设置for=someld来让说明文本和相对应的input关联起来
-
不仅写 html 结构时,要用语义化标签,给元素写css类名时,也要遵循语义化原则,不要随便起个名字就用,那样等以后,再重构时,非常难读。最忌讳的是不会英文,用汉语拼音代替。
2.5 HTML5新增了哪些语义化标签
header,footer,nav,aside,article,video,audio,canvas
3. 行内元素/块级元素有哪些
行内元素:相邻的行内元素会排列在同一行,不会独占一行设置宽高无效: a br I em img input select span sub sup u textarea
块级元素:会独占一行 可以设置宽高等属性: div h1-h6 hr p ul ol table address blockquote dir from menu
可变元素:根据上下文预警决定该元素为块元素还是内联元素块级元素:button del iframe ins
4. CSS选择器及优先级
!important
- 内联样式(1000)
- ID选择器(0100)
- 类选择器/属性选择器/伪类选择器(0010)
- 标签选择器/伪元素选择器(0001)
- 关系选择器/通配符选择器(0000)
5. 浏览器怎么解析 CSS 选择器
CSS选择器的读取顺序是从右向左。
.mod-nav h3 span {font-size: 16px;}
读取顺序变成:先找到所有的span,沿着span的父元素查找h3,中途找到了符合匹配规则的节点就加入结果集;如果直到根元素html都没有匹配,则不再遍历这条路径,从下一个span开始重复这个过程(如果有多个最右节点为span的话)。
6. link和@import的区别
-
从属关系
- link:link是HTML提供的标签,不仅可以加载CSS,还可以定义rel等属性
- @import:@import是css提供的语法,只有导入样式表的作用
-
加载顺序
- link:link在页面加载时CSS同时被加载
- @import:引入的CSS要等页面加载完毕后再加载
-
兼容性问题
- link是HTML提供的语法,不存在兼容性问题
- @import是css2.1提供的语法,ie5以上才兼容
-
DOM可控性
- js控制DOM时,可以通过插入link标签来改变样式,不能通过@import改变
建议使用link,慎用@import
CSS 文字超出部分以省略号结尾
文字只有一行时
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
指定多行文字
overflow: hidden;
/* 将对象作为弹性伸缩盒子模型显示; */
display: -webkit-box;
/* 溢出部分用省略号代替 *//* autoprefixer: off */
text-overflow: ellipsis;
/* 设置文本显示两行 */
-webkit-line-clamp: 2;
/* 从上到下排列子元素; */
-webkit-box-orient: vertical;
7. BFC
7.1 什么是BFC
BFC 全称为块级格式化上下文 (Block Formatting Context) 。BFC是 W3C CSS 2.1 规范中的一个概念,它决定了元素如何对其内容进行定位以及与其他元素的关系和相互作用,当涉及到可视化布局的时候,Block Formatting Context提供了一个环境,HTML元素在这个环境中按照一定规则进行布局。一个环境中的元素不会影响到其它环境中的布局。比如浮动元素会形成BFC,浮动元素内部子元素的主要受该浮动元素影响,两个浮动元素之间是互不影响的。有点类似一个BFC就是一个独立的行政单位的意思。可以说BFC就是一个作用范围,把它理解成是一个独立的容器,并且这个容器里box的布局与这个容器外的box毫不相干。
7.2 BFC触发的条件有哪些
- 根元素或其它包含它的元素
- 浮动元素 (元素的
float
不是none
) - 绝对定位元素 (元素具有
position
为absolute
或fixed
) - 弹性盒(
flex
或inline-flex
) - 内联块 (元素具有
display: inline-block
) - 表格单元格 (元素具有
display: table-cell
) - 表格标题 (元素具有
display: table-caption
) - 具有
overflow
且值不是visible
的块元素
7.3 BFC的布局规则
-
内部的盒会在垂直方向一个接一个排列(可以看作BFC中有一个的常规流)
-
处于同一个BFC中的元素相互影响,可能会发生外边距重叠
-
每个元素的margin box的左边,与容器块border box的左边相接触(对于从左往右的格式化,否则相反),即使存在浮动也是如此
-
BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素,反之亦然
-
计算BFC的高度时,考虑BFC所包含的所有元素,连浮动元素也参与计算
-
浮动盒区域不叠加到BFC上
7.4 BFC可以解决的问题
- 防止margin重叠
- 清除内部浮动
- 自适用两列布局(
float
+overflow
) - 防止字体环绕
7.5 代码实例演示
<style>
div {
width: 100px;
height: 100px;
background-color: aqua;
margin: 100px;
}
</style>
<body>
<div></div>
<div></div>
</body>
<!--
因为两个 div 元素都处于同一个 BFC 容器下 (这里指 body 元素) 所以第一个 div 的下边距和第二个 div 的上边距发生了重叠,所以两个盒子之间距离只有 100px,而不是 200px。
-->
<style>
.container {
overflow: hidden;
}
p {
width: 100px;
height: 100px;
background: aqua;
margin: 100px;
}
</style>
<div class="container">
<p></p>
</div>
<div class="container">
<p></p>
</div>
<!--
如果想要避免外边距的重叠,可以将其放在不同的 BFC 容器中。
-->
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sVr6UML0-1633482194973)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210410200423783.png)]
<div style="border: 1px solid #000;">
<div style="width: 100px;height: 100px;background: #eee;float: left;"></div>
</div>
<!--
由于容器内元素浮动,脱离了文档流,所以容器只剩下 2px 的边距高度。
-->
<div style="border: 1px solid #000;overflow: hidden;">
<div style="width: 100px;height: 100px;background: #eee;float: left;"></div>
</div>
<!--
如果使触发容器的 BFC,那么容器将会包裹着浮动元素。
-->
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sSIo5fmC-1633482194976)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210410200626846.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4ru6NQhq-1633482194978)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210410200718428.png)]
<div style="height: 100px;width: 100px;float: left;background: lightblue">我是一个左浮动的元素</div>
<div style="width: 200px; height: 200px;background: #eee">我是一个没有设置浮动,
也没有触发 BFC 元素, width: 200px; height:200px; background: #eee;</div>
<!--
第二个元素有部分被浮动元素所覆盖,(但是文本信息不会被浮动元素所覆盖) 如果想避免元素被覆盖,可触第二个元素的 BFC 特性,在第二个元素中加入 overflow: hidden,
-->
<div style="height: 100px;width: 100px;float: left;background: lightblue">我是一个左浮动的元素</div>
<div style="width: 200px; height: 200px;background: #eee; overflow: hidden;;">我是一个没有设置浮动,
也没有触发 BFC 元素, width: 200px; height:200px; background: #eee;</div>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eRfrwgJf-1633482194980)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20210410200847925.png)]
8. 盒模型
包括内容区域、内边距区域、边框区域和外边距区域。
box-sizing: content-box
(W3C盒子模型):元素的宽高大小表现为内容的大小。
box-sizing: border-box
(IE盒子模型):元素的宽高表现为内容 + 内边距 + 边框的大小。背景会延伸到边框的外沿。
IE5.x 和 IE6在怪异模式中使用非标准的盒子模型,这些浏览器的width
属性不是内容的宽度,而是内容、内边距和边框的宽度的总和。
9. 如何实现左列定宽,右列自适应
DOM结构
<div class="box">
<div class="box-left"></div>
<div class="box-right"></div>
</div>
9.1 利用float + margin
实现
.box {
height: 200px;
}
.box > div {
height: 100%;
}
.box-left {
width: 200px;
background-color: blue;
float: left;
}
.box-right {
margin-left: 200px;
background-color: red;
}
9.2 利用calc
计算宽度
.box {
height: 200px;
}
.box > div {
height: 100%;
}
.box-left {
width: 200px;
background-color: blue;
float: left;
}
.box-right {
background-color: red;
width: calc(100% - 200px);
float: right;
}
9.3 利用float + overflow
实现
.box {
height: 200px;
}
.box > div {
height: 100%;
}
.box-left {
width: 200px;
float: left;
background-color: blue;
}
.box-right {
overflow: hidden;
background-color: red;
}
9.4 利用flex
实现
.box {
height: 200px;
display: flex;
}
.box > div {
height: 100%;
}
.box-left {
width: 200px;
background-color: blue;
}
.box-right {
flex-grow: 1;
overflow: hidden;
background-color: red;
}
10. 实现居中
10.1 水平居中
父元素是块级元素,子元素是行内元素,给其父元素设置text-align:center
.father {
width: 200px;
height: 200px;
background-color: antiquewhite;
text-align: center;
}
.son {
width: 50%;
height: 50%;
background-color: aqua;
}
<div class="father">
<span class="son">son</span>
</div>
子元素是块级元素,该元素设置margin:0 auto
。或父元素为 flex
布局,子元素设置margin:0 auto
.son {
margin: 0 auto;
}
<div class="son">son</div>
使用 flex 布局,设置父元素的 justify-content: center
.father {
display: flex;
justify-content: center;
}
使用绝对定位和CSS3新增的属性 transform
.father {
position: relative;
}
.son {
position: absolute;
left: 50%;
transform: translate(-50%, 0);
}
使用绝对定位和 margin-left
(元素定宽)
.father {
position: relative;
}
.son {
width: 100px;
position: absolute;
left: 50%;
margin-left: -50px;
}
**子元素不定宽度时,设置 display 为 inline-block,父元素设置 text-align: center **
.father {
width: 200px;
height: 200px;
background-color: antiquewhite;
text-align: center;
}
.son {
background-color: aqua;
display: inline-block;
}
<div class="father">
<span class="son">son</span>
</div>
10.2 垂直居中
若元素是单行文本, 可设置line-height
等于父元素高度
.son {
line-height: 200px;
}
<span class="son">box-center</span>
若是块级元素,设置父元素为flex布局,子元素设置margin: auto 0
即可(子元素不需要定宽)
.box {
display: flex;
}
.box-center {
margin: auto 0;
}
<div class="box-center">box-center</div>
多行的行内元素
.father {
width: 200px;
height: 200px;
line-height: 200px;
background-color: aquamarine;
}
.son {
display: inline-block;
line-height: 1em;
vertical-align: middle;
}
<div class="father">
<span class="son">
这里是高度为150像素的标签内的多行文字,文字大小
</span>
</div>
Flex 布局
.father {
display: flex;
align-items: center;
}
可用 transform
,设置父元素相对定位
.box {
position: relative;
}
.box-center {
position: absolute;
top: 50%;
transform: translate(0, -50%);
}
居中元素高度固定 :position: absolute + margin
.box {
position: relative;
}
.box-center {
height: 100px;
position: absolute;
top: 50%;
margin-top: -50px;
}
.box {
position: relative;
}
.box-center {
height: 100px;
position: absolute;
top: 0;
bottom: 0;
margin: auto 0;
}
10.3 水平垂直居中
前提:定宽高
.box {
width: 200px;
height: 200px;
border: 1px solid red;
position: relative;
}
.children-box {
width: 100px;
height: 100px;
background: yellow;
}
1. 绝对定位和负magin值
position: absolute;
left: 50%;
top: 50%;
margin-left: -50px;
margin-top: -50px;
2. 绝对定位 + transform
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
3. 绝对定位 + left/right/bottom/top + margin
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: auto;
4. 父元素设置 flex 布局
display: flex;
justify-content: center;
align-items: center;
5. grid布局
display: grid;
//
margin: auto;
6. table-cell + vertical-align + inline-block/margin: auto
display: table-cell;
text-align: center;
vertical-align: middle;
//
margin: auto;
前提:不定宽高
1. 绝对定位 + transform
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
2. table-cell
display: table-cell;
text-align: center;
vertical-align: middle;
//
display: inline-block;
3. flex布局
display: flex;
justify-content: center;
align-items: center;
4. flex布局
display: flex;
//
margin: auto;
5. grid + flex布局
display: grid;
//
align-self: center;
justify-self: center;
6. gird + margin布局
display: grid;
//
margin: auto;
11. 伪类和伪元素的区别
伪类用于当已有元素处于的某个状态时,为其添加对应的样式,这个状态是根据用户行为而动态变化的。比如说,当用户悬停在指定的元素时,我们可以通过:hover来描述这个元素的状态。虽然它和普通的css类相似,可以为已有的元素添加样式,但是它只有处于dom树无法描述的状态下才能为元素添加样式,所以将其称为伪类。
伪元素用于创建一些不在文档树中的元素,并为其添加样式。比如说,我们可以通过:before来在一个元素前增加一些文本,并为这些文本添加样式。虽然用户可以看到这些文本,但是这些文本实际上不在文档树中。
11.1 区别
伪类的操作对象是文档树中已有的元素,而伪元素则创建了一个文档树外的元素。因此,伪类与伪元素的区别在于:有没有创建一个文档树之外的元素。
CSS3规范中的要求使用双冒号(::)表示伪元素,以此来区分伪元素和伪类,比如::before和::after等伪元素使用双冒号(:😃,:hover和:active等伪类使用单冒号(😃。除了一些低于IE8版本的浏览器外,大部分浏览器都支持伪元素的双冒号(::)表示方法。
12. 定位 position
static
默认值。位置设置为static的元素,它始终会处于文档流给予的位置
inherit
规定应该从父元素继承 position 属性的值,IE 无法支持。
fixed
生成固定定位。默认情况下,可定位于相对于浏览器窗口的指定坐标。元素的位置通过 left
, top
, right
,bottom
属性进行规定。不论窗口滚动与否,元素都会留在那个位置。但当祖先元素具有transform
属性且不为none
时,就会相对于祖先元素指定坐标,而不是浏览器窗口。
absolute
生成绝对定位。相对于距该元素最近的已定位的父元素进行定位。此元素的位置可通过 left
, top
, right
,bottom
属性来规定。一旦给元素加上absolute
或float
就相当于给元素加上了display:block
。absolute
元素覆盖正常文档流内元素(不用设z-index,自然覆盖)。可以减少重绘和回流的开销(如absolute + top:-9999em
,或absolute + visibility:hidden
,将动画效果放到absolute
元素中)
relative
生成相对定位。相对于该元素在文档中的初始位置进行定位。通过 left
、top
、right
, bottom
属性来设置此元素相对于自身位置的偏移。
sticky
粘性定位可以被认为是相对定位和固定定位的混合。元素在跨越特定阈值前为相对定位,之后为固定定位。须指定 top
, right
, bottom
,left
四个阈值其中之一,才可使粘性定位生效。否则其行为与相对定位相同。
#one {
position: sticky;
top: 10px;
}
在 viewport 视口滚动到元素 top 距离小于 10px 之前,元素为相对定位。之后,元素将固定在与顶部距离 10px 的位置,直到 viewport 视口回滚到阈值以下。
浮动、绝对定位和固定定位会脱离文档流,相对定位不会脱离文档流,绝对定位相对于该元素最近的已定位的祖先元素,如果没有一个祖先元素设置定位,那么参照物是body层。
-
绝对定位相对于包含块的起始位置:
- 如果祖先元素是块级元素,包含块则设置为该元素的内边距边界。
- 如果祖先元素是行内元素,包含块则设置为该祖先元素的内容边界。
-
定位元素的起始位置为父包含块的内边距(不会在border里,除非使用负值,会在padding里)
-
定位元素的margin还是能起作用的
-
background属性是会显示在border里的
-
z-index是有层叠层级的,需要考虑同一个层叠上下文的层叠优先级
-
z-index是负值不会覆盖包含块的背景色(但是如果有内容,会被包含块的内容覆盖)
-
z-index的值影响的元素是定位元素以及flex盒子
-
上面一个定位元素,下面一个正常流的元素,定位元素会覆盖在正常流元素之上,除非给z-index是负值
-
页面根元素html天生具有层叠上下文,称之为“根层叠上下文”
13. 前端 SEO 优化
13.1 什么是 SEO
SEO,即搜索引擎优化。SEO是随着搜索引擎的出现而来的,两者是相互促进,互利共生的关系。SEO的存在就是为了提升网页在搜索引擎自然搜索结果中的收录数量以及排序位置而做的优化行为。而优化的目的就是为了提升网站在搜索引擎中的权重,增加对搜索引擎的友好度,使得用户在访问网站时能排在前面。
分类:白帽SEO和黑帽SEO。白帽SEO,起到了改良和规范网站设计的作用,使网站对搜索引擎和用户更加友好,并且网站也能从搜索引擎中获取合理的流量,这是搜索引擎鼓励和支持的。黑帽SEO,利用和放大搜索引擎政策缺陷来获取更多用户的访问量,这类行为大多是欺骗搜索引擎,一般搜索引擎公司是不支持与鼓励的。
13.2 前端 SEO 规范
- 网站结构布局优化:尽量简单、开门见山,提倡扁平化结构。一般中小型网站目录结构超过三级,“蜘蛛”便不愿意往下爬了
- 控制首页链接数量
- 扁平化的目录层次
- 导航优化
- 注意网站的结构布局
- 利用布局,把重要内容HTML代码放在最前,搜索引擎抓取HTML内容是从上到下
- 控制页面的大小,减少http请求,提高网站的加载速度
- 网页代码优化
- 突出重要内容—合理的设计title、description和keywords
- 语义化书写HTML代码,符合W3C标准
- 标签:页内链接,要加 “title” 属性加以说明,让访客和 “蜘蛛” 知道。而外部链接,链接到其他网站的,则需要加上 el=“nofollow” 属性, 告诉 “蜘蛛” 不要爬,因为一旦“蜘蛛”爬了外部链接之后,就不会再回来了。
- h标签的使用,h1标签只能出现一次,它是当前页面的主标题,对蜘蛛的吸引力是最强的。
- strong标签的使用,strong标签对关键词的强调作用仅次于h标签,用于加粗段落标题或是重点关键词。
< title >
网站SEO标题</ title >
、< meta name=“descriptiion” content=“网站描述”/>
和< meta name=“keywords” content=“网站关键词/”>
,这是SEO的重点。< a href=“链接地址” title=“链接说明”>链接关键词< /a>
,站内丰富的超链接会方便蜘蛛爬行,体现网站的深度和广度,这点在SEO中至关重要。< img src=“图片链接地址” alt=“图片说明”/>
,这是针对网页中图片的,当然也可以写成<img src="图片链接地址"title=“图片说明”/>
。< div id=“copyright”>版权部分加上网站名称和链接</ div>
。- 重要内容不要用JS输出,因为“蜘蛛”不会读取JS里的内容,所以重要内容必须放在HTML里。
- 尽量少使用iframe框架,因为“蜘蛛”一般不会读取其中的内容。
- 谨慎使用 display:none 。对于不想显示的文字内容,应当设置z-index或缩进设置成足够大的负数偏离出浏览器之外。因为搜索引擎会过滤掉display:none其中的内容。
14. 首屏和白屏时间如何计算?
15. Flex 布局
Flex 布局可以简便、完整、响应式地实现各种页面布局。Flex 意为"弹性布局",用来为盒状模型提供最大的灵活性。任何一个容器都可以指定为 Flex 布局。父元素设为Flex布局后,子元素的float、clear、vertical-align属性将失效。
15.1 Flex的兼容性
IE6~9
不支持,IE10~11
部分支持flex的2012版
,但是需要-ms-
前缀。其它的主流浏览器包括安卓和IOS
基本上都支持了。
15.2 基本概念
采用 Flex 布局的元素,称为 Flex 容器(flex container),简称"容器"。它的所有子元素自动成为容器成员,称为 Flex 项目(flex item),简称"项目"。
容器默认存在两根轴:水平的主轴(main axis)和垂直的交叉轴(cross axis)。
15.3 容器属性
flex-direction:决定主轴的方向(即项目的排列方向)
row
(默认值):主轴为水平方向,起点在左端row-reverse
:主轴为水平方向,起点在右端column
:主轴为垂直方向,起点在上沿column-reverse
:主轴为垂直方向,起点在下沿
flex-wrap:决定是否换行
- nowrap(默认):不换行
- wrap:换行,第一行在上方
- wrap-reverse:换行,第一行在下方
flex-flow:flex-direction
属性和flex-wrap
属性的简写形式
- 默认值为
row nowrap
justify-content:定义了项目在主轴上的对齐方式
flex-start
(默认值):左对齐flex-end
:右对齐center
: 居中space-between
:两端对齐,项目之间的间隔都相等space-around
:每个项目两侧的间隔相等。所以,项目之间的间隔比项目与边框的间隔大一倍
align-items:定义项目在交叉轴上如何对齐
flex-start
:交叉轴的起点对齐flex-end
:交叉轴的终点对齐center
:交叉轴的中点对齐baseline
: 项目的第一行文字的基线对齐stretch
(默认值):如果项目未设置高度或设为auto,将占满整个容器的高度
align-content:定义了多根轴线的对齐方式。如果项目只有一根轴线,该属性不起作用
flex-start
:与交叉轴的起点对齐flex-end
:与交叉轴的终点对齐center
:与交叉轴的中点对齐space-between
:与交叉轴两端对齐,轴线之间的间隔平均分布space-around
:每根轴线两侧的间隔都相等。所以,轴线之间的间隔比轴线与边框的间隔大一倍stretch
(默认值):轴线占满整个交叉轴
15.4 项目属性
order:定义项目的排列顺序。数值越小,排列越靠前,默认为0
flex-grow:定义项目的放大比例,默认为0
,即如果存在剩余空间,也不放大
flex-shrink:定义了项目的缩小比例,默认为1,即如果空间不足,该项目将缩小
flex-basis:定义了在分配多余空间之前,项目占据的主轴空间(main size)。浏览器根据这个属性,计算主轴是否有多余空间。它的默认值为auto
,即项目的本来大小。
flex
:flex-grow
, flex-shrink
和 flex-basis
的简写,默认值为0 1 auto
。后两个属性可选。
align-self:允许单个项目有与其他项目不一样的对齐方式
16. 实现三栏布局
16.1 左右加浮动,中间不动
<style>
.layout.float .left {
float: left;
width: 300px;
background: red;
}
.layout.float .right {
float: right;
width: 300px;
background: blue;
}
.layout.float .center {
background: yellow;
}
</style>
<section class="layout float">
<article class="left-center-right">
<div class="left"></div>
<div class="right"></div>
<div class="center">
<h1>浮动解决方案</h1>
<p>1.这是布局的中间部分</p>
<p>2.这是布局的中间部分</p>
</div>
</article>
</section>
16.2 绝对定位,div 全部浮动,左边距离设为0,中间设 300,最右边那个右边设0
<style>
.layout.absolute .left-center-right>div {
position: absolute;
}
.layout.absolute .left {
left: 0;
width: 300px;
background: red;
}
.layout.absolute .center {
left: 300px;
right: 300px;
background: yellow;
}
.layout.absolute .right {
right: 0;
width: 300px;
background: blue;
}
</style>
<section class="layout absolute">
<article class="left-center-right">
<div class="left"></div>
<div class="center">
<h1>绝对定位的解决方案</h1>
<p>1.这是布局的中间部分</p>
<p>2.这是布局的中间部分</p>
</div>
<div class="right"></div>
</article>
</section>
16.3 flexbox布局 父元素设置 flex,左右元素设置宽高,中间设置 flex: 1
<style>
.layout.flexbox .left-center-right {
display: flex;
}
.layout.flexbox .left {
width: 300px;
background: red;
}
.layout.flexbox .center {
flex: 1;
background: yellow;
}
.layout.flexbox .right {
width: 300px;
background: blue;
}
</style>
<section class="layout flexbox">
<article class="left-center-right">
<div class="left"></div>
<div class="center">
<h1>flexbox的解决方案</h1>
<p>1.这是布局的中间部分</p>
<p>2.这是布局的中间部分</p>
</div>
<div class="right"></div>
</article>
</section>
16.4 父元素设置表格属性,div 设置 table-cell,子元素左右设置宽高即可
<style>
.layout.table .left-center-right {
width: 100%;
display: table;
height: 100px;
}
.layout.table .left-center-right>div {
display: table-cell;
}
.layout.table .left {
width: 300px;
background: red;
}
.layout.table .center {
background: yellow;
}
.layout.table .right {
width: 300px;
background: blue;
}
</style>
<section class="layout table">
<article class="left-center-right">
<div class="left"></div>
<div class="center">
<h1>表格布局的解决方案</h1>
<p>1.这是布局的中间部分</p>
<p>2.这是布局的中间部分</p>
</div>
<div class="right"></div>
</article>
</section>
16.5 网格布局,父元素设置 grid
<style>
.layout.grid .left-center-right {
display: grid;
width: 100%;
grid-template-rows: 100px;
grid-template-columns: 300px auto 300px;
}
.layout.grid .left {
background: red;
}
.layout.grid .center {
background: yellow;
}
.layout.grid .right {
background: blue;
}
</style>
<section class="layout grid">
<article class="left-center-right">
<div class="left"></div>
<div class="center">
<h1>网格布局的解决方案</h1>
<p>1.这是布局的中间部分</p>
<p>2.这是布局的中间部分</p>
</div>
<div class="right"></div>
</article>
</section>
17. 移动端布局
17.1 CSS 单位
em
:em是一个相对的度量单位,对于浏览器来说,1em=16px,16px为浏览器的默认字体大小。父级的字体大小为font-size: 2em
,即:32px。若此时,子元素的font-size: 2em
,即:64px。em单位为一个相对的度量单位,它通过寻找父标签的font-size
,然后通过计算得出自身的font-size
。rem
:根节点html
的font-size
决定了rem
的尺寸,也就是说它是一个相对单位,相对于html
。浏览器的默认的font-size
是16px,1rem默认就等于16px。%
:以父级的宽度为基准。如父级width: 200px
,则子级width:50%
为width:100px
vw和vh
:视口单位中的“视口”,桌面端指的是浏览器的可视区域,不包含任务栏标题栏以及底部工具栏的浏览器区域大小。1vw等于视口宽度的1%。1vh等于视口高度的1%。vmin和vmax
:vmin
为当前vw
和vh
中较小的一个值;vmax
为较大的一个值。例如视口宽度375px
,视口高度812px
,则100vmin = 375px
,100vmax = 812px
17.2 怎样初始化根元素的字体大小
页面开头动态计算 font-size
(1rem = 16px)
(function() {
// document.documentElement:获取document的根元素
var html = document.documentElement
function onWindowResize() {
// html.getBoundingClientRect().width:获取html的宽度(窗口的宽度)
html.style.fontSize = html.getBoundingClientRect().width / 16 + 'px'
}
// 监听window的resize事件
window.addEventListener('resize', onWindowResize)
onWindowResize()
})()
一般还会配置 meta 信息
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-sacle=1.0, maximum-scale=1.0, user-scalable=no">
17.3 移动端布局
- 移动端布局的方式主要使用rem和flex,可以结合各自的优点,比如flex布局很灵活,但是字体的大小不好控制,我们可以使用rem和媒体查询控制字体的大小,以及视口的大小,然后根据不同的视口大小设置html的font-size。
- 可单独制作移动端页面也可响应式pc端移动端共用一个页面。没有好坏,视情况而定,因势利导
17.4 移动端适配 1px 的问题
Retina 显示屏比普通的屏幕有着更高的分辨率,所以在移动端的 1px 边框就会看起来比较粗,为了美观通常需要把这个线条细化处理。
.box {
position: relative;
border:none;
}
.box::after {
content: '';
position: absolute;
left: 0;
bottom: 0;
background: #000;
width: 100%;
height: 1px;
transform: scaleY(0.5);
transform-origin: 0 0;
}
同时设置 4 条边框:
.box {
position: relative;
margin-bottom: 20px;
border:none;
}
.box::after {
content: '';
position: absolute;
top: 0;
left: 0;
border: 1px solid #000;
-webkit-box-sizing: border-box;
box-sizing: border-box;
width: 200%;
height: 200%;
-webkit-transform: scale(0.5);
transform: scale(0.5);
-webkit-transform-origin: left top;
transform-origin: left top;
}
18. 移动端适配方案
- 适配不同屏幕宽度以及不同dpr,通过动态设置viewport(scale=1/dpr) + 根元素fontSize + rem, 辅助使用vw/vh等来达到适合的显示
- 若无需适配可显示1px线条,也可以不动态设置scale,只使用动态设置根元素fontSize + rem + 理想视口
- 当视口缩放,计算所得的根元素fontSize也会跟着缩放,即若理想视口(scale=1), iPhone6根元素fontSize=16px; 若scale=0.5, iPhone6根元素fontSize=32px; 因此不必担心rem的计算
- css单位:全部用rem,包括字体大小,不用px
- px为单位的元素,需根据dpr有不同的大小,如大小12px, dpr=2则采用24px, 使用sass mixin简化写法
- 配合scss函数,简化px2rem转换,且易于维护(若需修改$base-font-size, 无需手动重新计算所有rem单位)
- px2rem函数的base-font-size只跟根元素fontSize的基准(此文中是【fontSize=16px when 375】)以及设计图的大小有关,按此基准,若设计图为iPhone6二倍稿,则base−font−size只跟根元素fontSize的基准(此文中是【fontSize=16px when 375】)以及设计图的大小有关,按此基准,若设计图为iPhone6二倍稿,则base-font-size=32px,参数传值直接为设计图标注尺寸
- 使用iPhone6(375pt)二倍设计图:宽度750px
- 切图使用三倍精度图,以适应三倍屏
19. 浮动
19.1 什么是浮动
浮动的框可以向左或向右移动,直到它的外边缘碰到包含框或另一个浮动框的边框为止。由于浮动框不在文档的普通流中,所以文档普通流中的块框表现得就像浮动框不存在一样。
19.2 为什么要清除浮动
浮动本质是用来做一些文字混排效果的,但是被拿来做布局用,则会有很多的问题出现。
浮动元素会脱离正常的文档流,并不会占据文档流的位置,所以如果一个父元素下面都是浮动元素,那么这个父元素就无法被浮动元素所撑开,这样一来父元素就丢失了高度,这就是所谓的浮动造成的父元素高度坍塌问题。父元素高度一旦坍塌将对后面的元素布局造成影响。
19.3 怎么清除浮动
19.3.1 使用带 clear 属性的空元素
利用清除可以设置元素禁止浮动元素出现在它的左侧、右侧甚至是双侧
.news {
background-color: gray;
border: solid 1px black;
}
.news img {
float: left;
}
.news p {
float: right;
}
.clear {
clear: both;
}
<div class="news">
<img src="news-pic.jpg" />
<p>some text</p>
<div class="clear"></div>
</div>
优点:简单,代码少,浏览器兼容性好
缺点:需要添加大量无语义的html元素,代码不够优雅,后期不容易维护
19.3.2 使用CSS的overflow属性
.news {
background-color: gray;
border: solid 1px black;
overflow: hidden;
}
.news img {
float: left;
}
.news p {
float: right;
}
<div class="news">
<img src="news-pic.jpg" />
<p>some text</p>
</div>
19.3.3 使用CSS的:after伪元素
.news {
background-color: gray;
border: solid 1px black;
}
.news img {
float: left;
}
.news p {
float: right;
}
.clear::after {
content: "020";
display: block;
height: 0;
clear: both;
visibility: hidden;
}
<div class="news">
<img src="news-pic.jpg" />
<p>some text</p>
<div class="clear"></div>
</div>
20. transform
Transform字面上就是变形,改变的意思。在CSS3中transform主要包括以下几种:旋转rotate、扭曲skew、缩放scale和移动translate以及矩阵变形matrix。
transform: rotate | scale | skew | translate |matrix;
21. CSS 动画
21.1 transition
样式应该设置在需要变化的 class 类名处。
img{
/* 指定状态变化所需要的时间 */
transition: 1s;
}
img{
/* 只适用于height, width 不变 */
transition: 1s height;
}
img{
/* 可以分别指定多个属性 */
transition: 1s height, 1s width;
}
img{
/* width在1秒之后,再开始变化,也就是延迟(delay)1秒 */
transition: 1s height, 1s 1s width;
}
img{
/*
linear:匀速
ease-in:加速
ease-out:减速
cubic-bezier函数:自定义速度模式
*/
transition: 1s ease;
}
transition的优点在于简单易用,但是它有几个很大的局限
- transition需要事件触发,所以没法在网页加载时自动发生
- transition是一次性的,不能重复发生,除非一再触发
- transition只能定义开始状态和结束状态,不能定义中间状态,也就是说只有两个状态
- 一条transition规则,只能定义一个属性的变化,不能涉及多个属性
21.2 Animation
/* 持续时间,动画名称 */
div:hover {
animation: 1s rainbow;
}
@keyframes rainbow {
0% { background: #c00; }
50% { background: orange; }
100% { background: yellowgreen; }
}
/* 加入infinite关键字,可以让动画无限次播放 */
div:hover {
animation: 1s rainbow infinite;
}
/* 指定动画具体播放的次数,比如3次 */
div:hover {
animation: 1s rainbow 3;
}
/* forwards表示让动画停留在结束状态 */
div:hover {
animation: 1s rainbow forwards;
}
22. 什么是GPU加速,如何使用GPU加速,GPU加速的缺点
GPU,又称显示核心、视觉处理器、显示芯片,是一种专门在个人电脑、工作站、游戏机和一些移动设备(如平板电脑、智能手机等)上图像运算工作的微处理器。GPU是专为执行复杂的数学和几何计算而设计的,这些计算是图形渲染所必需的。GPU 拥有一个由数以千计的更小、更高效的核心(专为同时处理多重任务而设计)组成的大规模并行计算架构。
- 优点:使用
transform
、opacity
、filters
等属性时,会直接在GPU中完成处理,这些属性的变化不会引起回流重绘 - 缺点:GPU渲染字体会导致字体模糊,过多的GPU处理会导致内存问题
23. CSS 动画和 JS 动画的区别
23.1 JS动画(逐帧动画)
js动画是逐帧动画,是在时间帧上逐帧绘制帧内容,由于是一帧一帧的话,所以可操作性很高,几乎可以完成任何动画形式。但是由于逐帧动画的帧序列内容不一样,会增加制作负担,且资源占有比较大。但它的优势也很明显:因为它相似与电影播放模式,很适合于表演很细腻的动画,如3D效果、人物或动物急剧转身等等效果。但是,如果帧率过低的话,帧与帧之间的过渡很可能会不自然、不连贯。
js是单线程的脚本语言,当js在浏览器主线程运行时,主线程还有其他需要运行的js脚本、样式、计算、布局、交互等一系列任务,对其干扰线程可能出现阻塞,造成丢帧的情况。
其次,js在做动画的时候,其复杂度是高于css3的,需要考虑一些计算,操作等问题。
但是正是由于js对动画的操作复杂度比较高,能对动画有一个比较好的控制,如开始、暂定、回放、终止、取帧等,可以很精确的做到。因此js可以通过操作DOM和BOM来做一些酷炫的动态效果及特效,且兼容性比较好。
23.2 CSS3(补间动画)
制作方法简单方便。只需确定第一帧和最后一帧的关键位置即可,两个关键帧之间的帧内容由合成线程自动生成,不需要人为处理。当然也可以多次添加关键帧的位置。
因为只设置几个关键帧的位置,所以在进行动画控制的时候是比较弱的。不能够在半路暂停动画,或者在动画过程中不能对其进行一些操作等。
css3在实现一些简单的滑动,翻转等特效的时候会很方便,但是想要做到一些酷炫的效果的时候,其操作往往可能会比js操作有更多的冗余。
css3在做动画的时候,浏览器可以对其进行一些优化,会比js使用更少的占用cpu资源。
23.3 结论
如果动画只是一些简单的状态切换,滑动等效果,不需要中间的控制过程,css3是比较好的选择,它直接在css文件中就可以实现,并不需要引入太多的js库。复杂的纹理动画,需要对页面进行精准的控制计算,js是不错的选择。
24. 图片格式
在大多数的web页面中,图片占到了页面大小的60%-70%。因此在web开发中,不同的场景使用合适的图片格式对web页面的性能和体验是很重要的。
24.1 图片格式分类
-
无压缩:无压缩的图片格式不对图片数据进行压缩处理,能准确地呈现原图片。BMP格式就是其中之一。
-
无损压缩:压缩算法对图片的所有的数据进行编码压缩,能在保证图片的质量的同时降低图片的尺寸。png是其中的代表。
-
有损压缩:压缩算法不会对图片所有的数据进行编码压缩,而是在压缩的时候,去除了人眼无法识别的图片细节。因此有损压缩可以在同等图片质量的情况下大幅降低图片的尺寸。其中的代表是jpg。
格式 | 优点 | 缺点 | 适用场景 |
---|---|---|---|
gif | 文件小,支持动画、透明,无兼容性问题 | 只支持256种颜色 | 色彩简单的logo、icon、动图 |
jpg | 色彩丰富,文件小 | 有损压缩,反复保存图片质量下降明显 | 色彩丰富的图片/渐变图像 |
png | 无损压缩,支持透明,简单图片尺寸小 | 不支持动画,色彩丰富的图片尺寸大 | logo/icon/透明图 |
webp | 文件小,支持有损和无损压缩,支持动画、透明 | 浏览器兼容性不好 | 支持webp格式的app和webview |
25. CSS 画圆半圆扇形三角梯形
div{
margin: 50px;
width: 100px;
height: 100px;
background: red;
}
/* 半圆 */
.half-circle{
height: 50px;
border-radius: 50px 50px 0 0;
}
/* 扇形 */
.sector{
border-radius: 100px 0 0;
}
/* 三角 */
.triangle{
width: 0px;
height: 0px;
background: none;
border: 50px solid red;
border-color: red transparent transparent transparent;
}
/* 梯形 */
.ladder{
width: 50px;
height: 0px;
background: none;
border: 50px solid red;
border-color: red transparent transparent transparent;
}
26. 圣杯布局和双飞翼布局
通俗的来说就是左右两栏固定宽度,中间部分自适应的三栏布局。
26.1 圣杯布局
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
right:0;
}
.header, .footer {
height: 100px;
line-height: 100px;
background-color: aquamarine;
text-align: center;
font-size: 30px;
font-weight: bolder;
}
.footer {
background-color: blueviolet;
}
.container {
/*
7. container设置padding: 0, rightWidth, 0, leftWidth
*/
padding: 0 220px 0 200px;
/*
2. 给container设置上overflow: hidden,可以形成BFC撑开文档
*/
overflow: hidden;
}
.left, .middle, .right {
/*
5. 给left、middle、right设置position: relative,不会遮挡middle的内容
*/
position: relative;
/*
1. 首先把left、middle、right都放出来,给它们三个设置上float: left, 脱离文档流
*/
float: left;
min-height: 130px;
word-break: break-all;
/*
8. 解决单独部分内容扩充的时候,底部会参差不齐。
*/
padding-bottom: 9999px;
margin-bottom: -9999px;
}
.left {
margin-left: -100%;
/*
6. left设置 left: -leftWidth
*/
left: -200px;
/*
3. left、right设置上各自的宽度
*/
width: 200px;
background-color: cadetblue;
}
.right {
margin-left: -220px;
/*
6. right设置 right: -rightWidth
*/
right: -220px;
/*
3. left、right设置上各自的宽度
*/
width: 220px;
background-color: coral;
}
.middle {
/*
4. middle设置width: 100%
*/
width: 100%;
background-color: darkkhaki;
}
</style>
</head>
<body>
<div class="header">header</div>
<div class="container">
<div class="middle">
<h4>middle</h4>
<p>
middlemiddlemiddlemiddlemiddlemiddlemiddlemiddle
middlemiddlemiddlemiddlemiddlemiddlemiddlemiddle
middlemiddlemiddlemiddlemiddlemiddlemiddlemiddle
middlemiddlemiddlemiddlemiddlemiddlemiddlemiddle
middlemiddlemiddlemiddlemiddlemiddlemiddlemiddle
middlemiddlemiddlemiddlemiddle
</p>
</div>
<div class="left">
<h4>left</h4>
<p>
leftleftleftleftleftleftleftleftleftleftleftleft
leftleftleftleftleftleftleftleftleftleftleftleft
leftleftleftleftleftleftleftleftleftleftleftleft
</p>
</div>
<div class="right">
<h4>right</h4>
<p>
rightrightrightrightrightrightrightrightrightright
rightrightrightrightrightrightrightrightrightright
rightrightrightrightrightrightright
</p>
</div>
</div>
<div class="footer">footer</div>
</body>
</html>
26.2 双飞翼布局
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
.header, .footer {
height: 100px;
line-height: 100px;
background-color: aquamarine;
text-align: center;
font-size: 30px;
font-weight: bolder;
}
.footer {
background-color: blueviolet;
}
.container {
/*
2. 给container设置上overflow: hidden; 可以形成BFC撑开文档
*/
overflow: hidden;
}
.left, .middle, .right {
/*
1. 首先把left、middle、right都放出来, middle中增加inner,给它们三个设置上float: left, 脱离文档流
*/
float: left;
min-height: 130px;
word-break: break-all;
/*
7. 解决单独部分内容扩充的时候,底部会参差不齐。
*/
padding-bottom: 9999px;
margin-bottom: -9999px;
}
.left {
/*
5. left设置 margin-left: -100%
*/
margin-left: -100%;
/*
3. left、right设置上各自的宽度
*/
width: 200px;
background-color: cadetblue;
}
.right {
/*
6. right设置 right: -rightWidth
*/
margin-left: -220px;
/*
3. left、right设置上各自的宽度
*/
width: 220px;
background-color: crimson;
}
.middle {
/*
4. middle设置width: 100%
*/
width: 100%;
height: 100%;
background-color: cornflowerblue;
}
.inner {
margin: 0 220px 0 200px;
min-height: 130px;
background-color: darkkhaki;
word-break: break-all;
}
</style>
</head>
<body>
<div class="header">header</div>
<div class="container">
<div class="middle">
<div class="inner">
<h4>middle</h4>
<p>
middlemiddlemiddlemiddlemiddlemiddlemiddlemiddle
middlemiddlemiddlemiddlemiddlemiddlemiddlemiddle
middlemiddlemiddlemiddlemiddlemiddlemiddlemiddle
middlemiddlemiddlemiddlemiddlemiddlemiddlemiddle
middlemiddlemiddlemiddlemiddlemiddlemiddlemiddle
middlemiddlemiddlemiddlemiddle
</p>
</div>
</div>
<div class="left">
<h4>left</h4>
<p>
leftleftleftleftleftleftleftleftleftleftleftleft
leftleftleftleftleftleftleftleftleftleftleftleft
leftleftleftleftleftleftleftleftleftleftleftleft
</p>
</div>
<div class="right">
<h4>right</h4>
<p>
rightrightrightrightrightrightrightrightrightright
rightrightrightrightrightrightrightrightrightright
rightrightrightrightrightrightright
</p>
</div>
</div>
<div class="footer">footer</div>
</body>
</html>
27. CSS 性能优化
- 合并css文件,如果页面加载10个css文件,每个文件1k,那么也要比只加载一个100k的css文件慢。
- 减少css嵌套,最好不要嵌套三层以上。
- 不要在ID选择器前面进行嵌套,ID本来就是唯一的而且权限值大,嵌套完全是浪费性能。
- 建立公共样式类,把相同样式提取出来作为公共类使用。
- 减少通配符*或者类似[hidden=“true”]这类选择器的使用,挨个查找所有…这性能能好吗?
- 巧妙运用css的继承机制,如果父节点定义了,子节点就无需定义。
- 拆分出公共css文件,对于比较大的项目可以将大部分页面的公共结构样式提取出来放到单独css文件里,这样一次下载 后就放到缓存里,当然这种做法会增加请求,具体做法应以实际情况而定。
- 不用css表达式,表达式只是让你的代码显得更加酷炫,但是对性能的浪费可能是超乎你想象的。
- 少用css rest,可能会觉得重置样式是规范,但是其实其中有很多操作是不必要不友好的,有需求有兴趣,可以选择normolize.css。
- cssSprite,合成所有icon图片,用宽高加上background-position的背景图方式显现icon图,这样很实用,减少了http请求。
- 善后工作,css压缩(在线压缩工具 YUI Compressor)
- GZIP压缩,是一种流行的文件压缩算法。
避免使用@import,外部的css文件中使用@import会使得页面在加载时增加额外的延迟。首先,使用@import引入css会影响浏览器的并行下载。使用@import引用的css文件只有在引用它的那个css文件被下载,解析之后,浏览器才会知道还有另外一个css需要下载,这时才去下载,然后下载后开始解析,构建render tree等一系列操作,这就导致浏览器无法并行下载所需的样式文件。其次,多个@import会导致下载顺序紊乱,在IE中,@import会引发资源文件的下载顺序被打乱,即排列在@import后面的js文件优先于@import下载,并且打乱甚至破坏@import自身的并行下载。所以不要使用这一方法,使用link标签就行了。
避免过分重排
- 浏览器为了重新渲染部分或整个页面,重新计算页面元素位置和几何结构的进程叫做reflow
- 浏览器根据定义好的样式来计算,并将元素放到该出现的位置上,这个过程叫做reflow
- 页面上任何一个节点触发来reflow,会导致他的子节点和祖先节点重新渲染
- 导致reflow发生的情况
- 改变窗口的大小
- 改变文字的大小
- 添加 删除样式表
- 内容的改变 输入框输入内容也会
- 伪类的激活
- 操作class属性
- 脚本操作dom js改变css类
- 计算offsetWidth和offsetHeight
- 设置style属性
10.改变元素的内外边距
- 常见重排元素
- 大小有关的 width,height,padding,margin,border-width,border,min-height
- 布局有关的 display,top,position,float,left,right,bottom
- 字体有关的 font-size,text-align,font-weight,font-family,line-height,white-space,vertical-align
- 隐藏有关的 overflow,overflow-x,overflow-y
- 减少reflow对性能的影响的建议
- 不要一条条的修改dom的样式,预先定义好class,然后修改dom的classname
- 不要修改影响范围较大的dom
- 为动画元素使用绝对定位
- 不要table布局,因为一个很小的改动会造成整个table重新布局
- 避免设置大量的style属性,通过设置style属性改变节点样式的话,每一次设置都会触发一次reflow,所以最好使用class属性
- 如果css里面有计算表达式,每次都会重新计算一遍,触发一次reflow
repaint
- 当一个元素的外观被改变,但是布局没有改变的情况
- 当元素改变的时候,不影响元素在页面中的位置,浏览器仅仅会用新的样式重绘此元素
- 常见的重绘元素
颜色 color,background
边框样式 border-style,outline-color,outline,outline-style,border-radius,box-shadow,outline-width
背景有关 background,backgound-image,background-position,background-repeat,background-size
CSS动画
- css动画启用GPU加速,应用GPU的图形性能对浏览器中的一些图形操作交给GPU完成。canvas2D,布局合成,css3转换,css3d变换,webGL,视频
- 2d加速
- 3d加速
文件压缩
性能优化时最容易想到的,也是最常见的方法,就是文件压缩,这一方案往往效果显著。文件的大小会直接影响浏览器的加载速度,这一点在网络较差时表现尤为明显,构建工具webpack,gulp/grunt,rollup,压缩之后能够明显减少,可以大大降低浏览器的加载时间。
去除无用CSS
虽然文件压缩能够降低文件大小,但css文件压缩通常只会去除无用的空格,这样就限制来css文件的压缩比例。如果压缩后的文件仍然超过来预期的大小,可以试着找到并删除代码中无用的css。
一般情况下,会存在这两种无用的CSS代码:
- 不同元素或者其他情况下的重复代码,
- 整个页面内没有生效的CSS代码
有选择地使用选择器
css选择器的匹配是从右向左进行的,这一策略导致来不同种类的选择器之间的性能也存在差异。相比于 #markdown-content-h3,显然使用 #markdown.content h3时,浏览器生成渲染树所要花费的时间更多。因为后者需要先找到DOM中的所有h3元素,再过滤掉祖先元素不是.content的,最后过滤掉.content不是#markdown的。试想,页面中的元素更多,那么匹配所要花费的时间代价自然更高。
显得浏览器在这一方面做了很多优化,不同选择器的性能差别并不明显,甚至可以说差别甚微,此外不同选择器在不同浏览器中的性能表现也不统一,在编写css的时候无法兼顾每种浏览器,鉴于这两点,在使用选择器时,尽量记住以下几点:
- 保持简单,不要使用嵌套过多过于复杂的选择器
- 通配符和属性选择器效率最低,需要匹配的元素最多,尽量避免使用。
- 不要使用类选择器和ID选择器修饰元素标签,如:h3#markdown-content,这一多此一举,还会降低效率
- 不要为了追求速度而放弃可读性和可维护性
TIPS:为什么css选择器是从右向左匹配的?
css中更多的选择器是不会匹配的,所以在考虑性能问题时,需要考虑的是如何在选择器不匹配时提升效率,从右向左匹配就是为了达成这一目的的,通过这一策略能够使得css选择器在不匹配的时候效率更高。
减少使用昂贵的属性
在浏览器绘制屏幕时,所有需要浏览器进行操作或计算的属性相对而言都需要花费更大的代价,而页面发生重绘时,它们会降低浏览器的渲染性能。所以在编写css时,应该尽量减少使用昂贵属性,如:
box-shadow, border-radius, filter, 透明度, :nth-child等
当然并不是不要使用这些属性,这些都是经常使用的属性,只是这里可以作为一个了解。当有其他方案可以选择的时候,可以优先选择没有昂贵属性或昂贵属性更少的方案,这一网站的性能会在不知不觉中得到一定的提升。
硬件加速的好坏
- 仅仅依靠GPU还是不行的,许多动画还是需要CPU的介入,连接cpu和GPU的总带宽不是无限的,所以需要注意数据在cpu和GPU之间的传输,尽量避免造成通道的拥挤,要一直注意像素的传输。
- 一个重点是了解创建的合成层的数量,每一个层都对应来一个GPU纹理,太多的层会消耗很多内存。
**chrome://flags/#composited-layer-borders**
观察的地址。- 每一个dom元素的合成层都会被标记一个额外的边框,这一就可以验证是否有了很多层
- 另一个重点是保持GPU和CPU之间传输量达到最小值,也就是说,层的更新数量最好是一个理想的常量,每次层更新的时候,一堆新的像素就可能需要传输给GPU。
- 因为为了高性能,动画开始之后避免层的更新也是非常重要的,避免动画进行中其他层一直更新导致拥堵。
- 也就是使用这些css属性来实现动画:transformation, opacity, filter
- 使用性能工具检测优化的合理性,timeline检测优化是否合理,还需要实现自动操作来做性能回归测试。
- 检测层数和层更新次数是非常有用的。
28. CSS可以继承的属性
1、字体系列属性
font:组合字体
font-family:规定元素的字体系列
font-weight:设置字体的粗细
font-size:设置字体的尺寸
font-style:定义字体的风格
font-variant:设置小型大写字母的字体显示文本,这意味着所有的小写字母均会被转换为大写,但是所有使用小型大写字体的字母与其余文本相比,其字体尺寸更小。
font-stretch:对当前的 font-family 进行伸缩变形。所有主流浏览器都不支持。
font-size-adjust:为某个元素规定一个 aspect 值,这样就可以保持首选字体的 x-height。
2、文本系列属性
text-indent:文本缩进
text-align:文本水平对齐
line-height:行高
word-spacing:增加或减少单词间的空白(即字间隔)
letter-spacing:增加或减少字符间的空白(字符间距)
text-transform:控制文本大小写
direction:规定文本的书写方向
color:文本颜色
3、元素可见性:visibility
4、表格布局属性:caption-side、border-collapse、border-spacing、empty-cells、table-layout
5、列表布局属性:list-style-type、list-style-image、list-style-position、list-style
6、生成内容属性:quotes
7、光标属性:cursor
8、页面样式属性:page、page-break-inside、windows、orphans
9、声音样式属性:speak、speak-punctuation、speak-numeral、speak-header、speech-rate、volume、voice-family、pitch、pitch-range、stress、richness、、azimuth、elevation
三、所有元素可以继承的属性
1、元素可见性:visibility
2、光标属性:cursor
四、内联元素可以继承的属性
1、字体系列属性
2、除text-indent、text-align之外的文本系列属性
五、块级元素可以继承的属性
1、text-indent、text-align
DOM 事件
1. 浏览器事件流
事件流是网页元素接收事件的顺序,"DOM2级事件"规定的事件流包括三个阶段:事件捕获阶段、处于目标阶段、事件冒泡阶段。首先发生的事件捕获,为截获事件提供机会。然后是实际的目标接受事件。最后一个阶段是事件冒泡阶段,可以在这个阶段对事件做出响应。虽然捕获阶段在规范中规定不允许响应事件,但是实际上还是会执行,所以有两次机会获取到事件。
1.1 事件捕获阶段
事件捕获的用意是在于事件到达预定目标之前捕获它。因此,事件捕获的过程是让不太具体的节点先更早接收到事件,而最具体的节点应该最后接收到事件。
1.2 处于目标阶段
事件在发生
1.3 事件冒泡阶段
事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播到较为不具体的节点,即document对象。
练习题
<div onclick="console.log('div')">
<p onclick="console.log('p')">
Click here!
</p>
</div>
// p div
如果我们单击p,我们会看到两个日志:p和div。在事件传播期间,有三个阶段:捕获,目标和冒泡。 默认情况下,事件处理程序在冒泡阶段执行(除非您将useCapture设置为true)。 它从最深的嵌套元素向外延伸。
1.4 监听函数
- addEventListener()
- removeEventListener()
所有的DOM节点都包含这两个方法,而且接受三个参数:
- 要处理的事件名
- 作为事件处理程序的函数
- 一个
boolean
值,如果值为true
,表示在捕获阶段调用事件处理程序;如果是false
,表示在冒泡阶段调用此事件处理程序。通常默认第三个参数不写的话,事件就在冒泡阶段执行。
1.5 事件如何发生
基于发布–订阅模式,就是在浏览器加载的时候会读取事件相关的代码,但是只有实际等到具体的事件触发的时候才会执行。
比如点击按钮,这是个事件(Event),而负责处理事件的代码段通常被称为事件处理程序(Event Handler),也就是「启动对话框的显示」这个动作。
2. 事件委托(代理)
2.1 原理
事件冒泡机制
事件委托指的是,不在事件的发生地(直接dom)上设置监听函数,而是在其父元素上设置监听函数,通过事件冒泡,父元素可以监听到子元素上事件的触发,通过判断事件发生元素DOM的类型,来做出不同的响应。
2.2 优点
- 可以大量节省内存占用,减少事件注册。比如ul上代理所有li的click事件
- 可以实现当新增子对象时,无需再对其进行事件绑定,对于动态内容部分尤为合适
2.3 缺点
事件代理的常用应用应该仅限于上述需求,如果把所有事件都用事件代理,可能会出现事件误判。即本不该被触发的事件被绑定上了事件。
2.4 阻止事件冒泡和默认事件
event.preventDefault() // 阻止默认事件
event.stopPropagation() //阻止冒泡
3. 类数组和数组
3.1 什么是类数组
类数组是指在写法上跟数组一样,比如arguments,函数的第一个参数是argument[0],写法上跟数组一样,但是不是数组,原型是Object。类数组对象不能直接利用数组的方法(例如:forEach,map等),需要转换为数组后,才能用数组的方法。
练习题
function getAge(...args) {
console.log(typeof args)
}
getAge(21)
// "object"
扩展运算符(
...args
)会返回实参组成的数组。而数组是对象,因此typeof args
返回"object"
。
3.2 类数组转换为数组
- Array.from(arr)
// 将hdList用Array.from()方法转换为数组,并用list变量接收
let list = Array.from(hdList);
- Array.prototype.slice.call(elems)
// hdList转化为数组并用list变量接收
let list = Array.prototype.slice.call(hdList);
- [ …elems ]
// 用[ ...elems ]方法转化为数组并用list接收
let list = [...hdList];
- Array.prototype.forEach.call(elem,callback)
// 直接对hdList集合进行循环或者map等
Array.prototype.forEach.call(hdList,function(){
//...
})
Array.prototype.map.call(hdList,function(){
//...
})
- Array.prototype.forEach.apply(elem,[callback])
Array.prototype.forEach.apply(hdList,[(current,index) => {
current.addEventListener('click',() => {
animationFn(index);
},false);
}]);
- bind
Array.prototype.forEach.bind(hdList)((current,index) => {
current.addEventListener('click',() => {
animationFn(index);
},false);
});
4. 添加原生事件不移除,为什么会导致内存泄漏
var button = document.getElementById('button');
function onClick(event) {
button.innerHTML = 'text';
}
button.addEventListener('click', onClick);
给元素button
添加了一个事件处理器onClick
, 而处理器里面使用了button
的引用。而老版本的 IE 是无法检测 DOM 节点与 JavaScript 代码之间的循环引用,因此会导致内存泄漏。
如今,现代的浏览器(包括 IE 和 Microsoft Edge)使用了更先进的垃圾回收算法,已经可以正确检测和处理循环引用了。换言之,回收节点内存时,不必非要调用 removeEventListener 了。
4.1 常见的容易导致内存泄漏的点
4.1.1 意外的全局变量
如果必须使用全局变量存储大量数据时,确保用完以后把它设置为 null 或者重新定义。与全局变量相关的增加内存消耗的一个主因是缓存。缓存数据是为了重用,缓存必须有一个大小上限才有用。
4.1.2 被遗忘的计时器
尽管这个定时器不再需要,里面的回调也不再需要,可是计时器回调函数并没有被回收,这样someResource
,如果存储了大量的数据,也是无法被回收。 因此需要把定时器清除。
var someResource = getData();
setInterval(function() {
var node = document.getElementById('Node');
if(node) {
// 处理 node 和 someResource
node.innerHTML = JSON.stringify(someResource));
}
}, 1000);
4.1.3 脱离DOM的引用
当你保存了一个dom的引用,然后将该dom从html中删除后,你应该将这个引用赋为null,否则GC不会回收,这个dom仍然在内存中。保存 DOM 元素引用的时候,要小心谨慎。
var elements = {
button: document.getElementById('button'),
image: document.getElementById('image'),
text: document.getElementById('text')
};
function doStuff() {
image.src = 'http://some.url/image';
button.click();
console.log(text.innerHTML);
// 更多逻辑
}
function removeButton() {
// 按钮是 body 的后代元素
document.body.removeChild(document.getElementById('button'));
// 此时,仍旧存在一个全局的 #button 的引用
// elements 字典。button 元素仍旧在内存中,不能被 GC 回收。
}
4.1.4 闭包
闭包包含外面函数的活动对象,无法被GC回收。
5. 如何减少 dom 数量?大量的 dom 操作如何优化?
5.1 减少 dom 数量
- 使用伪元素
- 按需加载,减少不必要的渲染
- 结构合理,语义化标签
5.2 大量 dom 操作优化
- 缓存 dom 对象
- 使用
document.createDocumentFragment
创建文档碎片,创建一个虚拟的节点对象。向这个节点添加 dom 节点,或者修改 dom 节点是不会影响到真实的 dom 节点。 - 用 innerHTML 代替高频的 appendChild
- 使用 requestAnimationFrame() 批量读,一次性写
- 使用 虚拟 dom
6. setInterval() 和 setTimeout()
6.1 setInterval()
setInterval() 方法可按照指定的周期(以毫秒计)来调用函数或计算表达式。
setInterval() 方法会不停地调用函数,直到 clearInterval() 被调用或窗口被关闭。由 setInterval() 返回的 ID 值可用作 clearInterval() 方法的参数。
6.2 注意事项
- 在动态加载的页面中,一定要清理循环定时器。有时候重复设置定时器,严重的时候会导致内存泄露,最终页面崩溃。
- 回调函数中会包含一些变量或者DOM元素,需要更加小心谨慎,考虑这些元素的释放问题。
6.3 setTimeout() 时间为什么不精确
- 因为 JavaScript 是一个单线程序的解释器,因此一定时间内只能执行一段代码
- 为了控制要执行的代码,就有一个 JavaScript 任务队列
- 这些任务会按照将它们添加到队列的顺序执行
- setTimeout() 的第二个参数告诉 JavaScript 再过多长时间把当前任务添加到队列中。如果队列是空的,那么添加的代码会立即执行;如果队列不是空的,那么它就要等前面的代码执行完了以后再执行
7. window.onload 和 DOMContentLoaded 的区别
- load事件触发时,页面上所有的DOM,样式表,脚本,图片都已经加载完成了
- DOMContentLoaded事件触发时,仅当DOM加载完成,不包括样式表,图片(譬如如果有async加载的脚本就不一定完成)