查漏补缺之 HTML 篇 part2

前言

迷茫的时候,卷就是最好的选择;毕竟,与人斗其乐无穷。

本节主要包括以下部分的查漏补缺

  • HTML5 特性
  • 各种特性概念介绍;如何使用;掰头一下原理及优缺点;应用及最佳实践的思考

HTML5 特性介绍

话说,HTML5 发布都快 20 年了,其中增加的一些内容实在是很陈旧的东西了,但所谓温故而知新,知识总是常学常新的~~~

HTML5 新增特性整理

  • 语义化标签
  • 表单增强
  • Web Storage
  • Web Worker
  • canvas 图形绘制
  • SVG 矢量图形
  • 音视频处理
  • 地理定位

语义化标签

HTML5 引入了一系列的语义化标签,用来让文档结构更加清晰,并帮助搜索引擎更好的理解网页

以上是一张使用 HTML5 语义化标签实现的页面图,它不再是 div 嵌套的形式

为什么要使用语义化标签

div 布局玩的好好的,为啥非要整这么些个语义化标签?这就不得不说说语义化标签的优点了

  • 在没有 css 时,页面也能呈现较好的内容结构
  • SEO 友好,爬虫依赖标签来确定上下文及关键字的权重
  • 屏幕阅读器友好,视障人士的福音(事实上国内网站几乎就不考虑这个,他们觉得没事听啥网页,哎~)
  • 可维护性,可读性;看到对应的标签就知道大致包含的内容了,维护起来自然也方便许多

header 元素代表页面、section、article 的头部

以掘金网首页为例,具有两个 header 元素,分别是公用的大头部和列表头

最佳实践:

  • header 允许有多个,但一般情况下,只对页面头部或 section 头部使用 header 元素
  • 对于可以使用 h1-h6 实现的简单头部,不需要使用 header 标签

补充一点,也不要滥用 h 标签,一个页面最好有且只有一个 h1;h2-h4 不要超过 5 个,只在内容是关键词时使用;避免使用更低层次的标题 h5、h6;如果只是单纯的加粗,可以使用 strong 标签;这在 SEO 中很重要,因为标题会影响关键字和权重

footer 元素代表页面、section、article 的底部

页面级的 footer 一般会包含一些版权信息、备案信息、友情链接、文档说明

最佳实践:

  • footer 允许有多个,一般情况下,只会在页面级别使用
  • 有时也会在 article、section 底部使用,如一篇文章, 底部有评论、点赞、分享功能,可以放到 footer 中(如微博的文章)

nav 元素用来包含与当前页面主要导航相关的元素

最佳实践:

  • 不要滥用 nav,nav 应该用来包含主要导航;不是链接到其他地方就使用 nav,如第三方友链、广告;这些使用 ul 就可以了
  • 页面交互性搜索,个人信息等内容,应该放到 nav 中,如上掘金网首页的 nav
  • 移动端下,浏览器可能将其转换为滑动菜单

以上是 vue 文档移动端下抽屉式导航效果,它会在页面的一侧隐藏起来,用户可以通过点击屏幕边缘的按钮或图标来展开和收起这个菜单;当然这是网站自己实现的,而 nav 本身在移动端就可能被解析为抽屉式导航;

为了保证各浏览器的兼容性,最好是通过媒体 fixed 布局的形式来实现移动端下 nav

main

main 元素用来包含页面主要元素

最佳实践

  • main 一个页面只能有一个,一般放在 header 和 footer 之间
  • mian 代表页面的核心区域,内部可能会包含 section、article 的内容;但不能被他们包含

article

article 元素表示一篇文章、新闻报道、博客帖子、评论、回复或其他类似内容

最佳实践

  • 尽可能避免将多个 article 元素嵌套在一起,以免混淆文档的层次结构;如果需要请在内部使用 section
  • 只有当某个部分具有足够的独立性和完整性时,才适合使用 article 元素;比如文章描述是段落文本,它只适合作为 article 的一部分,而不应该是一个 article

aside

aside 用来表示与主内容有关,可以被视为从属关系的内容

section

当内容存在明显逻辑分隔的时候,使用 section 来分割;如介绍、目录、结论等,可以分割为多个 section

最佳实践

  • section 提供一个 id,用来锚点

time

time 元素用来表示日期、时间信息

