本文为HTML标准解读系列文章,其他文章详见这里。
在HTML中,有一类标签,虽然很重要,但由于大部分不会被浏览器渲染出来,而被很多开发者所忽略,这类标签叫作元数据内容标签。
如果你不知道什么是叫「元数据」,可以看看维基百科对元数据的定义:
Metadata is "data that provides information about other data"。
元数据是“给其他数据提供信息的数据”。
如果范围缩小到HTML上,HTML标准对于「元数据内容」的定义是这样的:
Metadata content is content that sets up the presentation or behavior of the rest of the content, or that sets up the relationship of the document with other documents, or that conveys other "out of band" information.
元数据内容是具有如下作用的内容:设置整体内容的呈现或者行为、设置本文档与其他文档之间的关系、传达其他主内容以外的信息。
对于这个定义,可以举几个例子:
<!-- 设置整体内容的呈现:设置默认背景夜色为dark -->
<meta name="color-scheme" content="dark">
<!-- 设置整体文档的行为:每30秒刷新页面 -->
<meta http-equiv="refresh" content="30">
<!-- 设置本文档与其他文档之间的关系:设置本文档的作者页 -->
<link rel="author" href="./author.html">
<!-- 传达其他主内容以外的信息: 设置文档title -->
<title>Document</title>
元数据内容标签
一般来说,元数据内容标签会统一放在head标签里面。根据HTML的内容模型,允许放在head标签里面的标签包括:title、base、link、meta、style、script、noscript、template。在这里,style我们已经很熟悉了,script、noscript、template主要是给页面提供一些脚本能力,关于script标签,我在《详解script元素》里也进行了详细的展开。本文会重点关注前面4种标签,即title、base、link和meta。
title标签
title元素表示整个页面的标题或者名字。title会被用在页面的各种存储、检索、分发的场景中,比如用户历史、浏览器标签、搜索引擎、以及各种app的分享卡片当中。
title标签有时候容易与页面中的第一个h1标签混淆,它们之间的区别,就相当于word文档的文件名与文章大标题的区别。标准里举了一个关于蜜蜂求偶仪式的HTML文档作为例子:
介绍页面:
<title>蜜蜂求偶仪式介绍</title> ... <h1>介绍</h1>下一页:
<title>蜜蜂求偶仪式使用的舞蹈</title> ... <h1>舞蹈</h1>
从这里你可以看出,title标签需要无歧义地描述页面的整体内容,而h1标签可以假定读者已知道标签所在的上下文是什么。
base标签
base标签主要有两个作用:
- 通过
href属性,设置页面的基础URL; - 通过
target属性,设置页面中的超链接以及表单提交默认使用的浏览上下文。
看一个简单的例子:
<head>
<!-- ... -->
<base href="https://www.example.com/news/index.html" target="_blank">
</head>
<body>
<!-- ... -->
<p>访问 <a href="archives.html">档案</a>.</p>
</body>
在这个HTML中,当你点击「档案」这个超链接的时候,有两个行为被修改了:
- 如果没有base标签,链接访问的是"./archives.html",而现在访问的是"www.example.com/news/archiv…"
- 如果没有base标签,新的页面会在当前标签打开(沿用同一个浏览上下文),而现在会在一个新的标签中打开(使用一个新的浏览上下文)。
所有的node节点都有一个baseURL属性,可以获取当前页面的基础URL。
关于target属性与浏览上下文,我在《document与浏览上下文》做了详尽的解释,有兴趣的读者可以前往阅读。
link标签
link元素允许开发者建立页面与其他外部资源的连接。
link标签可以创建两种不同类型的链接,一种是超链接,另一种是导入外部资源的链接。具体使用的类型由rel属性(relationship)决定:
<!-- 超链接 -->
<link rel="author" href="./author">
<!-- 导入外部资源的链接 -->
<link rel="stylesheet" href="main.css">
与a标签所创建的超链接不同的是,link标签创建的超链接不会渲染出来。即便你使用css把它强行显示出来,它也不能像a元素那样点击后导航到新的页面。这种超链接主要是用来给第三方(如搜索引擎)提供语义信息的。
掌握link标签,最重要的就是掌握rel属性,我强烈建议你阅读我的另一篇文章《详解HTML链接元素》,这篇文章里,我把所有链接元素(a、area、link、form)上rel属性的所有用法以及他们的区别都完全讲清楚了。
meta标签
当其他元数据标签都无法描述的元数据,可以使用meta标签来表达。
meta标签有三种主要的形态:
<!-- 形态1:使用charset属性定义页面的字符编码 -->
<meta charset="utf-8">
<!-- 形态2:使用http-equiv属性定义特定的指令 -->
<meta http-equiv="XXX" content="YYY">
<!-- 形态3:使用name属性声明页面的其他元数据 -->
<meta name="XXX" content="YYY">
meta标签使用charset属性声明了页面使用的字符编码形式。 所有的HTML页面都应该声明这个标签,即便一个页面的内容全都是ASCII字符。这是因为用户在提交表单,或者使用脚本生成URL的时候,有可能会用到非ASCII字符。
meta标签使用http-equiv定义特定的指令(Pragma directives)。 http-equiv只有有限的几个值,有的指令没有任何作用,只是因为历史原因还遗留:
| 值 | 解释 |
|---|---|
| content-language | 声明「指令设置默认语言(pragma-set default language)」。 确定一个元素使用的语言的顺序是(找到为止):该元素上的 lang属性 -> 祖先元素上的lang属性 -> 指令设置默认语言 -> 从更高级的协议上找,如Content-lanuagehttp头。 |
| content-type | 设置页面编码形式,一个页面不应该同时有一个meta[http-equiv=content-type]的元素和一个meta[charset]元素。 |
| default-style | 设置默认的CSS样式表 |
| refresh | 设置页面定时刷新或重定向到其他页面 |
| set-cookie | 这个指令不会有任何作用,浏览器会忽略这个指令。 |
| x-ua-compatible | 浏览器会忽略这个指令。 |
| content-security-policy | 设置内容安全策略。 |
meta标签使用name属性声明页面的其他元数据。 HTML标准预定义了一部分的值,而开发者也可以基于自己的需求去扩展这里面的值。
以下是已经被标准化的name属性值:
| name | 解释 |
|---|---|
| application-name | 如果页面是一个应用,则赋予该应用一个名称。与title的区别是,title可能带有状态信息,而这个名称是整个应用的命名。 |
| author | 作者的名字。 |
| description | 页面的描述。 |
| generator | 生成页面使用的软件。 |
| keywords | 页面关键词。 |
| referrer | 定义页面默认的referrer策略。 |
| theme-color | 主题颜色。 |
| color-scheme | 页面默认背景色。 |
当然,除了这些,你也可以根据自己的需求扩展meta标签。不过这么做之前,你应该先查看meta标签扩展页,你所需要扩展的元数据类型很可能早就有人定义过了,比如我们经常使用的meta[name=viewport]在这里就已经被定义了。
除此之外,如果扩展的name或者content的值是URL,那应该使用link标签来扩展,而不是meta标签。
使用HTTP头设置元数据
除了使用元数据标签,HTTP头也经常可以用来设置页面的元数据,代替元数据标签使用。
比如,有时候,我们即便没有设置<meta charset="utf-8">,页面也能以UTF-8编码,那是因为HTTP头上往往也做了一次字符编码形式的声明:content-type: text/html; charset=utf-8。
而meta标签上的另一个属性:http-equiv,很多人觉得这个名字长得很奇怪,它其实是「HTTP equivalent」的缩写,中文的意思是HTTP的等价形式。即http-equiv属性的每一个值,都能在HTTP协议中找到其对应的header头(理论上是这样,实际上还是有差异的):
| 关键词 | 对应的http头 |
|---|---|
| content-language | 对应Content-LanguageHTTP头,不过从检索链条上可以看出两者是有优先级上的区别的。 |
| content-type | 等同于Content-Type的http头 |
| default-style | 无对应的HTTP头 |
| refresh | 等同于Refresh的http头 |
| set-cookie | 对应Set-Cookie的http头 |
| x-ua-compatible | 对应X-UA-Compatible的http头 |
| content-security-policy | 等同于Content-Security-Policy的http头 |
除此以外,link元素也有自己一种等价的http形式,可以使用Linkhttp头来进行设置,格式如下:
Link: <uri-reference>; param1=value1; param2="value2"
所以,以下两种形式是等价的:
// HTTP头:
Link: <https://example.com>; rel="preconnect"
// 元数据标签:
<link rel="preconnect" href="https://example.com">