前言
迷茫的时候,卷就是最好的选择;毕竟,与人斗其乐无穷。
本节主要对 HTML 标签使用进行介绍;掰头一下应用场景及最佳实践的思考;以及一些标签使用的问题总结。
另外,这里对元素和标签做一个释义,它们之间的区别在于元素一般是我们单独提及,如 p 元素;而标签则是在使用时通过闭合语法,如 <p></p>
就是指 p 标签。一般情况下,两者可以互通,即说标签也可以说元素也没问题。
文档声明
文档声明,告知浏览器以何种规范解析 HTML 和 CSS ;如果不指定或指定错误则默认以怪异模式解析;如果指定了标准,则根据指定的标准模式进行解析
html5 之后,应该始终使用最新的 DOCTYPE 值;注意:DOCTYPE 声明是大小写敏感的
html
<!DOCTYPE html>
早期也出现过的一些声明文档类型的值,用来告知浏览器 HTML 或 XHTML 的版本;也将会以标准模式解析
html
<!-- HTML 4.01 Strict -->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<!-- XHTML 1.0 Strict -->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
quirks 模式
根据浏览器自己的规范解析 HTML 和 CSS;好嘛,那就八仙过海,各显神通吧~同一套代码在不同浏览器上的解析效果必然是五花八门的
核心特性:盒子模型的宽度和高度通常包括边框和内边距;这种形式被称为怪异盒模型,是 IE8 以下的怪异模式下的解析形式
当然,除了早期的 IE8 浏览器行为特别怪异外;现代浏览器基本都开始遵循 HTML 和 CSS 规范,因为即使不设置 DOCTYPE,你会发现,差异也并不大;
standards 模式
浏览器会尽可能地遵守HTML和CSS规范,以确保页面的外观和行为符合预期;
盒模型
什么是盒模型?用来描述元素如何在网页上渲染的矩形盒子,包括 content、border、margin、padding
css 可以通过 box-sizing 来控制盒模型的方式,默认值为 content-box,即标准盒模型;设置 box-sizing: border-box;
则为怪异盒模型
content-box 与 border-box 的区别
content-box:设置内容的宽高即为渲染的宽高,padding、border 则会将元素撑开
border-box: padding、border 会占据内容的宽高
关于 border-box 思考
border-box 有时反而非常有用,由于 content-box 会受到 padding、border 的影响而撑开元素,很容易导致在弹性布局中导致宽度不够导致换行问题。如以下弹性布局中,使用 li 实现,对 li 设置 box-sizing: border-box; width: 50%;
即可实现弹性自适应
适用场景:
- 固定布局:让元素在固定大小的区域内保持一定的尺寸
- 弹性布局:让元素能够随着窗口尺寸的变化而改变尺寸;百分比布局也是如此,不需要考虑 padding、border 的影响
- 滚动条问题:避免滚动条影响元素的尺寸
figure 和 figcaption
figure 和 figcaption 并不是语义化标签 ,它们只是用来添加对外部资源或独立内容的描述,从而让搜索引擎更好的理解这一块内容,帮助 SEO ;同时 figure 标签具有默认的 margin,可以更好的帮助排版,无样式渲染等
html
<figure>
<img src="xxx.png" alt="logo"/>
<figcapition>fg1. learn site logo</figcaption>
</figure>
最佳实践:
figure 标签适合用来对图片、音视频、表格、代码块、诗句、文章等独立内容添加描述或标题(添加标题时 figcapition 在上);但它并不是语义化标签,不能用来替代 p、h、ul 这样的语义化标签;
即语义化标签优先,figure 后考虑;比如你的页面上只有一个表格,那么这个表格的标题,最好的选择是使用 h 标签;而某个局部独立区域的表格,才是使用 figure 标签的适用场景。
一个非常适用的场景就是如上图所示的一组图片 + 描述形式
代码呈现元素
figure 可以用来为代码添加描述或标题,那 HTML 中用来表示代码的元素你又了解多少?
- code,用来表示计算机代码,忽略格式
- pre,用来表示计算机代码,保留原始输入的所有空格和换行
- kbd,用来表示键盘输入内容,如快捷键
- samp,用来表示命令行命令的输出结果
- var,用来表示公式、变量中的字母;默认具有斜体字
html
<p>运行 npm run dev, 终端将输出:<samp>http://192.168.10.56:8899/</samp></p>
<p>表达式: <var>x</var> = <var>y</var> + 2 </p>
<pre>
function test() {
}
</pre>
<code>
function test() {
}
</code>
<p>快捷复制:<kbd>CTRL + C</kbd></p>
最佳实践:
- 代码呈现元素并不是语义化标签,只是用来强调文本;只是这些强调都和代码相关,更方便理解
- 键盘输入内容使用 kbd、公式变量使用 var、计算机代码一般需要保留格式使用 pre
- pre 标签是块级元素,具有
HTMLPreElement
DOM 接口,且具有默认的 margin;其他元素则大部分继承自HTMLSpanElement
,为行内元素 - var 元素的内容默认具有斜体,其他则是默认等高字体;可以通过 CSS 重置效果,一般是通过 reset.css 默认设置
文本强调元素
代码相关的强调,使用上述的代码呈现元素;除代码之外,HTML 还提供了一些其他的强调元素
- strong, 表示文本非常重要;默认具有加粗效果
- b, 表示相对于普通文本字体上的区别,但不表示任何特殊的强调;默认具有加粗效果
- em, 强调某个短语;默认具有斜体
- i, 表示从正常文本区分的内容;默认具有斜体
- mark, 标记状态的内容;默认具有高亮效果
真正具有强调含义的是 strong、em;b、i 不具有强调效果,只是语义化突出内容
b vs strong
两者都默认具有加粗效果
strong 标签表示严重强调内容 ,常用来强调重要语句;只是它默认是加粗的,这个强调效果可以是红色、下划线、背景色等等;
b 则是用来语义化表示突出的文字,不具有强调效果;如产品名、人物名、关键字
如果只是为了单纯的加粗引起注意,请使用 font-weightL bold;
进行加粗
em vs i
两者都默认具有斜体效果
em 表示强调内容,通常用来强调短语;如需要着重标识的单词,如搜索引擎的关键字就是使用 em 实现的
i 则用来语义化从正常内容中突出文字,如科学术语、化学方程、旁白、说明、书籍名、电影名等
em vs mark
mark 用来突出显示的文本通常是外部引用的文本,或者标记成特殊审查的内容;具有高亮效果
不要为了语法高亮而使用 mark 标签;你应该用 strong 元素来实现这个目的(语法高亮)
mark 一定是具有特殊标记、外部引用 等内容突出效果时使用;即必须与正常内容产生关联性时
label 解决可访问性问题
表单图标如 radio、checkbox 可点击区域非常小,很容易点不中
html
<!-- 方案1:单独包裹 -->
<label>
扩大区域
<input name="input" type="checkbox" />
</label>
<!-- 方案2: for + id 关联 -->
<label for="test2">
扩大区域
</label>
<input name="input" type="checkbox" id="test2" />
<!-- 方案3:双管齐下 -->
<label for="test3">
扩大区域
<input name="input" type="checkbox" id="test3" />
</label>
通过 label 包裹后,就可以扩大点击区域,如上,点击扩大区域
文本也会切换 checkbox 的选择;
理论上,直接通过 label 包裹就可以生效、使用 for + id 关联单独就可以生效;如上述代码方案1、方案2;但为了兼容性,推荐使用方案3,双管齐下
label 除了扩大点击区域,也常用来实现一些自定义的组件样式,如下,是一个 label + 隐藏的文件选择空间;我们只需要控制 label 的样式即可
html
<label for="fileInput">选择文件</label>
<input type="file" id="fileInput" hidden>
area 元素的应用
area 元素用来标记图片的热点区域,一般配合 map 使用,可以通过 TAB 检索 area 查看形状;这在电子邮件场景下非常有用,因为邮件不支持复杂的布局(支持 table)
html
<img src="mm1.jpg" alt="美女" usemap="#MM">
<map id="MM" name="MM">
<area shape="rect" coords="20,20,80,80" href="#rect" alt="矩形">
<area shape="circle" coords="200,50,50" href="#circle" alt="圆形">
<area shape="poly" coords="150,100,200,120" href="#poly" alt="多边形">
</map>
- shape,表示热点的形状,支持矩形rect,圆形circle以及多边形poly
- coords,热点形状区域坐标
- href,跳转链接,area 可以看做半个 a 标签
- target,同 a 的 target 属性,控制链接打开方式
- alt 同图片的 alt,表示热点区域的描述信息
area 解决 a 标签嵌套问题
a 标签无法嵌套,即使你改变为 block 布局,依然会造成渲染错误
为啥需要 a 标签嵌套?
好像咱们正常情况下,a 标签内部就不应该有内容可以点击跳转吧?是的,正常不应该有,但有一种场景,就是埋点热力图分析;a、input 默认具有热力图分析功能,外层的 a 不设置跳转,内层各区域跳转
模拟 a 标签
当一个块级 a 内部还有一个模块可以跳转时,使用普通的 span 等元素模拟,
- 1、需要通过 click 事件处理;
- 2、模拟时还需要考虑 tabindex、role 等无障碍访问;
- 3、然后还需要阻止外层 a 的访问事件,即需要阻止事件冒泡,不然会有两个跳转
使用 area
使用 area 则天然的不需要阻止冒泡、设置 tabindex、role;完美的解决 a 标签嵌套问题
元素嵌套问题
HTML 对于元素的嵌套有一定的限制,目的是为了保证元素功能及其语义;更多的是一种强制的记忆,熟悉标签的使用规则,这也是早期 div 布局横行的原因之一,用 div 来组织文档结构,根本不存在这些所谓的嵌套问题
同时,应该尽可能减少嵌套层级,影响页面性能和爬虫读取
思考
现在常用的 flex 布局,让嵌套层次越写越深...
a 内部不能嵌套 a、input、select
原理也简单,a、input、select、button 它们都有自己的行为;一旦 a 标签内部嵌套了这些标签,容易引起行为或功能的混乱
p 标签不允许嵌套块级标签
如 p、h、header 等;均不能嵌套在 p 标签内部
原理也简单,p 标签用于表示一个段落,那段落里怎么能又放一个段落呢?这在本质上就是违反语义的,段落里不会再有段落了,只能有文本呈现元素
detail 元素展开收起
html
<details>
<summary>详情</summary>
我是具体描述
</details>
html5 提供 details、summary 来实现展开收起行为(三角图标+描述,点击 toggle 展开收起)
- details 标签内放详细描述的内容,默认收起,可以通过设置 open 属性默认展开
- summary 用来设置具体描述 slot,缺省时展示"详细信息"
- 我们可以重置 summary 的三角形等样式,而不需要额外的 js 代码来实现展开与收起功能
思考
好像没有办法实现点击时切换 summary 里面文案,如展开/收起这样的效果?伪类 + content + attr 也控制不了;so,大概率还是得 js 来
可访问性 fieldset 和 legend
表单元素之间默认并没有关联。当我们有一组如省市区的选择表单时,无障碍用户并不知道它们之间有关联
我们可以将多个有关系的表单放到 fieldset 元素内部,legend 标签则表示这个组的标题
适用于有关联多个表单,通过 fieldset 包裹,legend 描述信息:
- 多个有关系的单选按钮(是否)
- 省市区等多个有关系选择框,legend 就可以是"收货地址"这样的文字
html
<fieldset>
<legend>收货地址:</legend>
<span>省</span>
<select>
<option>测试省</option>
</select>
<span>市</span>
<select>
<option>测试市</option>
</select>
<span>区</span>
<select>
<option>测试区</option>
</select>
</fieldset>
最佳实践:
- 使用时避免过度嵌套;同时如果是单个表单,不要使用
- 尽量使用 label 标签来标记每个控件,以便更好地理解和使用表单
- 只用来包裹 input、select、button 等元素
HTMLUnknownElement 与 customElement
HTMLUnknownElement:规范以外的标签元素,不能是短横线命名规则(短横线命名规则的是自定义元素)
- 例如 HTML5 已经不在支持 font 这样的标签,如果你在页面中使用,那它就是一个未知元素
- 或者你随便写的一个元素,只要不是短横线命名,如
<username></username>
检测是否为未知元素:document.createElement('username') instanceof HTMLUnknownElement === true;
customElement
customElement 是 web components、shadow DOM、Vue 模板的核心;必须满足短横线命名规则;
创建时的两个核心:
- 继承 HTMLElement、HTMLFormElement、HTMLDivElement、HTMLSpanElement 等类声明的自定义类
- 通过 customElements.define('custom-ell', HTMLCustomElement);
一个完善的自定义元素模版;大致理解即可,想要深入掌握,在 shadow DOM 中再做分析
picture 标签
picture 本身是一个很实用的标签,常用来在不同场景使用不同图片;但由于语义化开发并没有太多人关注,且存在替代方案,所以使用的人一直不多
使用场景
- 不同尺寸屏幕显示不同图片
- 不同浏览器显示不同后缀图片
[重要]渲染的时候,浏览器优先使用顺序使用 <source>
元素,<img>
元素兜底
不同尺寸屏幕显示不同图片
html
<picture>
<source srcset="../../statics/images/learn/html_good.png" media="(min-width: 640px)">
<source srcset="../../statics/images/learn/html_bad.png" media="(min-width: 800px)">
<img src="../../statics/images/learn/layout.png">
</picture>
上述效果,也可以通过 css 媒体查询实现
不同浏览器显示不同后缀图片
比如说我们期望使用 avif、webp 等更小,压缩效果更好的图片格式,怎么实现优雅降级呢?
一种方式是通过判断兼容性,采用不同的格式;
另一种就是通过 picture 标签,由于它渲染时会优先按顺序解析 source 元素的图片格式,然后 img 标签兜底
当然,终极的方案是交给云服务厂商处理的,通常 COS 服务支持通过配置进行图片优化,直接处理所有图片,完全不用一个一个手动转格式
template 元素
template 中的内容不会渲染,提供了一种可复用内容的方式,使用方式
- 1、
<script type="text/template"></script>
非标准的方式 - 2、内容放到 textarea 标签,设置 display: none;
- 3、
<template></template>
推荐
template 标签内容默认是隐藏的;且可以放在任意位置,如 style、script、div 等标签
思考
上述 3 种方案,本质都是在页面上放置隐藏元素;这是不利于 seo 的;早期,为了更好的 seo,开发者经常通过隐藏元素来提升页面的权重,搜索引擎有一套完整的算法可以针对这部分内容进行有效识别,防止作弊,反而会影响 seo 效果
因此,针对现代的搜索引擎,最好不要带有隐藏的元素,防止被误认为作弊(如果一定需要有,放在页面底部)
子元素无效性
template.content 返回一个 document fragment,所有子节点的查询、处理均需要通过 template.conent 操作
js
// 无效
document.querySelect("#myTemplate").querySelector("h2")
// 获取到 template 的 h2
document.querySelect("#myTemplate").content.querySelector("h2")
应用
- 预设数据,如某段 html、css,只在特定的条件启用
- 延迟加载,将页面上暂不需要的内容放在 template 中,在需要的时候才追加到文档中渲染
- 作为模板引擎,动态生成内容
meter 元素
meter 的意思是计量表,在 Web 中,任何与丈量有关,需要分阶段提示的场景,都非常适合 meter 元素
特性&使用
meter 具有最多三种效果,正常状态的绿色UI、警戒状态的橙色 UI、危险状态的红色 UI
非常适合例如剩余油量、温度、降雨量、游戏中人物血量、强中弱三级密码强度等等场景
html
<meter min="0" max="100" low="30" high="60" optimum="80" value="20"></meter>
- min、max 表示数值范围,默认为 0-1
- low、height 表示警戒值,low 表示低警戒值,height 表示高警戒值
- value 表示当前值,默认为 0
- optimum 属性表示最佳值,用来决定过低和过高值属于正常还是异常
关于 optimum
- 如果 optimum 唯一 low - height 中间,则低于 low 或高于 height 都是警戒状态,low - height 之间为正常状态
- 如果 optimum 小于 low,那么会有三种状态,低于 low 正常,low - height 警告,高于 height 危险
- 如果 optimum 大于 height,那么会有三种状态,高于 height 正常,low - height 警告,低于 low 危险
iframe
iframe 是 HTML 提供用来在文档中嵌入另一个文档的内联框架
优点:
- 可以用来解决加载缓慢的第三方内容,如客服、广告等
- 异步加载,iframe 动态设置 src 可以实现异步加载内容,提升性能
- 可以用来解决跨域通讯问题:domain + iframe,但目前 Chrome 已经开始限制 domain 的设置,只允许读取,建议更换为 postMessage 的形式
缺点:
- 每个 iframe 都需要进行一次 HTTP 请求,从而增加了页面加载时间
- iframe 会阻塞主页面的 onload 事件(可通过上述动态设置 src 解决)
- SEO 不友好,无法被爬虫爬取
结束语
作为一个油盐不进的爱卷人士,这当然不是一个结束,后续将会持续进行更新。To Be Continue...