0%

JPG / JPEG

优点:

  • 有损压缩
  • 不支持透明
  • 适合色彩丰富的照片
  • 体积小、加载快

缺点:当它处理矢量图形和 Logo 等线条感较强、颜色对比强烈的图像时,人为压缩导致的图片模糊会相当明显

PNG

优点:

  • 无损压缩
  • 有 PNG8 和 PNG24
  • 适合图标、背景、按钮

缺点:体积大

PNG 还是 JPG

  • 复杂的、色彩层次丰富的图片,用 PNG 来处理的话,成本会比较高,我们一般会交给 JPG 去存储
  • 考虑到 PNG 在处理线条和颜色对比度方面的优势,我们主要用它来呈现小的 Logo、颜色简单且对比强烈的图片或背景等

SVG

优点:

  • 文件体积更小,可压缩性更强
  • 矢量图,图片可无限放大而不失真
  • 兼容性好

缺点:渲染成本比较高,会影响性能

Base64

Base64 并非一种图片格式,而是一种编码方式
优点:Base64 通过对图片进行 Base64 编码,我们可以直接将编码结果写入 HTML 或者写入 CSS,从而减少 HTTP 请求的次数

缺点:图片大小会膨胀为原文件的 4/3,因此只有在传输非常小的图片的时候,Base64 带来的文件体积膨胀、以及浏览器解析 Base64 的时间开销,与它节省掉的 HTTP 请求开销相比,可以忽略不计,这时候才能真正体现出它在性能方面的优势

使用场景:

  • 图片的实际尺寸很小
  • 图片不适合以雪碧图的形式与其它小图结合(合成雪碧图仍是主要的减少 HTTP 请求的途径,Base64 是雪碧图的补充)
  • 图片的更新频率非常低,如 logo

WEBP

优点:
WebP 支持有损和无损,它可以像 JPG 一样对细节丰富的图片信手拈来,像 PNG 一样支持透明,像 GIF 一样可以显示动态图片。总而言之,它集多种图片文件格式的优点于一身。

缺点:
兼容性不好

我们可以使用这样的处理方案:在浏览器环境支持 WebP 的情况下,优先使用 WebP 格式,否则就把图片降级为 JPG 格式

参考资料:
https://juejin.cn/book/6844733750048210957/section/6844733750106914830

rgba 和 opacity 的透明效果比较

rgba 和 opacity 都能实现透明效果,但最大的不同是 opacity 作用于元素,以及元素内的所有内容的透明度,而 rgba 只作用于元素的颜色或其背景色。(换言之,设置 rgba 透明的元素的子元素不会继承透明效果!)

line-height 三种赋值方式之间的区别

带单位

px 是固定值,而 em 会参考父元素 font-size 值计算自身的行高

纯数字

会把比例传递给后代。例如,父级行高为 1.5,子元素字体为 18px,则子元素行高为 1.5 * 18 = 27px

百分比

会将计算后的值传递给后代。例如,父级行高为 150%,font-size 是 20px,那么行高就是 20px * 150% = 30px,子元素也是 30px

流体布局

要求:左右固定,中间自适应。
原理:一个左浮,一个右浮,中间宽度自适应。

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
<div class="container">
<div class="left"></div>
<div class="right"></div>
<div class="main"></div>
</div>

<style>
.left {
float: left;
width: 100px;
height: 200px;
background: red;
}

.right {
float: right;
width: 200px;
height: 200px;
background: blue;
}

.main {
height: 200px;
background: green;
}
</style>

三列布局

要求:三列布局;中间主体内容前置,且宽度自适应;两边内容定宽。
优点:重要内容放在文档流前面,可以被优先渲染

首先完成页面基础布局。

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
30
31
32
33
34
35
36
<div class="container">
<div class="main"></div>
<div class="left"></div>
<div class="right"></div>
</div>

<style>
body {
/* 避免出现奇怪 bug */
min-width: 600px;
}

.main,
.left,
.right {
float: left;
}

.left {
width: 200px;
height: 200px;
background: green;
}

.right {
width: 100px;
height: 200px;
background-color: red;
}

.main {
width: 100%;
height: 200px;
background: yellow;
}
</style>

圣杯布局

  • 先给 container 设置左右 padding,把位置空出来
    1
    2
    3
    4
    5
    .container {
    padding-left: 200px;
    padding-right: 100px;
    overflow: hidden;
    }
  • left 设置 margin-left 为 -100%,来到最左边
    1
    2
    3
    .left {
    margin-left: -100%;
    }
  • right 设置 margin-left 为 -自身宽度,来到最右边
    1
    2
    3
    .right {
    margin-left: -100px;
    }
    完成后如图:

