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 等格式。
浏览器由两部分组成:
- Shell(外壳): 负责用户界面,如菜单、工具栏和设置等,调用内核实现功能。
- 内核(核心): 主要负责网页的解析与渲染。
浏览器内核包含两个核心模块:
- 渲染引擎(Rendering Engine): 解析 HTML、CSS 并渲染页面内容。
- JS 引擎(JavaScript Engine): 解析和执行 JavaScript,赋予网页动态交互能力。
早期渲染引擎和 JS 引擎并未明确区分,随着 JS 引擎的独立发展,"浏览器内核" 现多指 渲染引擎。不同浏览器厂商对 Web 规范的实现有所差异,导致兼容性问题。
浏览器的渲染原理
- 资源获取:根据 URL 下载 HTML、CSS、JS、图片等资源。
- 构建 DOM 和 CSSOM:分别解析 HTML 和 CSS,构建 DOM 树和 CSSOM 树。
- 生成渲染树:将 DOM 树和 CSSOM 树合并,仅保留需显示的节点,形成渲染树。
- 布局:根据渲染树计算每个元素的确切位置和大小。
- 绘制:将各元素转换成像素,在屏幕上绘制出页面内容。
浏览器的渲染过程是逐步完成的,为了更好的用户体验,渲染引擎将会尽可能早的将内容现呈到屏幕上,解析完一部分内容就显示一部分内容。
渲染过程中遇到 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>
前,确保页面内容先行加载。 - defer 属性:在
<script>
标签中添加defer
属性,脚本会在 HTML 解析完毕后按顺序执行。 - async 属性:在
<script>
标签中添加async
属性,脚本异步加载,加载完成后立即执行,执行顺序不确定。 - 动态创建脚本:使用 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 事件
事件 | 触发时机 | 适用场景 |
---|---|---|
DOMContentLoaded | HTML 解析完毕(不等图片、CSS 加载) | DOM 操作,初始化 JS 逻辑 |
Load | 页面所有资源加载完成(包括图片等) | 资源相关的操作,如动画、布局调整 |
- 若 仅需操作 DOM,使用
DOMContentLoaded
,避免等待不必要的资源加载。 - 若 依赖页面所有资源,如图片尺寸计算,则使用
load
。
浏览器端的存储技术
浏览器端的常用存储技术有 Cookies、LocalStorage、SessionStorage、IndexedDB 和 Cache API 等。
存储方式 | 容量 | 过期机制 | 特点 |
---|---|---|---|
Cookies | 4KB | 可设过期时间,每次请求都会携带 | 适合存小量数据,不安全,不适合存敏感信息 |
LocalStorage | 5MB | 永久保存,需手动清除 | 适合持久存储,简单易用,受同源策略限制 |
SessionStorage | 5MB | 关闭页面即清除 | 适合临时存储,生命周期随会话结束 |
IndexedDB | 几百 MB+ | 需手动管理 | 适合存大量数据,支持异步和事务机制 |
Cache API | 依浏览器而定 | 需手动管理 | 适合缓存网络资源,支持离线访问 |
浏览器内多个标签页之间的通信
实现多个标签页之间的通信,本质上都是通过中介者模式来实现的。因为标签页之间没有办法直接通信,因此我们可以找一个中介者,让标签页和中介者进行通信,然后让这个中介者来进行消息的转发。
使用
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; // 处理更新后的数据 } });
使用 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' });
使用 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' });
使用 WebSocket
WebSocket
协议可以实现服务器推送,服务器就可以用来当做这个中介者。标签页通过向服务器发送数据,然后由服务器向其他标签页推送转发。
Canvas 和 SVG
特性 | Canvas | SVG |
---|---|---|
渲染方式 | 逐像素绘制(位图) | 基于 XML(矢量图) |
缩放效果 | 可能失真(像素化) | 不失真,保持清晰 |
交互性 | 需要手动处理事件 | 直接支持 DOM 事件 |
适合场景 | 大量动态绘制,如游戏、数据可视化 | 复杂矢量图形,如图标、地图 |
- Canvas:适合高性能、频繁更新的图形,如动画、游戏、实时图表。
- SVG:适合静态或少量动态的矢量图,如图标、地图、流程图。
渐进增强和优雅降级
渐进增强:针对低版本浏览器进行构建页面,保证最基本的功能,然后再针对高级浏览器进行效果、交互等改进和追加功能达到更好的用户体验。
优雅降级:一开始就根据高版本浏览器构建完整的功能,然后再针对低版本浏览器进行兼容。
浏览器地址栏输入 URL 到页面渲染的整个流程
URL 解析:浏览器会对该 URL 进行解析,分析需要使用的传输协议和请求资源的路径。
缓存检查:检查本地缓存,如果存在缓存资源且未过期则直接使用,否则发起新请求。
DNS 查询:浏览器通过 DNS 解析器查询该域名对应的 IP 地址。如果 DNS 缓存中存在该域名对应的 IP 地址,则直接返回;否则,将请求发送到 DNS 服务器进行解析。
建立 TCP 连接:浏览器使用 HTTP 协议建立与服务器三次握手的 TCP 连接。在建立连接的过程中,如果是 HTTPS 协议,还需要进行 TLS/SSL 四次握手来确保通信安全。
发起 HTTP 请求:浏览器向服务器发送 HTTP 请求。
服务器处理请求:服务器接收到 HTTP 请求后,根据请求的 URL 和方法进行相应的处理。处理过程可能包括查询数据库、生成动态内容、读取静态文件等操作。
服务器响应:服务器处理完请求后,将相应的结果以 HTTP 响应的形式返回给浏览器。
接收响应:浏览器接收到服务器的响应后,开始解析响应。检查响应头中的 Content-Type,确定响应的数据类型(如 HTML、JSON、图片等),然后根据相应的数据类型进行相应的处理。
页面渲染:如果响应的是 HTML 类型的数据,浏览器开始解析 HTML,并构建 DOM 树。在构建 DOM 树的过程中,遇到外部资源(如 CSS、JavaScript、图片等)的引用,则会发起额外的请求获取这些资源。同时,浏览器还会解析 CSS,构建 CSSOM 树,并将 DOM 树和 CSSOM 树合并成渲染树。最后,浏览器根据渲染树进行页面渲染,呈现给用户。
断开连接:页面加载完成后,通过 TCP 四次挥手断开连接。
前端性能优化
前端性能优化是提高网页加载速度和用户体验的关键。需要根据项目的实际情况做相对应的优化,以下是一些常见的前端性能优化方案:
资源优化:
- 文件优化(多个文件合并为一个,JS/CSS 代码合并、压缩、拆分、按需加载、懒加载、预加载、异步加载)
- 图片优化 (选择适当的格式,如:WebP/AVIF/SVG、压缩、懒加载、预加载、雪碧图、base64)
- 图标优化 (iconify 按需加载)
- Tree-shaking 减小包体积
- 缓存优化(浏览器缓存,对常用不变的资源进行缓存、本地缓存,如:LocalStorage、SessionStorage、IndexedDB)
渲染优化:
- 减少 DOM 操作,避免重绘和重排
- 使用虚拟滚动和分页
- 骨架屏和占位 UI
- 优先显示关键内容
- 使用请求动画帧(requestAnimationFrame)
网络优化:
- HTTP/2 和 HTTP/3(减少网络请求的开销)
- 资源压缩 (Gzip/Brotli)
- CDN 加速
- 预连接 (preconnect)、预加载 (preload) 和预获取 (prefetch)
- 懒加载和按需加载
- 缓存策略
- DNS 优化(DNS 预解析、DNS 缓存)
运行时优化:
- Web Workers(处理密集计算和耗时长的任务,避免阻塞主线程)
- 防抖和节流
- 事件委托
- 编译优化 (AOT 编译)
服务端优化:
- 服务端使用 SSR(提前生成 HTML,减轻客户端渲染的负担)
- 服务端预渲染(预渲染关键页面,提高首屏加载速度)
- 响应资源压缩(接口响应启用 Gzip 等方式对传输的资源进行压缩)
这些优化方案是综合应用的结果,不同的项目和场景需要结合不同的优化策略。