最佳实践

  • 所有与时间相关的信息,都应该使用 time 元素;比如倒计时、日期等
  • 必须包含 datetime 属性,以便阅读器识别日期时间格式;datetime 应当符合 ISO8601 标准格式,如 YYYY-MM-DDTHH:MM:SSZ 或 YYYY-MM-DD;

掘金网的 time 元素,挠头?datetime 属性还包含了毫秒数???

github 甚至使用 shadowDOM 实现了一个自定义标签,表示所有与时间相关的信息,如上,提交时间是 13 hours age 使用的是 relative-time 自定义标签;不得不服~

mark

mark 元素用来高亮搜索关键词

最佳实践

  • mark 元素默认具有黄色背景和下划线样式,可以通过 CSS 重置
  • mark 只能用来包裹文本,不能包裹其他标签
  • em 也用来进行文本强调,比如百度搜索,关键词标红,就是通过 em 实现的;灵活运行两者

兼容性

2016 年至今,老选手了,兼容性这一块杠杠的,可以放心使用;当然,为了确保万无一失,可以通过 css hack 的形式对不支持的浏览器进行兼容

css 复制代码
header, footer, main {
  display: block;
}

尽管语义化标签兼容性很好,就算不兼容,也很容易 hack;然而事实上,大多数网站也还是 div 套娃的形式;我想这主要是历史遗留和开发人员技术栈、开发习惯等原因造成的;值得欣慰的是越来越多的网站正在逐渐采用语义化标签,这是无数前端努力的成果~

表单增强

HTML5 对表单元素进行了一系列的增强,大大提升了用户体验和开发者效率,改善了网站的安全性

input 表单的 type 拓展

为了让开发者更加方便地创建各种类型的表单控件,同时也能更好地满足用户的输入需求,HTML5 对 input 的 type 进行了拓展,主要有以下常用类型

  • color,色值选择器
  • date、datetime、month、week、time 等时间相关的选择;在对样式要求不高时,可以作为选择
  • email 地址输入域
  • search 搜索域,与 datalist 配合使用
  • tel 电话号码输入
  • number 数字输入
  • range 范围选择器

maxlength 对于 number 不生效问题

经常会遇到限制某个输入框的最大长度的需求,比如一个要求输入手机号的输入框:

<input type="text" placeholder="请输入手机号码" maxlength="11" />

但是 text 有一个不好的体验,就是获取焦点后弹出的输入法是默认拼音的那种,不太适合此处要求纯数字的需求。那么自然会想到改为 number,改为后你会崩溃, 竟然发现 maxlength 属性不起作用了,可以无限地输入...

后面去试了下 tel 类型,发现 maxlength 属性又变有效了;着实让人牙疼~~~

兼容性的做法是在输入值变化时,进行判断截取

<input type="number" oninput="if (value.length > 11 ) { value = value.slice(0, 11) }" />

上述办法同样适用兼容性处理限制用户输入数字、字母、最大最小值等;当然为了保险起见,后台也必须进行一致限制,以防止非法数据插入数据库

色值选择

color 选择器常会作为隐藏点击元素,展示为 button 的形式来实现色值选择;选择后通过 dom.value 即可拿到色值

这就和一些 UI 组件的 Upload 一样,如 element,采用的是 button 覆盖在隐藏的 file input 之上的方式实现

range

range 作为天然的具有拖拽的范围选择,样式稍作修改,就是一个完美的进度条;同时结合 css 可以用来实现如评分星数、中高低密码强度等效果;非常好用

新增表单元素

  • datalist,输入域的选项列表,通常是 search input 的 list 属性与 datalist 的 id 关联
  • output,用来计算或动态脚本

datalist 使用

html 复制代码
  <input type="search" list="searchList">
  <datalist id="searchList">
    <option>前端</option>缺失缺失缺失
    <option>HTML</option>
    <option>JavaScript</option>
  </datalist>

很快捷的就实现搜索联想功能;我查看了包括 github、淘宝、京东、百度、谷歌等网站;并没有任何站点有使用它来做搜索功能;datalist 与 input 绑定,样式控制确实有诸多不便,同时搜索定制化效果比较多,div、ul 模拟反而更方便

但是,这并不影响 datalist 的使用,因为它和其他类型的 input 也能产生较好的联动效果

datalist 与 color 配合;配置推荐色值

html 复制代码
  <input type="color" />
  <input type="color" list="redColors" id="colors" />
  <datalist id="redColors"></datalist>

datalist 与 range 配合;分配刻度