接下来只要给 left 和 right 分别一个 position: relative 将它们自身定位到两端即可。

1
2
3
4
5
6
7
8
.left {
position: relative;
left: -200px;
}
.right {
position: relative;
left: 100px;
}

双飞翼布局

  • 首先在 main 里面添加一个子节点 content,若不设置此节点,main 的内容将无法显示
    1
    2
    3
    4
    5
    6
    7
    <div class="container">
    <div class="main">
    <div class="content"></div>
    </div>
    <div class="left"></div>
    <div class="right"></div>
    </div>
  • container 不需要设置 padding
  • left 和 right 不需要设置 relative 定位
  • 调整子节点 content 位置
    1
    2
    3
    .content {
    margin: 0 100px 0 200px;
    }

多列等高布局

考虑兼容性的情况下,可以使用很大的负 margin-bottom 和很大的正 padding-bottom 对冲实现。

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
30
31
32
33
34
35
36
37
38
39
40
<style>
ul {
overflow: hidden;
}

li {
float: left;
margin: 0 10px -9999px 0;
padding-bottom: 9999px;
background: #5182e6;
width: 200px;
color: #fff;
list-style: none;
}

p {
padding: 10px;
}
</style>

<ul>
<li>
<p>
测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试
测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试
</p>
</li>
<li>
<p>
测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试
测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试
测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试
测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试
测试测试测试测试测试测试测试测试测试
</p>
</li>
<li>
<p>一家将客户利益置于首位的经纪商</p>
</li>
</ul>

参考资料:
https://juejin.cn/post/6955482100426342430

如果要在一个 ul 节点中一次性插入 10000 个 li 元素怎么办?

1
2
3
<ul id="parent">
<!-- 插入一万条数据 -->
</ul>

常规解法

1
2
3
4
5
6
7
const parent = document.getElementById("parent");
for (let i = 0; i < 10000; i++) {
const child = document.createElement("li");
const text = document.createTextNode(i.toString());
child.appendChild(text);
parent.appendChild(child);
}

这样对 DOM 反复操作会导致页面重绘、回流,效率非常低,而且页面可能会被卡死。

DocumentFragment

DocumentFragment 翻译过来就是文档片段的意思。
简单来说就是在内存中提供了一个 DOM 对象,当我们需要频繁操作 DOM 的时候,可以在内存先中创建一个 DocumentFragment 文档片段,然后对这个文档片段中进行一系列频繁的 DOM 操作,当操作结束后直接插入真实的 DOM 节点中,这样所有的节点会被一次插入到真实的文档中,而这个操作仅发生一个重绘的操作。

1
2
3
4
5
6
7
8
9
const parent = document.getElementById("parent");
const fragment = document.createDocumentFragment();
for (let i = 0; i < 10000; i++) {
const child = document.createElement("li");
const text = document.createTextNode(i.toString());
child.appendChild(text);
fragment.appendChild(child);
}
parent.appendChild(fragment);

参考资料:
https://juejin.cn/post/6950553806484537357

什么是重绘与重排

  • 重绘指更改外观属性而不影响几何属性的渲染;重排也叫回流,指几何属性改变的渲染。
  • 注意:JS 获布局相关的属性值时(如:offsetLeft、scrollTop、getComputedStyle等)也会引起回流,因为浏览器需要通过回流计算最新值。
  • 回流必将引起重绘,而重绘不一定会引起回流

属性分类

几何属性

几何属性包括布局、尺寸等可用数学几何衡量的属性
布局:display、float、position、list、table、flex、columns、grid
尺寸:margin、padding、border、width、height

外观属性

外观属性包括界面、文字等可用状态向量描述的属性
界面:appearance、outline、background、mask、box-shadow、box-reflect、filter、opacity、clip
文字:text、font、word

如何减少重绘和回流

  • dom 离线修改:需要对元素进行复杂的操作时,可以先隐藏使用 display: none; 隐藏元素,操作完成后再显示
  • 需要创建多个 dom 节点时,使用 DocumentFragment 创建完后一次性的加入文档
  • 尽量避免用 table 布局(table 一旦触发回流就会导致 table 里所有的其它元素回流)
  • 避免使用 css 表达式,因为每次调用都会重新计算值(包括加载页面)
  • 批量修改元素样式:一次性修改完成后再更改元素类名
  • 使用 transform 替代绝对定位,因为 tranform 会开启新图层,使用 GPU 进行渲染。如果图片未改变,GPU 可以直接使用缓存来绘制图层,所以很快。类似的 CSS 属性还有 opacity 和 filter

