前言
迷茫的时候,卷就是最好的选择;毕竟,与人斗其乐无穷。
本节主要对 HTML 属性使用进行介绍;主要包括可访问、SEO、性能优化等相关内容;同时会梳理应用场景及最佳实践的思考;
data-* 自定义属性
html
<div id="test" data-index="1">test</div>
自定义属性获取:
- 1、推荐
document.querySelector('#test').dataset.index
- 2、通过属性获取
document.querySelector('#test').getAttribute('data-index')
最佳实践:
data-*
属性都应该以data-
开头,然后跟上一个唯一的名字,中间不能有任何空格- 避免存储大量的数据,以免增加页面的体积和下载时间;如果有大量数据需要存储,请使用 Web Storage
无障碍应用相关属性
无障碍(accessibility),也被称为可访问性,所谓的无障碍,并不是狭义的为盲人等提供基础的产品访问能力;
无障碍访问指单独使用例如鼠标、键盘、读屏软件或设备等均可访问(如鼠标坏了、键盘坏了、鼠标键盘都坏了只有麦克风);上述异常场景的适配和支持,就属于无障碍访问的范畴了
无障碍访问一直是国内站点所忽略的存在,包括国内的一线大厂;反而是一些外网如 github、Facebook 具有较好的支持;当然这也很能理解,毕竟,国内现在的盲道也是走不通的;
前段时间,刷到一个制作脚踏板的博主,只是为了让部分有缺陷的人可以在玩英雄联盟的时候可以通过用脚来释放闪现;曾经常开玩笑队友是用脚玩的我,深受触动~
我辈程序员,当有这样的责任;对网页的无障碍支持,实在不是一件费时或困难的技术,举手之劳,还能让网页提升排名(可访问性能帮助机器引擎理解网页)
role
指定元素充当的角色,如 div 模拟 button、或者本身就是 button,就可以设置 role="button";这样即使是屏幕阅读器,也能知道这个元素的作用;参考文档,常用的属性有:
- button 按钮、img 图片、input 输入框、link 链接、radio 单选按钮、checkbox 多选框等 HTML 语义化标签相关
- grid、gridcell、main、nav、section 等布局相关
- listbox 、list、menu、menuitem、dialog、tooltip 等具有明确作用的内容角色声明
- presentation、none,取消元素角色
需要明确的一点是,部分内容即使没有角色声明,浏览器和其他辅助技术也可以识别链接、交互行为等手段提供相应的功能;但我们始终推荐正确的设置 role,以更好的帮助辅助设备识别
下图为 github 对于 role=*
的使用,在自定义弹窗时使用 dialog、模拟按钮时使用 button、提示工具栏使用 tooltip;
最佳实践:
- 一般情况下用来在普通标签来模拟语义化标签时;如自定义的弹窗
role="dialog"
;div 模拟的按钮role="button"
- 对于语义化的标签,不应该再使用 role 重复指定角色;如 button 按钮不再需要
role="button"
; - 对于 ul,它默认具有列表的语义;但我们又经常用 ul 来模拟菜单、导航等,因此会指定 role 为 listbox、menu、nav 以明确其具体的用处
- presentation 用来指定元素不具有语义化;如 div、li 具有点击等交互,为避免辅助设备错误识别,使用
role="presentation"
告知其不具有语义 role="none"
与 presentation 基本一致,上述场景也可以使用;但如果是语义化元素,如 a 标签,只用来做热力图,并不具有 a 的语义,此时则需要设置role="none"
不能使用role="presentation"
来取消语义
aria-*
aria-* 属性用于为网页中的元素提供更多的语义信息,从而使屏幕阅读器等辅助技术可以更好地理解它们的功能和用途;参考文档,常用的属性有:
aria-label 和 aria-labelledby
主要用来为元素添加明确描述内容
aria-label 的使用场景:
- 图片 button 无文本时,添加 aria-label 描述按钮的作用
- a 链接内部无文本(如图片链接)或文本与链接不相关时;如页面 logo 图标点击跳转首页,那么此时需要设置
aria-label="home-page"
- 为元素指定用途说明,如导航栏、图片等,可以通过 aria-label 描述其具体的作用
注意:对于 img 元素。应使用 alt 属性来指定图片的描述
aria-labelledby 与 aria-label 的使用场景基本一致,只是它是通过关联元素的 id 来指定描述内容
html
<h1 id="header">Hello World</h1>
<button aria-labelledby="header">
<img src="icon.png">
</button>
最佳实践:如果描述内容在页面上有现有的标签;优先使用 aria-labelledby 关联元素 id
元素状态描述
aria-readonly、aria-required、aria-disabled、aria-hidden、aria-checked 等用来描述元素的状态,如页面上的隐藏元素,需要设置 aria-hidden="true"
以上为 github 对于 aria-* 的使用,主要用在 aria-label、aria-labelledby 和元素状态描述
tabindex
tabindex 设置是否可以被 TAB 键检索,默认的 a、button、input 可以被检索,在无鼠标时依然操作自如
tabindex 的值越大,元素越先收到焦点;当你想让某些元素优先于其他元素接收焦点时,可以设置 tabindex 的值大一些,这样它就会优先被检索
最佳实践:
- 一般情况下,设置 tabindex=0 即可让元素可以被检索;除非你想要优先聚焦,否则不会设置大于 0;
- 可以通过 tabindex="-1" 来取消 a、button 的默认检索行为;如 a、button 只用来做热力图或布局时
rel 属性常用释义
rel 专门用来连接相关元素之间的关系,可以用在 a、area、form、link 等元素上(主要是 a)
rel 属性在 SEO、性能优化、行为控制有非常广泛的运用
SEO 相关
rel="alternate"
alternate 是交替、替换,标识链接有替换内容
可以用来告知 SEO、屏幕阅读器有 H5 端
html
<link rel="alternate" media="only screen and (max-width: 640px)" href="https://m.xxx.com/" />
用在 link 标签中,与 media 配合,告知用户有 H5 站点
rel="alternate" 定义网站的替换样式
html
<link href="default.css" rel="stylesheet" type="text/css" title="默认">
<link href="red.css" rel="alternate stylesheet" type="text/css" title="红色">
<link href="green.css" rel="alternate stylesheet" type="text/css" title="绿色">
这里有个非常有趣的特性,那就是 rel="stylesheet"
的 <link>
如果有 title
属性并有值,性质上就变成了一个可以控制其渲染或者不渲染的特殊元素了。(没有 title 或 alternate 默认会加载并渲染)
上述 3 个 css 文件均会加载,但 red.css 和 green.css 的优先级为 Lowest
, 即在空闲时加载,这样不会影响页面性能
使用时,切换 disabled 即可,例如要启用红色的皮肤样式,其他的设置 disabled 为 true,红色的设置 disabled 为 false(注意 disabled 为 DOM 属性,link 标签上没有这个属性)
js
document.querySelector('link[href="red.css"]').disabled = false;
注意,直接设置在 link
alternate 控制主题切换语义非常好。搜索引擎或者其他辅助阅读设备能够准确识别网站还有其他替换 CSS 样式
关于主题切换的思考
一般情况下,我会通过 js 来切换对应的类名,然后控制不同样式生效;一种形式是提前加载好各个主题的样式,这样会造成性能浪费;另一种形式则是动态加载 css 文件,造成用户体验问题(切换需要等待 css 下载并渲染,有感知)
alternate 控制交互体验更好,瞬间切换,完全无感知。因为浏览器已经把换肤的 CSS 文件预加载好了;同时只会默认渲染一个主题的样式,其他样式文件会在浏览器空闲时加载
rel="canonica"
html
<link rel="canonical" href="https://edu.51cto.com" />
指定规范网页,用在 link 中; 告知搜索引擎,以哪个地址为规范版本,降低其他地址的抓取频率
比如你的站点可以通过多个域名访问、或者既有移动端又有 PC 端,这时候就能设定你想要的地址为搜索引擎优化抓取
rel="nofollow"
禁止搜索引擎追踪,一般不重要的链接设置,防止搜索引擎爬取从而降低主要内容的权重
比如首页,应该只保留列表页,详情页,友链的链接追踪;对于如 logo 回到首页,一些不重要的链接进入登录后的页面等,均需要设置 nofollow
辅助语义
- rel="author",用在 a 标签中,链接的地址是作者的主页
- rel="help",给帮助链接等设置,辅助语义化
- rel="license",如果链接指向版权说明,添加此属性告知 SEO
- rel="tag",用来标记标签型链接,可以用来对你觉得重要的链接地址进行标注,SEO 会更加精准,质量更高。
- rel="shortlink" 网站当前页面对应的短链接,有利于 SEO 理解链接;
- rel="external" 主要作用是告诉搜索引擎,这是一个外部链接(指向其他域名),设置此属性会降低链接的权重
- rel="icon" 用来指定网站小图标
<link rel="icon" href="favicon.ico" />
短连接在分享时也更容易(微博字数限制,微信或 QQ 中地址呈现等)
favicon 可以也可以设置 png 等格式哦
性能优化相关
DNS 优化
rel="dns-prefetch" DNS 预读取
rel="preconnect" DNS 预链接
html
<meta http-equiv="x-dns-prefetch-control" content="on">
<link rel="preconnect" href="https://xxx.com/">
<link rel="dns-prefetch" href="https://xxx.com/">
提前进行 DNS 预读取、预链接,提升页面加载速度;在 H5 等网速较慢的情况下效果非常明显
一般是用来预加载资源、网页的 DNS,对于网站本身的域名,由于已经打开,预连接的作用并不大
预加载
rel="preload" 强制浏览器提前加载资源,优先级为 high
如果 preload 的资源 3 秒内没有被当前页面使用,Chrome 开发者工具的控制台会触发警告!
常用来解决页面大背景下拉式渲染或轮播白图问题,预加载对应的图片
注意,不要预加载过多的资源,过度使用 rel="preload"
可能会导致额外的延迟和内存占用,从而影响网站性能。
预拉取
rel="prefetch" 资源预拉取,在浏览器空闲的时候下载缓存静态资源(优先级为 low)
常用来预下载缓存静态资源 css、js、html,提升网页性能
prefetch 会在浏览器空闲时进行资源的拉取并缓存,理论上可以不限制数量;但还是推荐只 prefetch 核心资源
prefetch 最适合抢占用户下一步可能进行的操作并为其做好准备,例如搜索结果列表中首个产品的详情页面或分页内容的下一页内容
如 React 的 next.js 框架,就会对当前页面所有 Link 组件的目标页面的资源进行 prefetch;极大的提升打开速度
预渲染
rel="prerender" 告知浏览器先默默渲染好页面,当用户导航到这个页面时会大大加快加载速度;
prefetch 获取页面并不会加载页面中的 css 和 js资源,更多是页面本身;但是 prerender 已经在背后默默做起渲染的事情,预处理要更进一步
注意不要过度使用,浪费宽带(不被使用的页面或资源);总的而言,prefetch 和 prerender 在低网速下,可以极大的提升页面打开速度;
查漏补缺
rel="noreferrer"
一般用在 img、a 标签中,用来防盗链;如 a 标签设置了 rel="noreferrer",那么新页面就无法通过 document.refferer 获取到上个页面的信息
rel="noopener" 和 rel="opener"
如果我们的链接元素没有设置 noopener,且在新窗口打开这个链接的时候;新打开的页面可以通过 window.opener 获取来源页面的窗体对象,进行一些恶意操作(如修改地址,添加恶作剧内容等)
因此,如果您的网站上有外部的链接地址,一定要记得加上 noopener
现代浏览器设置了 target=_blank
的 <a>
元素默认就是 noopener,这样更安全。如果想要操作(如两个站点都是我们自己的内部站点),可以设置 rel="opener"
input 的 form 属性
我们可以为 form 表单之外的 input、textarea 等设置 form 属性,值为 form 元素的 id
html
<form id="testForm">xx</form>
<input type="text" form="testForm" />
有点类似于 label 标签的 for 属性,这在我们实现页面效果时往往非常有用,有些和表单一起提交的内容,往往在样式上需要在表单之外
元素禁用
有时我们希望阻止用户与元素进行交互,比如某些输入框只在满足条件下可以输入修改内容
disabled 属性
适用于表单元素、button 等,会置灰;没有对 hover 等交互行为阻止,这在 button 禁用提示时非常有用
最佳实践:如果需要批量禁用表单中的多个表单元素,可以将他们放到 fieldset、legend 中,然后给 fieldset 设置 disabled 属性
inert 属性
inert 这个单词的意思是无活动能力的、无行动力的
设置了 inert 属性的元素,其内部所有文字、元素都不能点击,不能戳,不能选中,不能输入,没有 hover
inert 属性不具备默认的样式标识,可以手动设置 CSS [inert] { background: #ccc; }
使用场景:inert 可以快速实现博文禁止选中、复制功能
pointer-events: none
阻止鼠标行为,包括点击,悬停等交互
注意,它只是阻止鼠标行为,使用 tab 检索到 input,依然可以输入(可以通过设置 tabindex = -1 修正)
适用于任何元素,特别适合实现可穿透的各类覆盖层(如半透明层遮挡、水印等,会阻碍其他元素的点击行为,就可以给水印设置 pointer-events: none;)
title 及 a 标签使用 title
属于可选属性,不必须;用来提供额外的信息,当文本内容不能很好的描述时,title 可以提供准确的说明,对屏幕阅读器友好;
鼠标悬停提示,辅助了解
a 标签使用 title 能帮助 SEO 优化,搜索引擎会考虑链接的 title 属性
最佳实践:
- 不要滥用,只在块级链接或链接文本复杂时添加必要的说明,对于简短链接并不需要
- 应确保链接文本的清晰描述,不要依赖 title,因为移动设备无法悬停
文件下载 download 属性
html
<a href="x.pdf" download="下载名">下载</a>
- 通过 href 设置资源路径,download 开启下载,并设置下载后的文件名
- 可以通过动态创建 a 标签,设置 download 属性,然后 a.click() 触发下载
- 部分浏览器可能会预览打开而不是直接下载
预览问题:对下载的资源指定 http 响应头 Content-Disposition: attachment; filename=xxx
,这样资源将会作为附件形式,可以解决预览打开问题
data URL 下载
将文本或 dom 导出下载;可以导出下载为 html、txt、json 等;
js
let data = 'Hello, world!';
let blob = new Blob([data], {type: 'text/plain'});
let href = window.URL.createObjectURL(blob);
let a = document.createElement('a');
a.href = href;
a.download = 'hello-world.txt';
document.body.appendChild(a);
a.click();
window.URL.revokeObjectURL(url);
得到这个 href 也可以用来设置给图片 src 直接显示;
常用来导出页面;不适合大型文件,因为 Data URL 的长度有限制;
base64 下载
核心代码
js
var context = document.createElement('canvas').getContext('2d');
context.drawImage(downloadDom, imgWidth, imgHeight);
let href = canvas.toDataURL('image/png');
创建 download 的 a 标签下载即可;这个 base64 格式的地址也可以用来设置给图片 src 直接显示;主要是导出下载图片
ping 属性
html
<a href ping="post请求>链接1</a>
当用户点击链接时,浏览器会自动调佣 ping 设置的接口;
只支持 post 请求,只支持 a 标签,只支持点击行为上报
ping 属性实现数据上报非常适合简单上报如 AB 测试
css 上报
css
.report:active::afetr {
content: url(post请求);
}
这样在设置了类名为 .report 的元素按下时,就会调用上报请求;黑科技,了解即可
JavaScript 上报
自行调用接口,适合复杂上报
拓展:我们可以默认给 a、button 这些交互元素绑定上报处理,许多数据统计库都是这样处理的
ping 与 DDos 攻击
DDos 攻击:利用大量的计算机不停的调用请求,占用服务器资源,使目标系统瘫痪
DDos 攻击属于分布式攻击,需要多台设备发起请求,因此前端的防抖节流并不能解决问题
ping 可以用来发起请求,可以通过给 a 绑定 ping属性,然后通过定时器不断地触发其 .click() 事件,达到 DDos 攻击的目的
这也就要求我们固化 npm 包版本、使用自己内部的 CDN 资源;因为一旦它们在 js 里搞点什么 DDos 攻击,威力会非常惊人
img 的 alt 使用
alt 属性是 img 的必须属性,即使为空,也应该添加
- 无障碍性, alt 属性是理解图像内容的重要途径
- SEO 优化,搜索引擎也考虑 alt 属性
- 可访问性,在图像无法加载或显示时,浏览器会显示 alt 属性中指定的文字
最佳实践:
- alt 属性应简明清晰的说明图片内容
- 对于纯装饰图片、背景,可以设置 alt="",不是说 alt 一定要有内容
结束语
作为一个油盐不进的爱卷人士,这当然不是一个结束,后续将会持续进行更新。To Be Continue...