Skip to content

HTML ​

HTML 文档 ​

HTML(HyperText Markup Language,超文本标记语言)是用于描述网页结构的标准标记语言,通过各种标签标记文本、图像、链接等内容,使浏览器能正确解析并显示网页。

一个标准的 HTML 文档通常包含以下部分:

  • <!DOCTYPE html>:声明文档类型,告知浏览器使用 HTML5 标准解析页面。
  • <html>:整个文档的根元素。
  • <head>:存放文档的元数据(meta 信息)、标题、样式、外部链接等。
  • <body>:包含页面的主要内容,如文本、图片、链接等。

行内元素与块级元素 ​

属性行内元素块级元素
占据空间仅限于标签边框内占满父元素宽度
排列方式同行排列,不换行独占一行
包含内容文本和行内元素行内元素及其他块级元素
盒模型width/height 无效,上下边距无连带影响完全支持 width、height 及边距
常见标签a、span、img、button、input 等div、p、h1~h6 等

HTML5 新特性 ​

  • 语义化标签:新增 <header>、<footer>、<article>、<nav> 等标签,使文档结构更清晰。

  • 增强的表单:扩展 <input> 的 type 属性(如日期、时间、邮箱等),并增加 <datalist>, <keygen>, <output> 等元素。

  • 多媒体支持:通过 <audio> 和 <video> 标签以及相应 API 轻松嵌入和控制音视频。

  • Canvas 绘图:<canvas> 提供了用 JavaScript 绘制图形、动画和图像的能力。

  • 地理定位 API:利用 Geolocation API 获取用户地理位置信息,方便实现定位功能。

  • Web 存储技术:使用 localStorage 和 sessionStorage 在客户端保存数据,减少服务器通信。

  • WebSocket 协议:支持基于 TCP 的全双工通信,实现实时数据交换。

  • Web Workers:后台多线程执行 JavaScript,提升页面响应效率。

  • 离线应用与缓存:利用 Application Cache 缓存资源,实现离线访问网页。

语义化标签 ​

语义化标签指那些通过名称能够准确描述其内容含义的标签。

例如:

  • <header> 表示页面或区域的页眉;
  • <nav> 表示导航部分;
  • <article> 用于独立的文章内容;
  • <footer> 表示页脚。

作用:

  • 使页面内容结构清晰
  • 提高代码可读性
  • 方便搜索引擎理解页面结构,利于 SEO。

浏览器及其内核理解 ​

浏览器的主要功能是 呈现 Web 资源,它通过 URI(统一资源标识符) 定位资源,从服务器请求并在窗口中显示内容,如 HTML、CSS、图片或 PDF 等格式。

浏览器由两部分组成:

  1. Shell(外壳): 负责用户界面,如菜单、工具栏和设置等,调用内核实现功能。
  2. 内核(核心): 主要负责网页的解析与渲染。

浏览器内核包含两个核心模块:

  • 渲染引擎(Rendering Engine): 解析 HTML、CSS 并渲染页面内容。
  • JS 引擎(JavaScript Engine): 解析和执行 JavaScript,赋予网页动态交互能力。

早期渲染引擎和 JS 引擎并未明确区分,随着 JS 引擎的独立发展,"浏览器内核" 现多指 渲染引擎。不同浏览器厂商对 Web 规范的实现有所差异,导致兼容性问题。

浏览器的渲染原理 ​

  1. 资源获取:根据 URL 下载 HTML、CSS、JS、图片等资源。
  2. 构建 DOM 和 CSSOM:分别解析 HTML 和 CSS,构建 DOM 树和 CSSOM 树。
  3. 生成渲染树:将 DOM 树和 CSSOM 树合并,仅保留需显示的节点,形成渲染树。
  4. 布局:根据渲染树计算每个元素的确切位置和大小。
  5. 绘制:将各元素转换成像素,在屏幕上绘制出页面内容。

浏览器的渲染过程是逐步完成的,为了更好的用户体验,渲染引擎将会尽可能早的将内容现呈到屏幕上,解析完一部分内容就显示一部分内容。