参考资料:
https://juejin.cn/book/6850413616484040711/section/6850413616559194119
https://blog.csdn.net/duola8789/article/details/79237553

link 与 @import 的区别

  • link是 html 方式, @import 是 css 方式。@import 只有导入样式表的作用;link 不仅可以加载 CSS 文件,还可以定义其他属性,如 shortcut
  • 加载页面时,link 标签引入的 CSS 被同时并行加载;@import引入的 CSS 将在页面加载完毕后被加载,会出现 FOUC(文档样式短暂失效)
  • 浏览器对 link 支持早于 @import,兼容性更好
  • 可以通过 JS 操作 DOM ,插入 link 标签来改变样式;JS 无法使用 @import 的方式插入样式

补充:什么是 FOUC

FOUC(Flash Of Unstyled Content):用户定义样式表加载之前浏览器使用默认样式显示文档,用户样式加载渲染之后再重新显示文档,造成页面闪烁。
解决方法:把样式表放到文档的 <head>

参考资料:
https://www.cnblogs.com/my--sunshine/p/6872224.html

display: none 与 visibility: hidden 与 opacity: 0 的区别

联系:它们都能让元素不可见
区别:

  • opacity: 0 设置后元素还可以进行交互,如点击事件之类的
  • display:none; 会让元素完全从渲染树中消失,渲染的时候不占据任何空间;visibility: hidden; 不会让元素从渲染树消失,渲染时元素继续占据空间,只是内容不可见
  • display: none; 是非继承属性,子孙节点消失由于元素从渲染树消失造成,通过修改子孙节点属性无法显示;visibility: hidden; 是继承属性,子孙节点消失由于继承了 hidden,通过设置 visibility: visible; 可以让子孙节点显式
  • 修改 display 通常会造成文档重排;修改 visibility 只会造成元素重绘
  • 读屏器不会读取 display: none; 元素内容;会读取 visibility: hidden; 元素内容

示例代码

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
30
31
<style>
.parent {
border: 5px solid #fcc;
width: 300px;
}

.child {
border: 5px solid #f66;
width: 100px;
height: 100px;
float: left;
}

.clearfix:after {
content: '';
visibility: hidden;
clear: both;
display: block;
}

.clearfix {
*zoom: 1;
}
</style>

<body>
<div class="parent clearfix">
<div class="child"></div>
<div class="child"></div>
</div>
</body>

父元素设置具体高度

给父元素设置具体高度后,即可清除浮动。但是这样相当于把高度写死了,很不灵活。

父元素结束标签之前插入空元素

1
2
3
4
5
6
7
8
9
10
11
12
13
<style>
.clear {
clear: both;
}
</style>

<body>
<div class="parent">
<div class="child"></div>
<div class="child"></div>
<div class="clear"></div>
</div>
</body>

给父元素添加伪元素(推荐)

1
2
3
4
5
6
7
8
9
10
11
.clearfix:after {
content: '';
visibility: hidden;
clear: both;
display: block;
}

/* 兼容 IE */
.clearfix {
*zoom: 1;
}

clear 属性只有块级元素才有效的,而 ::after 等伪元素默认都是内联水平,这就是借助伪元素清除浮动影响时需要设置 display 为 block 的原因

利用 BFC

1
2
3
.parent {
overflow: hidden;
}

父元素浮动或者绝对定位

浮动

1
2
3
.parent {
float: left;
}

绝对定位

1
2
3
.parent {
position: absolute;
}

参考资料:
https://juejin.cn/post/6844903504545316877
https://www.kancloud.cn/pillys/qianduan/2049767

width: 100% 与 width: auto 的区别

  1. width:100% 并不包含 margin-left 和 margin-right 的属性值,直接取其父容器的宽度加上含 margin-left 和 margin-right 的值。如果设置了 margin 那新的 width 值是容器的宽度加上 margin 的值。

  2. width:auto 包含 margin-left 和 margin-right 的属性值。width:auto 总是占据整行,margin 的值已经包含其中了。

  3. 一般 width:auto 使用的多,因为这样灵活,而 width:100% 使用比较少,因为在增加 padding 或者 margin 的时候,容易使其突破父级框,破环布局。

举例来说,
当 child 没有加 margin,两者之间没什么区别

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<style>
.parent {
height: 200px;
width: 200px;
background-color: rgb(195, 229, 236);
color: #000;
}

.child {
height: 100px;
width: 100%;
background-color: red;
color: #fff;
}
</style>

或者改成

1
2
3
.child {
width: auto;
}

结果都一样

但是当 child 加上 margin 后,

1
2
3
.child {
margin-left: 50px;
}

width: 100% 的情况会变为

width: auto 的情况会变为