ini 复制代码
<input type="range" list="tickmarks" min="0" max="100" id="tick" name="tick" />
<datalist id="tickmarks">
  <option value="0"></option>
  <option value="10"></option>
  <option value="20"></option>
  <option value="30"></option>
  <option value="40"></option>
  <option value="50"></option>
  <option value="60"></option>
  <option value="70"></option>
  <option value="80"></option>
  <option value="90"></option>
  <option value="100"></option>
</datalist>

总结就是,datalist,除了和 search 配合,其他时候都挺好用,属于不务正业了是~

新增表单属性

  • placeholder 用来提示用户输入
  • required 必填
  • min、max 最大值最小值,一般与 number 类型的输入域配合使用
  • pattern 正则验证输入的值
  • autofocus 自动聚焦,不再需要通过 js focus 来聚焦

设置了 min、max 输入框后面会出现向上向下箭头,切换时,值会在 min-max 之间变化;但是,输入是可以随意输入的,没错,你需要结合 oninput 事件限制用户输入,闹呢~

Web Storage

HTML5 新增了 localStorage、sessionStorage 用来缓存数据;使用时非常简单

js 复制代码
localStorage.setItem("name", "value");
localStorage.getItem("name"); // => 'value'
localStorage.removeItem("name");
localStorage.clear(); // 删除所有数据

sessionStorage.setItem("name", "value");
sessionStorage.setItem("name");
sessionStorage.setItem("name");
sessionStorage.clear();

在这之前,我们一般通过 cookie 来存储数据,限制非常严重

  • cookie 只有 4k,而 Web Storage 约为 5M
  • cookie 中的信息会发送到服务器,过大会造成负担;老项目的性能优化,cookie 的缩减是很重要的一项
  • 操作简单,cookie 是一串字符串,每次都需要从字符串中解析,尽管我们可以封装 cookieUtils,但 Web Storage 则天然具有简单的 API
  • 查询快,如上 cookie 需要解析字符串,而 Web Storage 则使用散列存储,快速查询

localStorage 与 sessionStorage

浏览器可以通过 localStorage 与 sessionStorage 安全地存储键值对;内容会保存在同一个源下的 Storage 对象中

localStorage 中存储的数据除非主动清除,如清除浏览器缓存、上图 Application 清除 Storage、调用 clear 代码清除;否则会一直存在。这也就意味着关闭浏览器后再次打开,仍然可以缓存,适合持久化缓存应用场景

sessionStorage 中的数据则和会话窗口有关,多个 tab 栏中可以公用,但一旦浏览器关闭,则数据清除,适合临时存储登录 token

监听变化

当 Web Storage 发生变化时,会触发 storage 事件,回调参数中会返回变更的存储值

js 复制代码
window.addEventListener('storage', (event) => {
  // 来自清除缓存,变更 cookie
  if (e.key == null) {
    docCookies.removeItem('pageLoaded');
    docCookies.removeItem('detailLoaded')
  }
})

这个事件可以用来配合 css inline 进行极致的性能优化(适用于 PHP 的静态模版渲染、SSR),如果是第一次加载,则将 css 的内容放到 html 的 style 中;如果 css 缓存了,则从缓存中获取通过 link 加载 css,配合着将脚本放到 body 底部,可以做到首屏渲染无需请求任何资源

注意:这里要求 css 的内容不能太大,如果将 css 以 style 形式放到 html 中,对 Doc 文档的 fetch 影响较大,则得不偿失(一般情况下,几十 KB 的大小,对 html 的下载时间的影响都不大)

无痕模式下不可用

浏览器会在无痕模式下禁用 Web Storage,使用时需要进行可用性检测

typeof Storage !== "undefined"

大小问题

尽管 Web Storage 拥有 5M 左右的大小,但如果存储过于大量的 json 数据,依然非常容易满;而在存储接近满时,性能会非常差,很容易造成移动端卡顿

indexDB 与 localforage

使用 indexDB 可以很好的解决上述两个问题,它是一种类似数据库操作的存储结构,具有事务处理的特性,非常适合存储表格形式的数据,使用可参考 MDN 文档

由于 indexDB 的 API 非常繁琐,推荐使用封装好的 JavaScript 库,如 localforage

localforage 有一个优雅降级策略,若浏览器不支持 IndexedDB 或 WebSQL,则使用 localStorage

不支持跨域

注意,Web Storage 和 indexDB 存储的内容会保存在同一个 Origin 下,一旦跨域,就无法访问

