前言
当我们谈论起前端面试,自然不可避免那三板斧:HTML、CSS、JavaScript。聊的比较多的可能是JS和CSS,但是如果你不了解HTML5的新特性,你是无法很好去回答一些基于HTML5新特性才能够实现的业务解决方案。
比如基于全双工通信协议websocket实现的实时协作工具:腾讯文档、飞书文档等,还有直播互动平台,在直播平台中,websocket可以用于实现弹幕、礼物赠送、点赞等实时互动功能。
因此,这些知识点并不是枯燥无味的只能靠背诵的过时玩意儿,而是目前正在流行的东西。哪怕不是为了面试,作为一名前端工程师,也有必要去了解、去接触这些概念。
话不多说,就让我们一起来看看吧~
序章
在正式介绍HTML5的一些新特性之前,我觉得免不了俗,还是得先聊清楚“什么是HTML”这个问题。我不知道大家成为前端开发工程师的契机是什么,学习前端知识的方式是什么。但有一点应该是普遍能够感同身受的,那就是学这些不像小时候读书那样学语文和数学,往往并没有经历过一个系统性学习的过程。知识是碎片化的,获取知识的途径也是碎片化的。
最开始写页面的时候,可能会出现这种情况:
“这是div,这是span,这是button。”
“好了,你去写个类似淘宝商城的网站吧。”
我当然也没有能够带领大家去系统性学习的能力(目前没有,未来可期😀),但是我至少期望能够用规范、标准的语言,去给大家介绍相关的概念和知识,帮助大家建立更加正确的认知。
回到“什么是HTML”这个问题本身,这里我们直接引用MDN文档的定义:
HTML(超文本标记语言——HyperText Markup Language)是构成 Web 世界的一砖一瓦。它定义了网页内容的含义和结构。除 HTML 以外的其他技术则通常用来描述一个网页的表现与展示效果(如 CSS),或功能与行为(如 JavaScript)。——MDN
拿盖房子来比喻的话,HTML是地基,是毛坯房。CSS是装修,是刷墙的漆,是铺地的砖。JS是家具,提供特定的功能,让这个房子能够作为酒馆、餐厅等等。
虽然我们不会经常去提HTML扩展后完整的名字——超文本标记语言,日常交流也都是直接喊这4个缩写字母的,但是本着学习的态度,我们也有必要去掌握基本的概念:
-
什么是【超文本】?
- “超文本”(hypertext)是指连接单个网站内或多个网站间的网页的链接。链接是网络的一个基本方面。只要将内容上传到互联网,并将其与他人创建的页面相链接,你就成为了万维网的积极参与者。
-
什么是【标记】?
-
HTML 使用“标记”(markup)来注明文本、图片和其他内容,以便于在 Web 浏览器中显示(这为后续我们聊【语义化】做了铺垫)。HTML 标记包含一些特殊“元素”如
<head>、<title>、<body>、<header>、<footer>、<article>、<section>、<p>、<div>、<span>、<img>、<aside>、<audio>、<canvas>、<datalist>、<details>、<embed>、<nav>、<output>、<progress>、<video>、<ul>、<ol>、<li>等等。 -
HTML 元素通过“标签”(tag)将文本从文档中引出,标签由在“
<”和“>”中包裹的元素名组成,HTML 标签里的元素名不区分大小写。也就是说,它们可以用大写,小写或混合形式书写。例如,<title>标签可以写成<Title>,<TITLE>或以任何其他方式。然而,习惯上与实践上都推荐将标签名全部小写。
-
最后,让我们看一个最基础的HTML文件:
<!-- DOCTYPE 告诉浏览器(解析器)应该以什么样(html 或 xhtml)的文档类型定义来解析文档* -->
<!DOCTYPE html>
<html lang="zh">
<!-- head 是所有头部元素的容器, 绝大多数头部标签的内容不会显示给读者 -->
<head>
<meta charset="UTF-8">
<title>Demo</title>
</head>
<!-- body 用于定义文档的主体, 包含了文档的所有内容,该标签支持 html 的全局属性和事件属性 -->
<body>
<span>Hello, world</span>
</body>
</html>
浏览器的两种模式
在【序章】部分,我们看到了一个具备基本内容的html文件。我们会发现在文件的首行,是这样一串代码:
<!DOCTYPE html>
其实我们是很少关注这东西的,当我们使用一些UI框架的时候,比如React、Vue,我们创建工程一般都会基于这些框架提供给我们的脚手架,比如create-react-app或者create-next-app。这些脚手架已经帮我们自动包含了正确的DOCTYPE声明,不仅如此,其实CRA在Webpack的优化上也帮我们做了很多工作,包括模块拆分、Tree shaking等等等等。这些脚手架之所以这么完善,是期望开发者能够将精力专注在项目的业务逻辑和界面设计上,提升开发的效率。
我们不用管,不代表面试不会问。
因此,我选择在本篇文章正文的第一部分,讲一讲文档类型声明(DOCTYPE,DTD,Document Type Declaration),以及衍生出来的浏览器的两种模式。
在 HTML 中,文档类型声明是必要的。在所有文档的头部,你都将会看到“
<!DOCTYPE html>”序言。这个声明的目的是防止浏览器在渲染文档时,切换到我们称为“怪异模式”的渲染模式。“<!DOCTYPE html>”确保浏览器按照最佳的相关规范进行渲染,而不是使用一个不符合规范的渲染模式。——MDN
声明性标记语言的规范写法
定义也好,作用也罢,我不知道你是否会好奇写法?
<!DOCTYPE html>
🧐:“为啥
DOCTYPE前面要加一个!号呢?”
在 HTML 中,DOCTYPE 声明通常以感叹号 ! 开头,这是因为它遵循 SGML(Standard Generalized Markup Language)的语法,这是一种用于定义声明性标记语言的ISO(国际标准化组织)规范。在 SGML 中,所有声明都以感叹号开始,这有助于避免与 HTML 标签混淆。
我们将其作为编码的规范记忆一下即可。
标准模式(Standards mode)
浏览器使用 W3C 的标准解析渲染页面。在标准模式中,浏览器以其支持的最高标准呈现页面。
怪异模式(Quirks mode)
浏览器使用自己的怪异模式解析渲染页面。在怪异模式中,页面以一种比较宽松的向后兼容的方式显示。
不符合标准的行为是指没有遵循 W3C 等组织制定的标准的行为,举个例子:
根据 W3C 标准,<a>标签的title属性应该用来显示鼠标悬停在链接上时的提示文本。
然而在早期IE浏览器中,这个属性并没有被正确实现。
延伸话题
提到标准和怪异,这里可能会顺手考察一下标准盒模型和怪异盒模型,这是我们通过一段同样的样式代码,不同的盒模型,来直观地了解下区别即可:
width: 200px;
height: 150px;
background-color: #6c75ef;
padding: 10px;
border: solid 2px blue;
- 标准盒模型:
- 通过
box-sizing: content-box;设置 - width = 内容宽度
- 通过
- 怪异盒模型:
- 通过
box-sizing: border-box;设置 - width = border + padding + 内容宽度
- 通过
HTML5的变化
标签的废弃
“新的时代,已经没有载得下我的船了。”
HTML5废弃了以下这些元素:
- 纯表现的元素:basefont、big、center、font、s、strike、tt、u
- 为什么删除?
- 设置页面默认字体(
<basefont>)、定义大号字体(<big>)、居中内容(<center>)、设置字体和颜色和大小(<font>)、下划线(<u>)等这些元素所实现的效果在HTML5中都应该通过CSS来进行设置,因此被淘汰了。- 如何用
CSS实现下划线效果?
span { text-decoration: underline; } - 如何用
- 添加文本删除线(
<s>、<strike>)被<del>标签取代。123
<tt>原用于显示打字机文本(字符宽度均为相同像素数的字体),在HTML5中可以使用<kbd>和<code>等语义化更好的标签来显示等宽字体,或者设置font-family,因此也被淘汰。
- 对可用性产生负面影响的元素:frame、frameset、noframes
- 为什么删除?
- 本用于定义框架,而在
HTML5中,不再支持框架布局。因为框架布局存在一些问题:-
可用性:使网页导航变得复杂,让用户在框架之间迷失方向
-
可访问性:影响屏幕阅读器等辅助技术,使残障人士难以访问网页内容
-
书签和链接:无法创建书签和分享链接
-
打印:无法打印网页整个内容
-
新特性
HTML5新增的东西实在是太多了,而且不是像挤牙膏一样一点点往外挤,添加点新内容,而是直接多出来不少条牙膏本身。这些新特性极大地增强了网页的能力上限,简单列一下,作为本章节的开头:
- 丰富的图形和动画表现
- 更加完善的表单
- 支持离线应用
- 支持多媒体
- 支持跨平台
等等,就让我们一起来看看吧。
💉💉💉:我们之所以觉得“八股文”是“八股文” ,是因为觉得内容很老旧,很过时,只有面试有用,但是真的是这样吗?本章节内容将会结合市面上使用很多、start很高的基于
HTML5新特性开发的第三方库,一起聊聊新特性,或许这些知识的用处并不只是面试,掌握它们也并不只靠记忆呢~
更好的语义化
语义化、语义化、语义化,这个词在我们阅读HTML相关的技术文章时,经常看到。
语义化到底有什么好处,能够让HTML费劲巴拉地捣鼓各种新的标签元素,废弃旧的标签元素,就为了使它变得更好?
先来看看什么是语义
语义:程序设计中,语义指的是一段代码的含义。例如,“运行这行 JavaScript 代码会产生怎样的影响?”、“这个 HTML 的元素有什么作用,扮演了什么样的角色”(而不只是“它看上去像是什么?”)——MDN
什么叫做 一段代码的含义 呢?举个例子,在HTML中,<nav>是个语义化元素,赋予了它包裹着的内容“在当前文档或其他文档中提供导航链接”的含义。
nav同时也是navigation的简写。
<nav class="crumbs">
<ol>
<li class="crumb"><a href="#">Bikes</a></li>
<li class="crumb"><a href="#">BMX</a></li>
<li class="crumb">Jump Bike 3000</li>
</ol>
</nav>
当我们阅读这段代码的时候,能够清楚的明白,这一块被<nav>包裹的内容,是负责导航跳转的。
那么语义化都有哪些好处呢?
-
搜索引擎将其内容视为影响页面搜索排名的重要关键字(参见 SEO)。
- 这里就涉及到了CSR和SSR两种渲染模式的区别,为什么现在SSR(服务端渲染)这么热门,就是因为SSR也能更有利于SEO,从而让我们的网站更容易出现在用户面前,提高网站的点击率和用户量。
- 如果你经常使用
React技术栈,可以了解一下CNA这个脚手架,即create-next-app,我最近也在写有关Next.js的实战项目系列文章,感兴趣的话,你可以点击下方链接阅读: - 《从0到1搭建一个属于自己的工作流站点——入门篇(bpmn.js、Next.js)》
-
屏幕阅读器可以将其用作指引,帮助视力受损的用户导航页面。
- 语义化不好的页面甚至无法以朗读模式打开
- 语义化良好的页面可以被朗读模式正常识别
- 语义化不好的页面甚至无法以朗读模式打开
-
比起搜索无休止的带有或不带有语义/命名空间类的
div,找到有意义的代码块显然容易得多。- 我举两个代码例子,大家看看,如果选择权交给你的话,你更喜欢阅读哪份代码?
<!DOCTYPE html> <html> <head> <title>语义化不佳的页面</title> </head> <body> <div id="header"> <div>网站标题</div> <div>导航链接</div> </div> <div id="content"> <div> <div>文章标题</div> <div>文章内容...</div> </div> <div> <div>侧边栏标题</div> <div>侧边栏内容...</div> </div> </div> <div id="footer"> <div>版权信息</div> </div> </body> </html><!DOCTYPE html> <html> <head> <title>语义化良好的页面</title> </head> <body> <header> <h1>网站标题</h1> <nav> <ul> <li><a href="#home">首页</a></li> <li><a href="#about">关于</a></li> <li><a href="#contact">联系</a></li> </ul> </nav> </header> <main> <article> <header> <h2>文章标题</h2> </header> <p>文章内容...</p> </article> <aside> <h3>侧边栏标题</h3> <p>侧边栏内容...</p> </aside> </main> <footer> <p>版权信息</p> </footer> </body> </html>阅读语义化良好的代码,是不是更省力呢,通过合适的语义化标签,基本上一眼就能找到我们想要阅读的目标,比如想要查看侧边栏的代码,直接看
<aside>标签即可,而不是从一个又一个<div>中检查id的命名,然后找到侧边栏。 -
向开发人员建议将要填充的数据类型。
HTML5引入了多种新的表单输入类型,这些类型可以直接告诉浏览器和开发者预期的数据类型。以下是一些例子:<input type="email">:用于输入电子邮件地址。<input type="url">:用于输入网址。<input type="number">:用于输入数字。<input type="date">:用于输入日期。<input type="datetime-local">:用于输入本地日期和时间。<input type="month">:用于输入月份和年份。
-
语义命名反映了正确的自定义元素/组件命名。其实这一点也是我们在工作中,代码评审(code review)时,期望团队成员都能够做到的。clean-code。而且我很喜欢这句话:“Your code is your documentation.”,很多时候,一个好的命名习惯,一些好的执行逻辑,本身就能省略掉一些无谓的注释,而让我们的代码可读的同时更简洁,举个例子:
- 有注释但是命名习惯不好的代码:
// 合同删除提示弹窗 function Modal1() { return <></>; }- 没有注释但是命名习惯好的代码:
function ContractDeletionConfirmModal() { return <></>; }我们可以通过合理的组件命名,来避免去写一些多余的注释。
丰富的图形和动画表现
<canvas>
<canvas>元素可被用来通过 JavaScript(Canvas API 或 WebGL API)绘制图形及图形动画。——MDN
当HTML5新增<canvas>标签元素之后,网页设计和开发领域经历了显著的技术革新和创意爆发。<canvas>元素作为一种全新的媒介,为开发者提供了一块空白画布,允许他们通过JavaScript进行绘图和渲染,从而极大地扩展了网页的视觉表现力和交互性。
在此之前,网页内容主要依赖于图像和Flash动画来呈现动态视觉效果,但这种方式存在许多局限性,如加载速度慢、兼容性问题以及安全性风险。
并且Flash停用之后,以前基于Flash实现的网页还会产生功能上的问题,比如前几年比较出名的新闻:《Flash停用致沈阳铁路局下属站段系统瘫痪 铁路信息化建设亟待加强》
<canvas>元素的出现打破了这些限制,也避免了上述的这些问题。
-
数据可视化大屏一直以来都是政企项目的热门需求。博主本人曾在实习阶段入职过一家toG的公司,做了很多政府项目,那时候选择Echarts作为提供数据可视化图表的库。
饼图、折线图、柱状图、雷达图等等,这些图表都是在
<canvas>上绘制的。 -
Three.js。在上文我们提到了数据可视化大屏,但其实现在对大屏的视觉展示要求越来越高了,很多时候甲方期望我们能够将园区也好、厂房也好,具体的3D模型也展示出来,面对这些业务需求,我们通常就会采用Three.js来帮我们实现。它使用
<canvas>元素作为绘图表面,并且利用 WebGL(Web Graphics Library)来渲染 3D 模型和场景。 -
我们也可以使用第三方库signature_pad来实现在线手写签名的功能,这在一些园区访问、条约签署之类的toB网站中比较常用。
它的实现原理是基于
canvasElement创建一个SignaturePad实例,然后为画布绑定必要的事件监听器,以便在用户交互时捕获数据。 -
还有比较热门的实现工作流的库:bpmn-js,它所提供的流程配置页面,也是绘制在
<canvas>上的。期望做更深一步了解的同学,可以看看这篇文章: 《从0到1搭建一个属于自己的工作流站点——入门篇(bpmn.js、Next.js)》。
-
还可以基于
<canvas>绘制水印图片,并将其作为Watermark组件的背景图,从而实现给网页打上水印。比如ANTD-5.0就是这么做的。期望做更深一步了解的同学,可以看看这篇文章: 《【源码阅读】【万字长文预警】🔍水印保卫战》
<video>和 <audio>
<video>HTML 元素用于在文档中嵌入媒体播放器,用于支持文档内的视频播放。你也可以将<video>标签用于音频内容,但是<audio>元素可能在用户体验上更合适。
<audio>HTML 元素用于在文档中嵌入音频内容。<audio>元素可以包含一个或多个音频资源,这些音频资源可以使用src属性或者<source>元素来进行描述:浏览器将会选择最合适的一个来使用。也可以使用MediaStream将这个元素用于流式媒体。——MDN
<video>和<audio>标签为网页媒体播放带来了革命性的变化。这些标签的引入旨在简化网页上多媒体内容的嵌入和管理,提高性能和用户体验。
同<canvas>一样,很重要的一点就是原生支持。<video>和<audio>标签提供了原生的HTML5支持,这意味着它们不需要额外的插件,如Flash Player,就可以在现代浏览器中播放视频和音频。
并且这些标签自带了非常多的功能:自动播放、循环播放、暂停、进度控制等,使得网页上的媒体播放更加灵活和可控。
在<video>和<audio>标签出现之前,我们往往使用<object>和<embed>标签来给网页嵌入多媒体内容。这些旧标签存在兼容性问题,加载速度慢,并且需要依赖第三方插件。
说到网页媒体播放,不得不提到著名的第三方库:Video.js,这个开源项目有将近38000颗start。超过450000个网站使用它来实现网页媒体播放。
与使用原生<video>标签直接实现基础的视频播放不同
Video.js 还提供了高级功能,如章节支持、字幕加载、播放列表、播放速度控制、全屏模式等。
这里我再写一个在React中使用Video.js的示例:
import React from 'react';
import 'video.js/dist/video-js.css'; // 引入 Video.js 的样式
import videojs from 'video.js'; // 引入 Video.js 库
const VideoJS = ({ videoSrc, options }) => {
// 创建 Video.js 播放器的实例
const player = videojs(document.querySelector('#video-container'), options);
// 加载视频源
player.src(videoSrc);
return <div id="video-container" className="video-js vjs-theme-city"></div>;
};
export default VideoJS;
import React from 'react';
import VideoJS from './VideoJS'; // 引入自定义的 Video.js 组件
const MyVideoComponent = () => {
const videoSrc = 'http://example.com/demo-video.mp4'; // 视频的 URL
const videoOptions = {
width: 400,
height: 300,
controls: true,
autoplay: false,
poster: 'http://example.com/demo-poster.jpg', // 视频的缩略图
};
return (
<div>
<h1>我的视频播放器</h1>
<VideoJS videoSrc={videoSrc} options={videoOptions} />
</div>
);
};
export default MyVideoComponent;
结语
未曾想这篇文章写到这里,正文字数已经5000字,因此将其拆分成上、下两篇文章。在本篇文章,我们重新认识了一下HTML,并且对基本结构、语义化、图形和动画表现以及一些热门的第三方库做了介绍,这些都是展示和表现的层面。
在下一篇文章中,我们将会一起学习功能层面,比如离线应用、地图、跨窗口通信、websocket等等,期待与你在下一篇相遇~