滴水穿石----前端面试积累

214 阅读12分钟

理解浏览器如何渲染网页

用户访问网站时,浏览器将解析HTML和CSS,并将其渲染到屏幕

页面渲染过程.png

整个过程的具体步骤如下:

  1. 解析HTML以创建DOM(Document Object Model, 文档对象模型) ---- 从Web服务器下载HTML时,浏览器会对其进行解析 以构建DOM,这是HTML文档结构的层次表示。

  2. 解析CSS以创建CSSOM(CSS Object Model, CSS对象模型) ---- DOM建立完成后,浏览器解析CSS并创建CSSOM。CSSOM与 DOM类似,只不过它是用来表示CSS规则应用于文档的方式。

  3. 布局元素 ---- DOM和CSSOM树组合创建渲染树。然后渲染树执行布局过程,在此过程中应用CSS规则,并在页面上布局 元素以创建UI

  4. 绘制页面 ---- 文档完成布局后,页面外观将应用CSS和页面中的媒体内容。绘制过程结束时,输出转换为像素(光栅化) 并在屏幕上显示

许多站点的大部分渲染规则是在页面首次加载时完成的,但此后可能发生更多渲染。用户与页面上的元素交互时,页面可能 发生变化。这些变化可以触发重新渲染

出自《Web性能实战》

优化CSS的一些方案

  • CSS简写属性不仅方便,而且通过减少多余和冗长的规则为我们提供了一种减小样式表大小的方法
  • 使用CSS浅选择器也可以大幅减小样式表的大小,同时使代码更容易维护和模块化
  • 可以使用csscss冗余检查器应用DRY原则,通过移除多余的属性,进一步优化臃肿的CSS文件
  • 基于用户行为数据对CSS进行分割,可以确保用户第一次访问网站时,不会下载他们可能永远看不到的页面模块的CSS
  • 移动优先的响应式Web设计很重要,从极简主义开始设计最适用于创建高性能网站
  • 移动友好型网站是影响Google 搜索排名的一个因素。通过确保网站移动友好,可以避免对网站页面搜索排名的负面影响
  • 避免使用@import 声明,并将CSS放在文档标签中,会对网站的渲染和加载速度产生积极影响
  • 使用高效的CSS选择器和flex布局引擎,可以提高网站的渲染速度
  • 使用CSS过渡可以实现高性能的简单线性动画,并且不会给最终用户带来实际开销,因为CSS过渡不需要引入外部库
  • 使用will-change属性通知浏览器元素的状态更改,你可以有选择地提高某些元素的动画性能,但前提是要采用可预测的 智能方式。尝试用will-change为所有元素优化动画不仅仅是一种浪费,而且对性能有潜在危害。

微信图片_20220906163633.jpg 出自《Web性能实战》

关键CSS的原理

加载首屏样式

使用<link>标签时渲染阻塞的问题,通过使用CSS内联到标签,可以解决这个问题; 为首屏内容加载的内联样式。首屏内容的CSS被内联到HTML中,以便更快地解析,从而缩短首次绘制时间

内联CSS之所以如此有效,是因为浏览器不必等待太久。浏览器加载页面的HTML时将解析文档,并找到指向其他资源的URL。 如果样式是通过标签加载的,那么在浏览器必须等待CSS时,渲染就会被阻塞。 但是当样式内联到HTML中时, 用户只需要等待加载HTML的过程,随后浏览器就能解析CSS,页面就能渲染。

美中不足的是: 当你以这种方式加载一个网站的所有CSS时,就会失去其可移植性。最后每次加载页面时都会复制CSS, 这意味着以后每次加载页面时都会出现无法有效缓存的情况;

其实,关键CSS在一定程度上已经解释了这一点。 只将首屏样式存储到标签中,并将其内联到HTML,剩下的样式将从外部文件加载。

这是否会使用一些CSS在随后的页面中变得冗余?确实,但只设计网站首屏的一小部分内容。首次绘制的时间减少将抵消郑重冗余的损害。

加载首屏以外内容的样式----首屏以外内容异步加载样式