如果需要跨域访问

  • 如果是自己内部站点,拥有相同二级域,可以通过 iframe + postMessage 来进行通讯
  • 另一种就是通过 WebSocket 长连接

安全考虑

避免将敏感数据存储在 Storage 中(如用户手机号等),容易受到攻击

Web Worker

一句话,Web Worker 让 JavaScript 拥有了多线程处理的能力,简直是牛逼 plus

我们可以可以抽离一部分功能到 Web Worker 中,如复杂计算、处理,在结束后,通过 postMessage 并携带结果返回给主线程

使用

主页面 js

js 复制代码
// 主线程中初始化Web Worker
let myWorker = new Worker('worker.js');

// 接收Worker消息事件
myWorker.addEventListener(
  'message',
  function (e) {
    console.log('Received message ' + e.data);
  },
  false
);

// 发送消息给Worker
myWorker.postMessage([42, 1337]);

worker.js

js 复制代码
self.addEventListener('message', function(e) {
  let numbers = e.data;
  let sum = numbers.reduce(function(a, b) {
      return a + b;
  }, 0);
  self.postMessage(sum);
});

我们就完成一个运行在后台的加法计算 worker 了

优缺点

优点:Web Worker拥有独立的内存空间和线程池,即使处理出错或内存溢出,也不会阻塞主线程;同时充分利用多核进行计算任务,极大提升页面性能

缺点:不具备 DOM 操作能力,什么 window、document 统统不能操作,可以理解,因为在多线程环境下如果随意访问DOM,你操作一下,它操作一下,以谁为准呢?所以浏览器并未开放这个权限,如果需要操作 DOM,在主线程去操作

递归处理树结构

一个经典的 Web Worker 应用场景就是将递归抽离处理,比如一颗组织树列表数据,需要处理成树结构,这完全可以抽离到 Worker 中

如果在数据层次过深时,甚至可能导致内存溢出,造成页面崩溃,抽离到 Worker 中就不存在这种顾虑了,你崩任你崩,不影响咱们的主页面;当然,对于递归函数,还是建议转化为循环形式(蹦床函数

复杂耗时的逻辑,比如递归函数,即使进行了尾递归优化,但仍然有可能耗时较长,很影响页面性能,这时就很有必要将其抽离到 Worker 中

风险

避免过度使用(好像不太需要担心,实际用的人并不多 0.0~),这也很好理解,每一个 Worker 说白了就是分配一个线程,而每一个线程是需要占据一定的内存的,过多会影响整体性能(之前在 node 多线程与单线程讨论过)

错误使用:比如一直不停的给主线程 postMessage,导致主线程被占用阻塞;当然这都是很低级的错误,也很容易发现,使用时稍加注意即可

其他待查漏补缺项

  • canvas 图形绘制
  • 拖拽 API
  • SVG 矢量图形
  • 音视频处理
  • 地理定位

上述模块不是不常用,而是这些内容过于庞大,比如 canvas,甚至可以作为专项深入学习,咱目前的水平也就是照着 API 绘制绘制形状,写点轨迹动画;并没有深入使用,也就没踩过什么坑值得总结,留待将来查漏补缺吧~

结束语

作为一个油盐不进的爱卷人士,这当然不是一个结束,后续将会持续进行更新。To Be Continue...

相关推荐
前端郭德纲1 小时前
浅谈React的虚拟DOM
前端·javascript·react.js
2401_879103682 小时前
24.11.10 css
前端·css
ComPDFKit3 小时前
使用 PDF API 合并 PDF 文件
前端·javascript·macos
yqcoder3 小时前
react 中 memo 模块作用
前端·javascript·react.js
优雅永不过时·4 小时前
Three.js 原生 实现 react-three-fiber drei 的 磨砂反射的效果
前端·javascript·react.js·webgl·threejs·three
神夜大侠6 小时前
VUE 实现公告无缝循环滚动
前端·javascript·vue.js
明辉光焱6 小时前
【Electron】Electron Forge如何支持Element plus?
前端·javascript·vue.js·electron·node.js
柯南二号7 小时前
HarmonyOS ArkTS 下拉列表组件
前端·javascript·数据库·harmonyos·arkts
wyy72937 小时前
v-html 富文本中图片使用element-ui image-viewer组件实现预览,并且阻止滚动条
前端·ui·html
前端郭德纲7 小时前
ES6的Iterator 和 for...of 循环
前端·ecmascript·es6