渲染过程中遇到 JS 文件怎么处理 ​

JavaScript 的加载、解析与执行会阻塞文档的解析,在构建 DOM 树时,HTML 解析器若遇到了 JavaScript,那么它会暂停文档的解析,将控制权移交给 JS 引擎,等 JS 引擎运行完毕,浏览器再从中断的地方恢复继续解析文档。

如果想首屏渲染得越快,就不应该在首屏加载 JS 文件,这也是建议将 script 标签放在 body 标签底部的原因。或者可以给 script 标签添加 defer 或者 async 属性。

async 和 defer 的作用和区别 ​

两者都是用来告诉浏览器异步加载 JavaScript 脚本,从而避免阻塞页面的 HTML 解析,提升页面加载速度。

  • 使用 async 的 JS 脚本在下载后立即执行(无序),适合独立、互不依赖的脚本,例如统计、广告等
  • 使用 defer 的 JS 脚本则在文档解析完毕后按顺序执行,适合依赖 DOM 或相互之间有依赖关系的脚本。

JS 延迟加载的方式 ​

  • 将脚本放在页面底部:将 <script> 标签放在 </body> 前,确保页面内容先行加载。
  • async 属性:在 <script> 标签中添加 async 属性,脚本异步加载,加载完成后立即执行,执行顺序不确定。
  • defer 属性:在 <script> 标签中添加 defer 属性,脚本会在 HTML 解析完毕后按顺序执行。
  • 动态创建脚本:使用 JavaScript 动态创建并插入 <script> 标签,实现按需加载。
  • 使用 setTimeout 方法:通过 setTimeout() 延迟执行脚本,给页面其他资源留出加载时间。

重绘和重排(回流) ​

  • 重绘:当元素的外观样式(如颜色、背景) 发生变化,但不影响布局时,浏览器会重新绘制元素的外观,这个过程称为重绘。

    常见会引起重绘的属性和方法:

    • 颜色属性:color 文本颜色、background-color 背景颜色
    • 背景属性:background-image 背景图片
    • 边框属性:border 边框样式、宽度、颜色
    • 文本属性:font-size 字体大小、font-family 字体、font-weight 字体粗细、text-decoration 文本装饰
    • 显示属性:display 元素的显示方式(例如,从 none 到 block)
    • 定位属性:position: 元素定位方式(例如,从 static 到 relative 或 absolute)
    • ...
  • 重排(回流):当 DOM 元素的几何属性(如位置、大小)发生变化时,浏览器需要重新计算布局,这个过程称为重排。

    常见引起重排(回流)的属性和方法:

    • 添加或者删除可见的 DOM 元素。
    • 元素尺寸改变(宽度和高度、边距、填充、边框)。
    • 内容变化,比如用户在 input 框中输入文字。
    • 浏览器窗口尺寸改变 resize 事件发生时。
    • ...

重排必然会导致重绘,但重绘不一定需要重排。因此,尽量减少不必要的重排和重绘,有助于提升网页的渲染性能。

如何减少重绘和重排 ​

  • 批量修改样式:避免逐一修改样式属性,通过修改 className 一次性更改多个样式。

  • 使用文档碎片:当需要在 DOM 中插入大量节点时,使用文档碎片创建和操作节点,然后再一次性插入到 DOM 中,减少重排的次数。

  • 脱离文档流:对于需要频繁操作的元素,可以使用 position: absolute 或 position: fixed 使其脱离文档流,减少对其他元素布局的影响。

  • 避免频繁读取布局信息:多次读取布局属性(如 offsetTop、clientWidth)会触发重排,建议将其值缓存到局部变量中,减少重复访问。

  • 使用 Flexbox 和 Grid 布局:使用 Flexbox 和 Grid 布局可以减少元素的重绘和重排,因为它们不会像传统布局模型那样频繁引起元素的重新排列。

  • 节流和防抖:在处理用户输入、滚动等事件时,可以使用节流(throttle)和防抖(debounce)的技术,减少频繁的重排和重绘操作。

DOMContentLoaded 事件和 Load 事件 ​