关键CSS的另一半是加载首屏以外内容样式。这些样式是使用标签加载的,但是你不是以常规的方式使用它,而是要使用preload资源提示加载CSS, 同时不会阻塞渲染。你还将加载一个脚本,该脚本可以为不支持它的浏览器polyfill preload功能

以上操作看起来有点繁琐,但它立竿见影,当与首屏内容的内联CSS结合时,尤其如此。浏览器立即渲染首屏内容的CSS,而preload资源提示会在后台获取 页面其余部分的样式。

<link rel="preload" href="style.min.css" as="style" onload="this.ref='stylesheet'">
// preload资源提示加载首屏以外内的外部CSS。这种加载外部样式表的方式不会阻塞渲染。
// CSS完成加载时,onload事件会触发,并修改<link>标签的rel值使样式渲染

这样可以在不阻塞渲染的情况下加载CSS。CSS完成下载时,标签上的onload事件处理程序将被触发。下载完成后,ref属性的值就会从preload转换为stylesheet. 这将标签从资源提示改为普通CSS引入,后者将CSS应用于首屏以外的内容。 JavaScript polyfill作为兜底,以防浏览器不支持preload提示。

实现正则表达式在线测试

应产品需求,实现正则表达式在线测试功能

// 检查ip-v4是否合法
/((?:(?:25[0-5]|2[0-4]\d|[01]?\d?\d)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d?\d))/.test('172.16.20.64')   // true

考虑到就两个输入框嘛,只要把正则字符串转换成正则表达式即可,然后采用如下方法

// 检查ip-v4是否合法
let regExpString = '((?:(?:25[0-5]|2[0-4]\d|[01]?\d?\d)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d?\d))';
let regString = '172.16.20.64';
let result = new RegExp(regExpString).test(regString)
// false

上面测试结果居然是false,这是为什么?百度了好久没有找到答案,最后查看MDN找到了答案和办法

当使用构造函数创造正则对象时,需要常规的字符转义规则(在前面加反斜杠 \)。

比如,以下是等价的:

var re = new RegExp("\\w+");
var re = /\w+/;

// https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/RegExp

哦,原来是转义问题;接下来修改一下:

// 检查ip-v4是否合法
let regExpString = '((?:(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d))';
let regString = '172.16.20.64';
let result = new RegExp(regExpString).test(regString)
// true
// 最终效果
try{
    let regExpString = '((?:(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d))';
	let regString = '172.16.20.64';
	let result = new RegExp(regExpString).test(regString)
    if(!result) console.log('正则表达式与测试文本不匹配');
    console.log('正则表达式与测试文本匹配')
}catch(e){
    if(e.toString().includes('SyntaxError'))
    console.log('正则表达式书写错误');
}

此时结果如期望效果,妥妥的!

理解关键CSS

  • 折叠是一个灵活的概念。它指的是内容在屏幕上不可见的分界点,它还会基于查看页面的设备发生变化
  • 标签会阻塞网页渲染,从而延迟文档的绘制。关键CSS可以缓解这种行为
  • 关键CSS的工作原理是优先加载折叠之上的首屏内容。关键CSS内联到网站HTML中,而非关键的样式则以延迟的方式加载。 延迟给关键样式后,即可避免渲染阻塞的影响。
  • 实现关键CSS不仅让用户感觉页面加载速度更快,而且这种现象是可衡量的。使用关键CSS时,页面首次绘制的时间会减少。可以使用Chrome的Perfomance面板比较关键CSS对该度量的影响

图像类型及其应用

光栅图像

在web上最常使用的图像类型是光栅,有时称为位图图像;其典型的如:JPEG、PNG、GIF图像,它们由二维网格上对齐的像素组成

  • 光栅图像用于描述Web各种内容:logo、图标、照片等。在HTML中,它们使用标签显示。在CSS中,它们通常用于background属性,但也可以用于其他较少使用的属性。如list-style-image
  • 光栅图像按压缩方式可分为: 有损和无损
有损图像

