HTML 指南
本文档用于梳理 HTML 的重难点知识,用于复习巩固, 也用于面试谈经。
HTML 入门
官方文档:developer.mozilla.org/zh-CN/docs/…
HTML 元素
1 meta 元素
meta 元素用于定义浏览器的元数据(描述数据)。
在 meta 元素中,可以指定 SEO 相关的数据:Keywords - 关键字、description - 网页描述信息,比如:
<meta name="Keywords" content="React,Vue">
<meta name="description" content="The MDN Web Docs .." />
在 meta 元素中,可以指定 CSP(内容安全策略),比如:
<meta
http-equiv="Content-Security-Policy"
content="default-src 'self'; img-src https://*; child-src 'none';" />
其中,CSP 用于在 HTML 中限制内容(资源文件)的访问域名和运行方式,从而检测并削弱 XSS(跨站脚本)和数据注入等攻击。
在 meta 元素中,可以实现重定向,比如:
<head>
<meta http-equiv="Refresh" content="0; URL=http://example.com/" />
</head>
在 meta 元素中,可以指定浏览器窗口大小,比如:
<meta name="viewport" content="width=device-width, initial-scale=1" />
其中,"width=device-width" 代表浏览器窗口大小等于浏览器分辨率,"initial-scale=1" 代表页面的初始化缩放比例为 1。
注意:
- 在 PC 端,浏览器窗口大小默认等于浏览器分辨率;在移动端,浏览器窗口大小默认不等于浏览器分辨率,所以需要进行指定。
- user-scalable 属性用于控制界面缩放,但是实际测试后发现没有效果。
2 script 元素
script 元素用于执行内部 JS 代码,或者加载外部 JS 文件,示例:
<script src="./tool.js"></script>
<script>
console.log('测试');
</script>
2.1 ES module
在 ES6 中,浏览器支持 ES module,通过 import 和 export 语法加载模块。在浏览器中使用 ES module,需要指定 script 元素的 type 为 module,示例:
<script type="module" src="./tool.js"></script>
<script type="module">
import {test} from './tool.js';
test();
</script>
2.2 async 与 defer 属性
async 与 defer 属性用于将 JS 文件变成非阻塞资源,从而加快浏览器的解析。
async 与 defer 属性有以下区别:
- async 脚本的执行顺序由网络响应的顺序决定;defer 脚本的执行顺序由 HTML 中的顺序决定。
- async 脚本不会阻塞 DOMContentLoaded 事件;defer 脚本会阻塞。
注意:
- 模块脚本(type="module" 的脚本)默认相当于 defer 脚本,添加 async 属性后会变成 async 脚本。
- JS 文件作为阻塞资源的意义在于,防止 JS 修改 Dom 导致的界面重绘。如果需要将 JS 文件通过 async、defer 属性变成非阻塞资源,那么 JS 文件中最好不要修改 Dom,或者将修改 Dom 的代码单独提出来。
3 form 元素
forrm 元素一般用于提交用户信息。
3.1 表单提交
表单提交有两种方式:
- HTML 方式:点击 submit 类型的按钮时,自动根据 form 的 action 属性提交请求。注意:按钮的类型默认为 submit 。
- JS 方式:点击按钮时,先通过 e.preventDefault() 阻止 HTML 方式的提交,然后使用 AJAX 提交请求。
两种提交方式的区别:
- HTML 方式会跳转页面;JS 方式不会跳转页面,而是局部更新 DOM。
- HTML 方式发送的数据由表单决定;JS 方式发送的数据可以完全自定义。
- HTML 方式没有同源限制;JS 方式有同源限制。
- HTML 方式更加简单;JS 方式相对复杂。
3.2 表单校验
表单校验用于验证用户输入的数据是否正确,也用于保护网站安全。
为了用户的体验,表单校验需要遵循以下规范:
- 显示明确的错误消息。
- 放宽输入格式限制。
- 指出错误发生的位置(特别是在大型表单中)。
3.3 文件上传
表单可以上传文件,只序进行以下设置:
- input 元素指定 file 类型
- Content-Type 指定 "multipart/form-data"
如何指定 Content-Type?
- 在 HTML 方式中,通过 form 的 enctype 属性指定
- 在 JS 方式 中,通过请求头的 Content-Type 指定
3.4 表单安全
常见的表单安全问题:
- XSS(跨站脚本)攻击:向网页中插入恶意脚本代码。说明: 目前的浏览器已经能够过滤 XSS攻击。
- CSRF(跨站点请求伪造)攻击:利用用户的登录信息执行不安全的请求。应对方案: 通过 SameSite 禁止跨站获取 Cookie。
- SQL 注入:向服务端中插入恶意的 SQL 代码。应对方案: 对特殊字符进行转义。
对于表单安全,有一些通用的解决方法:
- 对特殊字符进行转义
- 对于输入内容的长度、格式进行限制。
- 沙箱上传文件:将文件保存在专门的服务器中,防止有毒的文件感染主服务器。
4 input 元素
input 元素也叫输入框,一般用于录入用户信息。
4.1 input 的类型
input 的类型非常多,几乎可以实现任何功能。按照功能,可以对它进行以下分类:
-
基本类型:
- 文本:type="text",用于文本编辑。
- 密码:type="password",用于密码编辑
- 隐藏:type="hidden",用于数据占位。
-
选择类型:
- 单选:type="radio",用于单选框。
- 多选:type="checkbox",用于多选框。
-
按钮类型:
- 按钮:type="button",用于普通按钮。
- 提交:type="submit",用于表单提交按钮。
- 重置:type="reset",用于表单重置按钮。
-
校验类型:
- 数字:type="number",用于表单提交时的数字校验。
- 号码:type="tel",用于表单提交时的号码校验。
- 邮箱:type="email",用于表单提交时的邮箱校验。
- 网址:type="url",用于表单提交时的网址校验。
-
日期类型:
- 日期和时间:type="datetime-local",用于日期和时间选择。
- 日期:type="date",用于日期选择。
- 时间:type="time",用于时间选择。
- 月:type="month",用于月份选择。
- 周:type="week",用于周选择。
-
其它类型:
- 图片:type="image",用于图片展示。
- 文件:type="file",用于文件选择。
- 查询:type="search"。查询类型在输入时,会显示关闭按钮,点击关闭按钮,会清空输入框数据。
- 滑块:type="range",用于滑块展示。
- 颜色:type="color",用于颜色选择。
4.2 自动填充
浏览器默认会自动填充输入框的用户名和密码,如果想禁止这种行为,需要对密码框设置 autocomplete=“new-password”,比如:
<input type="password" autocomplete="new-password"/>
5 img 元素
img 元素属于替换元素(内容和尺寸由外部资源决定的元素),用于展示图片,
5.1 响应式图片
在小屏手机上加载大图片时,会浪费宽带。可以通过响应式图片,来解决这个问题。
创建响应式图片有两种方式:根据尺寸、根据像素比。
第一种是根据尺寸进行创建,在 img 中指定 srcset 和 sizes 属性,比如:
<img
srcset="elva-fairy-480w.jpg 480w, elva-fairy-800w.jpg 800w"
sizes="(max-width: 600px) 480px, 800px"
src="elva-fairy-800w.jpg"
alt="Elva dressed as a fairy"
/>
其中,srcset 表示可选图片的 URL 和尺寸,sizes 表示可选媒体条件和预期图片宽度。浏览器会根据窗口大小和 img 的 sizes 属性获取预期图片宽度,然后从 srcset 中选择最接近的图片。
注意:在谷歌浏览器上调试时,需要禁用缓存,否则修改视口宽度时,图片不会切换。
第二种是根据像素比进行创建,在 img 中指定 srcset 属性,在 srcset 中指定像素比,比如:
<img
srcset="elva-fairy-320w.jpg, elva-fairy-480w.jpg 1.5x, elva-fairy-640w.jpg 2x"
src="elva-fairy-640w.jpg"
alt="Elva dressed as a fairy"
/>
其中,srcset 中的 x 代表像素比(可以通过 window.devicePixelRatio 获取)。根据像素比这种方式一般用于移动端,因为 PC 端的像素比固定为 1。
6 video 元素
video 元素属于替换属性,用于播放视频。
6.1 自动播放
出于用户体验的考虑,浏览器禁止了自动播放。但是不是完全禁止,无声的自动播放还是支持的。比如:
<video src="movie.webm" controls autoplay muted></video>
7 iframe 元素
iframe 元素用于加载其他 HTML 页面。
7.1 X-Frame-Options
X-Frame-Options:HTTP 响应头,用于标记网页在 iframe、embed、object 元素中的展示方式,从而避免点击劫持攻击。
X-Frame-Options 的可选值如下:
- DENY:不允许在 frame 中展示
- SAMEORIGIN:只允许在相同域名的页面中展示。
8 svg 元素
svg 元素用于展示矢量图。
8.1 svg 的使用方式
在 HTML 中使用 svg 时,有两种方式:
第一种,直接使用 svg 元素。
第二种,在 img 或 iframe 元素中引用外部的 svg 文件
在 CSS 中使用 svg 时,有三种方式:
第一种,使用 CSS 的 mask 属性展示 svg 中的 mark 元素,用于实现遮罩效果
第二种,使用 CSS 的 clip-path 属性展示 svg 中的 clipPath 元素,用于实现裁剪效果
第三种,使用 CSS 的 filter 属性展示 svg 中的 filter 元素,用于实现滤镜效果
8.2 svg 的优缺点
svg 的优点:
- 高保真:放大后不模糊
- 体积小:仅需储存少量的算法,而不是每个像素的信息
- 可编辑:可以在 HTML 中直接编辑,而不需要通过图片编辑器
- 可访问:svg 中的文本可以被访问,有利于 SEO
svg 的缺点:
- 无法产生色彩艳丽、复杂多变的图像。
9 文本元素
一些不常见但是有用的文本元素如下:
- sup :用于展示上标,比如:平方的符号
- sub :用于展示下标,比如:二氧化碳的符号
- del:用于展示文字的中划线。
- ins:用于展示文字的下划线。
- pre:用于保留空白字符。
- kbd:用于展示电脑的按键。
- code:用于展示计算机代码,一般在 pre 元素内部使用。
如果想展示隐藏内容(鼠标放入时会自动展示内容),可以使用 title 属性。
HTML 属性
1 crossorigin 属性
crossorigin 属性定义 link / script / img / video / audio 元素如何处理跨源请求。注意:处理跨域请求还需要服务端设置合适的 CROS 响应头。
crossorigin 属性具有以下可能的值:
- anonymous:不需要身份验证,就能跨源下载
- use-credentials:需要经过身份验证,才能跨域下载。
- 空值:等同于设置 anonymous 。格式:
crossorigin或crossorigin=""。
一般情况下,不需要指定 crossorigin 属性。但是在以下场景中使用跨域资源时,不指定 crossorigin 属性会遇到问题:
| 元素 | 限制 |
|---|---|
| img、audio、video | 当资源被放置在 canvas 中时,元素会标记为被污染的。 |
| script | 对错误日志 window.onerror 的访问将会被限制。 |
| link | 使用了不合适的 crossorigin 标头的请求可能会被丢弃。 |
2 数据属性
数据属性就是 data-* 属性,允许我们在标准内于 HTML 元素中存储额外的信息,比如:
<div id="data" data-columns="3" data-index-number="12314">测试</div>
数据属性可以通过 JS 访问,比如:
<script>
let data = document.querySelector('#data');
console.log(data.dataset.columns); // 3
console.log(data.dataset.indexNumber); // 1234
</script>
数据属性可以通过 CSS 访问,比如:
<style>
div::before {
content: attr(data-index-number);
}
</style>
HTML 机制
1 浏览器的运行流程
浏览器网页的运行流程,从逻辑上可以分为以下五步:
- 发送请求
- 下载文件
- 解析文件
- 渲染页面
- 用户交互
注意: 实际的运行流程中,有些步骤是并行的,这里只是为了方便讲解,才采用串行的方式。
1.1 发送请求
打开网站的步骤如下:
- 用户在浏览器上输入 URL(网址)
- 浏览器校验 URL 格式并获取域名
- 浏览器通过 DNS 解析域名,从而获取 IP 地址
- 浏览器通过三次握手与服务器建立 TCP 连接
- 浏览器通过 TLS 协商与服务器建立安全(基于 HTTPS)的连接
- 浏览器向服务器发送 HTTP 请求(一般是通过 GET 方式请求 HTML 文件)
1.2 下载文件
下载文件的步骤如下:
-
浏览器收到服务器返回的 HTML 文件后,就开始下载 HTML 中的资源文件,分为两种情况:
-
第一种是高级资源(html、css、font、js等),使用预加载扫描器在后台下载
- 预加载扫描器扫描到 HTML 中的外链资源时,就按照优先级创建请求对象放入请求队列中
- 预加载扫描器同时从请求队列中取出高优先级的请求对象,放入下载队列(最多六个下载任务)中开始下载。
- 当下载队列出现空闲时,预加载扫描器再次从请求队列中取出高优先级的请求对象进行下载。
-
第二种是低级资源(image、vedio、audio等),当解析器解析到该资源时开始下载。由于 js 会阻塞 HTML 的解析,所以低级资源会在所有的 js 文件下载后开始下载。
在同一个请求队列中,请求对象的优先级由资源文件的默认优先级决定,具体规则如下:
- 高等:html、css、font、同步请求
- 中等:js、ajax
- 低等:manifest、preload 资源
- 更低:image、vedio、audio
- 最低:prefetch 资源、defer 资源。
注意:
- 下载资源的顺序由资源在 HTML 中的位置和默认优先级共同决定。在 body 中加载 js、css 时,它们的下载顺序由 HTML 中的位置决定。
- TCP 传输时,第一个数据包为 14 KB,后面的数据包依次倍增。如果 HTML 文件大于 14 KB,那么浏览器收到第一个数据包后也会对其解析。
- 浏览器为每个域名最多建立 6 个 TCP连接,如果尝试大于这个数字,就有触发服务器 DoS 保护的风险。所以,下载队列中最多只能放入六个请求对象。
- prefetch 资源会在浏览器空闲时下载,用于后续页面的预加载;preload 资源用于当前页面的预加载。但是在最新版本的谷歌浏览器中测试发现,preload 并不能提高资源的优先级。
1.3 解析文件
解析文件是将资源文件转化为 DOM 和 CSSOM 的过程,解析过程分为以下部分:
-
构建 DOM 树:
- 浏览器收到 HTML 文件后,解析器就开始解析 HTML 的元素并按照树形结构创建 DOM 树
- 解析器遇到非阻塞的资源文件(比如:图片、CSS 文件)后,就继续解析,同时下载低级资源。
- 解析器遇到阻塞的资源文件(比如:JS 文件)后,就等待资源文件下载、解析并执行后,继续解析。
- 当 HTML 元素解析完了,DOM 树就构建好了。
-
构建 CSSOM 树:
- 当 CSS 文件下载后,解析器就开始解析它,并创建 CSSOM 树
- 解析器遍历 CSS 中的每个规则集,根据 CSS 选择器创建具有父、子和兄弟关系的节点树。
- 当 CSS 的规则集解析完,CSSOM 树就构建好了。
-
JS 编译:
- 当 JS 文件下载后,会被解析成抽象语法树
- 浏览器引擎会将抽象语法树传给解释器,输出在主线程上执行的字节码
1.4 渲染页面
渲染页面的步骤如下:
-
计算样式:所有节点的最终样式。
- 当所有的 CSS 文件解析完,就开始渲染并创建 Render(渲染) 树。此时,DOM 树如果没有解析完,就继续并行解析。
- 遍历 DOM 树,找到非隐藏元素加入 Render 树中
- 遍历 Render 树的节点,根据其 style 属性和 CSSOM 树中的样式,确定节点的最终样式
-
确定布局:确定所有节点的大小和位置。
- Render 树从根节点开始遍历
- 根据当前节点及其子节点的最终样式,确定当前节点的大小和位置。
- 如果遇到未定义尺寸的替换元素(比如:图片),就先给给它提供占位空间。
- 当前所有节点的大小和位置确定好,布局就确定好了。
- 如果样式发生了变化(比如:图片的大小确定了),就会修改节点的大小和位置,这个过程叫作回流。
-
绘制页面:将布局后的每个节点换为屏幕上的实际像素
- 如果 HTML 中不包含 video 和 canvas 元素,那么就直接将所有节点绘制到屏幕中
- 如果 HTML 中包含 video 和 canvas 元素,那就 video 、canvas、其他节点分为多个层,每个层单独绘制,最后合成到一起。
注意:
- CSS 文件决定了元素的样式和布局,所以要等到所有 CSS文件解析完,才开始渲染。
- 为了不造成卡顿,包括计算样式、回流、绘制的渲染过程,需要在 16.67 毫秒内完成。
1.5 用户交互
用户交互:
- 当页面渲染完成,用户就可以看到完整的页面了
- 当 JS 执行完成后,用户就可以进行交互了,因为 JS 的执行会阻塞浏览器主线程。
2 分辨率与像素比
浏览器展示内容的大小跟以下内容有关:
- 设备分辨率:设备的屏幕像素宽高。例如,vivo X21 的设备分辨率是:2280x1080 像素
- 浏览器分辨率:设备在展示浏览器页面时,使用的屏幕像素宽高。例如,vivo X21 的浏览器分辨率是:760x360 像素。
- 浏览器窗口大小:浏览器实际展示内容的像素宽高。例如,vivo X21 的默认浏览器窗口(也叫虚拟窗口)大小是:1693 x 980 像素。
- 像素比(drp): 设备分辨率 / 浏览器分辨率。例如,vivo X21 的像素比是 3x。
在 PC 端,浏览器分辨率与设备分辨率相同;在移动端,浏览器分辨率与设备分辨率不同,因为移动手机的高分辨率是为了展示高清图片,如果用这么高的分辨率展示浏览器页面,那就会看不清。
在 PC 端,浏览器的默认窗口大小跟浏览器分辨率一致;在移动端,虽然对浏览器分辨率做了优化,但是浏览器不清楚实际的展示内容,所以默认窗口大小跟浏览器分辨率不一致。例如,vivo X21 默认使用 1693 x 980 的窗口大小渲染页面,然后页面将缩小以适应 360px 的空间。
浏览器的分辨率可以通过 JS 查看:
let width = window.screen.width; // 屏幕的宽度
let height = window.screen.height; // 屏幕的高度:包含电脑底部任务栏的高度
let availWidth = window.screen.availWidth; // 屏幕的可用宽度
let availHeight = window.screen.availHeight; // 屏幕的可用高度:不包含电脑底部任务栏的高度
浏览器的窗口大小可以通过 JS 查看:
let clientWidth = document.documentElement.clientWidth; // 浏览器的窗口宽度
let clientHeight = document.documentElement.clientHeight; // 浏览器的窗口高度:不包含浏览器的标签栏
let scrollWidth = document.documentElement.scrollWidth; // 浏览器的窗口滚动条宽度
let scrollHeight = document.documentElement.scrollHeight; // 浏览器的窗口滚动条高度
像素比可以通过 JS 查看:
let drp = window.devicePixelRatio; // 像素比