事件触发时机适用场景
DOMContentLoadedHTML 解析完毕(不等图片、CSS 加载)DOM 操作,初始化 JS 逻辑
Load页面所有资源加载完成(包括图片等)资源相关的操作,如动画、布局调整
  • 若 仅需操作 DOM,使用 DOMContentLoaded,避免等待不必要的资源加载。
  • 若 依赖页面所有资源,如图片尺寸计算,则使用 load。

浏览器端的存储技术 ​

浏览器端的常用存储技术有 Cookies、LocalStorage、SessionStorage、IndexedDB 和 Cache API 等。

存储方式容量过期机制特点
Cookies4KB可设过期时间,每次请求都会携带适合存小量数据,不安全,不适合存敏感信息
LocalStorage5MB永久保存,需手动清除适合持久存储,简单易用,受同源策略限制
SessionStorage5MB关闭标签页即清除适合临时存储,生命周期随会话结束
IndexedDB几百 MB+需手动管理适合存大量数据,支持异步和事务机制
Cache API依浏览器而定需手动管理适合缓存网络资源,支持离线访问

浏览器内多个标签页之间的通信 ​

实现多个标签页之间的通信,本质上都是通过中介者模式来实现的。因为标签页之间没有办法直接通信,因此我们可以找一个中介者,让标签页和中介者进行通信,然后让这个中介者来进行消息的转发。

  1. 使用 localStorage 或 sessionStorage
    这两个 Web Storage 技术可以在同一域下的不同标签页之间共享数据。当一个标签页修改 localStorage 或 sessionStorage 中的数据时,其他标签页可以通过监听 storage 事件来得知数据的变化。

    javascript
    // 在页面 1 中设置数据
    localStorage.setItem('key', 'value');
    
    // 在页面 2 中监听 storage 事件,当页面 1 修改数据时会触发
    window.addEventListener('storage', function(event) {
      if (event.key === 'key') {
        var updatedValue = event.newValue;
        // 处理更新后的数据
      }
    });
  2. 使用 Broadcast Channel API
    BroadcastChannel API 提供了一种在不同窗口或标签页之间进行广播通信的方式。不同窗口可以通过同一个 BroadcastChannel 实例进行通信。

    javascript
    // 在页面 1 中创建广播通道
    const channel = new BroadcastChannel('my_channel');
    
    // 在页面 2 中监听消息
    channel.addEventListener('message', function(event) {
      var receivedData = event.data;
      // 处理接收到的数据
    });
    
    // 在页面 1 中发送消息
    channel.postMessage({ key: 'value' });
  3. 使用 SharedWorker
    SharedWorker 是一种在不同标签页之间共享状态的方式,不同于普通的 Web Worker,SharedWorker 可以被多个窗口共享。通过 postMessage 方法在不同标签页之间发送消息。

    javascript
    // 在页面 1 中创建 SharedWorker
    const worker = new SharedWorker('worker.js');
    
    // 在页面 2 中监听消息
    worker.port.addEventListener('message', function(event) {
      var receivedData = event.data;
      // 处理接收到的数据
    });
    
    // 在页面 1 中发送消息
    worker.port.postMessage({ key: 'value' });
  4. 使用 WebSocket
    WebSocket 协议可以实现服务器推送,服务器就可以用来当做这个中介者。标签页通过向服务器发送数据,然后由服务器向其他标签页推送转发。

Canvas 和 SVG ​

特性CanvasSVG
渲染方式逐像素绘制(位图)基于 XML(矢量图)
缩放效果可能失真(像素化)不失真,保持清晰
交互性需要手动处理事件直接支持 DOM 事件
适合场景大量动态绘制,如游戏、数据可视化复杂矢量图形,如图标、地图
  • Canvas:适合高性能、频繁更新的图形,如动画、游戏、实时图表。
  • SVG:适合静态或少量动态的矢量图,如图标、地图、流程图。

渐进增强和优雅降级 ​

  • 渐进增强:针对低版本浏览器进行构建页面,保证最基本的功能,然后再针对高级浏览器进行效果、交互等改进和追加功能达到更好的用户体验。

  • 优雅降级:一开始就根据高版本浏览器构建完整的功能,然后再针对低版本浏览器进行兼容。