有损图像采用了丢弃未压缩图像中数据的压缩算法。这些图像类型的实现思路是: 可以接受一定程度的质量损失,以换取较小的文件 这种格式的缺点: 极端的压缩会变得很明显。如果这些类型不是从未缩的源(即源文件,如PSD文件)保存的,则它们也容易发生代际损失。当已经压缩的文件被重新压缩时,会发生代际损失,从而导致 进一步的视觉退化。 然而,在实践中,如果小心使用压缩,退化应该不会很明显,而且这些图像类型是从未压缩的源保存的

  • JPEG算法的输出质量以1~100的刻度表示,1表示最低,100表示最高
  • JPEG并不是Web使用的唯一一种有损图像格式,还有其他格式,比如Google的新的WebP图像格式
无损压缩

另一类光栅图像是无损压缩。这些图像类型使用不从原始图像源中删除数据的是压缩算法。

  • 与有损图像格式不同,无损格式非常适合对图像质量要求比较高的场景。 这使得无损格式称为图标等内容的最佳选择

无损图像类型通常分为以下两类

  • 8位(256色)图像 ---- 包括GIF和8位PNG格式,这些格式支持256色和1位透明度。尽管它们的色彩比较局限,但对于不需要大量颜色或复杂透明度的图标和像素艺术图像来说,是最好的选择, 比如:8位PNG格式往往比GIF图像更高效。然而GIF支持动画,PNG不支持

  • 全彩图像 ---- 只有全彩PNG格式和无损压缩的WebP格式支持256种以上颜色。两者都支持全Alpha透明度,最高支持1670万色。全彩PNG格式比WebP受到更广泛的支持。

各种无损格式在某些类型的内容中有优势,并完全适用于线条艺术、图像学和摄影。要想找到合适方法,需要进行实验,但是基本使用规则一般很简单: 颜色少的简单图像应该使用8位无损格式; 不适合有损格式或需要完全透明的图像应使用全彩PNG

SVG图像

Web上使用的另一种图像格式是可缩放矢量图形。SVG是一种矢量图格式。与光栅图像不同,它们由属性计算的形状和大小组成,所以可以缩放到任何大小。

矢量图应其渲染而缩放得很好。尽管所有设备屏幕都是像素驱动的,因而所有的显示输出最终也以像素表示,但矢量图形显示在屏幕上时依然会经历一个不同于光栅图像的过程; 他们被解析,并且评估数学属性,然后通过一个称为光栅化的过程映射到基于像素的显示。每次图像缩放时都会发生这种情况,以确保所有显示的最佳视觉完整性。

JPEG和全彩PNG文件更适合照片,而SVG最适合用于Logo、线条艺术和图案等内容。

选择图像格式.png

通过媒体查询适配高DPI显示器

要实现响应式图像,必须兼容高DPI显示器(如4K和5K超高清显示器)

// 下面是一个基本的高DPI屏幕媒体查询示例:

@media screen (-webkit-min-device-pixel-radio: 2), (min-resolution: 192dpi) {
	/* 在此放置高DPI样式 */
}

// 在下载更高分辨率的图像之前,要确保显示器的像素密度至少为192DPI
// -webkit-min-device-pixel-radio 媒体查询是Webkit实现兼容就浏览器的高DPI显示支持; 它会检查像素密度的简单比率,其中比率1相当于96DPI;
// min-resolution 媒体查询用于现代浏览器支持

高DPI设置.png

图像的全局max-width

对于任何一个网站,不管是否为响应式网站,CSS中都应该有一个规则

img {
	max-width: 100%;
}
// 这条简单的规则有很多好处,其一是使任何<img>元素都渲染为其自然宽度(除非超过容器)。超过容器宽度时,这条规则会将图像宽度限制为容器的宽度。

在HTML中使用响应式图像的两种方法,这两种方法对于不同的场景都是有用的

  • 元素
  • 标签的srcset属性 显示响应式图像的方法之一,是在标签中使用名为srcset的HTML5特性。标签的这个可选属性不是替换src属性,而是对其进行补充