浏览器地址栏输入 URL 到页面渲染的整个流程 ​

  1. URL 解析:浏览器会对该 URL 进行解析,分析需要使用的传输协议和请求资源的路径。

  2. 缓存检查:检查本地缓存,如果存在缓存资源且未过期则直接使用,否则发起新请求。

  3. DNS 查询:浏览器通过 DNS 解析器查询该域名对应的 IP 地址。如果 DNS 缓存中存在该域名对应的 IP 地址,则直接返回;否则,将请求发送到 DNS 服务器进行解析。

  4. 建立 TCP 连接:浏览器使用 HTTP 协议建立与服务器三次握手的 TCP 连接。在建立连接的过程中,如果是 HTTPS 协议,还需要进行 TLS/SSL 四次握手来确保通信安全。

  5. 发起 HTTP 请求:浏览器向服务器发送 HTTP 请求。

  6. 服务器处理请求:服务器接收到 HTTP 请求后,根据请求的 URL 和方法进行相应的处理。处理过程可能包括查询数据库、生成动态内容、读取静态文件等操作。

  7. 服务器响应:服务器处理完请求后,将相应的结果以 HTTP 响应的形式返回给浏览器。

  8. 接收响应:浏览器接收到服务器的响应后,开始解析响应。检查响应头中的 Content-Type,确定响应的数据类型(如 HTML、JSON、图片等),然后根据相应的数据类型进行相应的处理。

  9. 页面渲染:如果响应的是 HTML 类型的数据,浏览器开始解析 HTML,并构建 DOM 树。在构建 DOM 树的过程中,遇到外部资源(如 CSS、JavaScript、图片等)的引用,则会发起额外的请求获取这些资源。同时,浏览器还会解析 CSS,构建 CSSOM 树,并将 DOM 树和 CSSOM 树合并成渲染树。最后,浏览器根据渲染树进行页面渲染,呈现给用户。

  10. 断开连接:页面加载完成后,通过 TCP 四次挥手断开连接。

前端性能优化 ​

前端性能优化是提高网页加载速度和用户体验的关键。需要根据项目的实际情况做相对应的优化,以下是一些常见的前端性能优化方案:

  1. 资源优化:

    • 文件优化(多个文件合并为一个,文件懒加载、预加载、异步加载)
    • 代码优化(JS/CSS 代码合并、压缩、按需加载、Tree-shaking 减小包体积)
    • 图片优化 (选择适当的格式,如:WebP/AVIF/SVG、压缩、懒加载、预加载、雪碧图、base64)
    • 图标优化 (iconify 按需加载)
    • 缓存优化(浏览器缓存,对常用不变的资源进行缓存、本地缓存,如:LocalStorage、SessionStorage、IndexedDB)
  2. 渲染优化:

    • 减少 DOM 操作,避免重绘和重排
    • 使用虚拟滚动和分页
    • 骨架屏和占位 UI
    • 优先显示关键内容
    • 使用请求动画帧(requestAnimationFrame)
  3. 网络优化:

    • HTTP/2 和 HTTP/3(减少网络请求的开销)
    • 请求和响应资源压缩 (Gzip/Brotli)
    • CDN 加速
    • 预连接 (preconnect)、预加载 (preload) 和预获取 (prefetch)
    • 响应资源缓存
    • DNS 优化(DNS 预解析、DNS 缓存)
  4. 运行时优化:

    • Web Workers(处理密集计算和耗时长的任务,避免阻塞主线程)
    • 防抖和节流高频操作
    • 事件委托
    • 编译优化 (AOT 编译)
  5. 服务端优化:

    • 服务端使用 SSR(提前生成 HTML,减轻客户端渲染的负担)
    • 服务端预渲染(预渲染关键页面,提高首屏加载速度)
    • 响应资源压缩(接口响应启用 Gzip 等方式对传输的资源进行压缩)

这些优化方案是综合应用的结果,不同的项目和场景需要结合不同的优化策略。

Released under the AGPL-3.0 License