Things I Learned (HTML)

hreflang🔗

HTML

hreflang 是 HTML 中的一个属性值,可以在“链接”相关的 Tag 中被使用,一般在 <link> 或者 <a> 中常见(理论上也可以在 <area> 上使用)。从属性的名字中不难知道,hreflang 标注的是:当前链接所指向资源的使用语言。根据 hreflang 具体应用的标签不同,实际的使用场景也存在一定的差异。

a

<a> 标签中,hreflang 表示的是当前这个链接指向的网站所使用的语言。在明确链接指向资源使用语言非当前网站使用语言的情况下可以使用。一些常见的使用场景:

  • 在一篇中文博客中引用了一个英文的文献,链接地址可以加上 hreflang=en-US
  • 一个网站包含多语言版本,不同语言切换的链接,可以加上 hreflang 标明。

这里需要注意的是,hreflanglang 属性之间的表意差异。lang 属性表示的是当前这个标签内,使用的语言是什么;而 hreflang 表示的则是当前链接标签指向的资源使用的语言是什么。对于一个多语言网站的跳转链接来说,往往需要同时声明 langhreflang 的值,因为链接一般会用对应语言而不是当前页面使用的语言来写。举个例子来说,假设这个页面有一个对应的德语版本,那么链接可以这么写:

<a lang="de-DE" hreflang="de-DE" href="xxx">Deutsch</a>

link

<link> 标签也是用来表示链接,但是和 <a> 有所不同,前者更多的表示的是当前页面对应的外部资源文件,如样式文件(CSS),预加载文件(Preload)等。就 hreflang 的使用场景来说,<link> 标签加上 hreflang 属性,可以用来表示当前页面的不同语言版本。

举例来说,假设有一个多语言的网站,一个页面同时有中文和英文两种语言。那么,在显示中文语言的网站内,可以加上下面的 HTML 代码,用于表示不同语言对应的版本网址分别是多少。

<link rel=alternate href=https://laysent.com hreflang=zh-cmn-Hans>
<link rel=alternate href=https://laysent.com/blog/en hreflang=en-US>

这样的设置有助于帮助程序更好的了解网站的结构。举个例子来说,Google 的搜索引擎的爬虫就可以根据上述的信息了解多语言的具体实施情况(参考这里),并在用户搜索的时候,根据用户的使用习惯推荐对应的语言版本。(因而也能帮助提升网站排名,参考这里关于 ccTLDs 的介绍)

注意事项

关于 hreflang 的使用,大体有几点需要注意的:

非权威性

根据 W3C 的说明,hreflang 是一个非强制的属性:

It is purely advisory. […] User agents must not consider this attribute authoritative — upon fetching the resource, user agents must use only language information associated with the resource to determine its language, not metadata included in the link to the resource.

也就是说,hreflang 给出的内容只是作为一种参考建议(advisory)。浏览器并不会根据给出的 hreflang 信息来判断网页使用的语言,所有的判断都只会依赖于该页面内给出的具体信息。

当然,依然有足够的理由可以支撑 hreflang 被正确的使用。足够的信息可以为程序(如搜索引擎爬虫,屏幕阅读器)提供更多额外的帮助,即时当下没有被使用,也依然为未来提供了更多的可能性。

链接的完整性

当使用 <link> 进行多语言说明的时候,需要注意链接的添加是否是完整的。具体来说,如果 A 页面上有 B 页面的 <link>,那么在 B 页面上也必须有指向 A 页面的 <link> 才行。如果链接的链路缺失或者有错误,可能会导致这些数据被忽略或者错误解析。(具体可以参考 Google 给出的说明

正确的语言标签

hreflang 可以配置的属性值需要是 BCP47,这一点和 lang 属性是一致的。关于 BCP47,可以在这里找到完整的说明。

参考


BDO Element🔗

HTML

针对某些语言(如阿拉伯文字希伯来文字),文字的排列顺序是从右往左,而不是一般的从左往右排列。因此,如果有两种语言同时出现在一个文档中,那么就有可能一个段落,同时有从左往右书写的文字以及从右往左书写的文字。这种两类文字混排的情况,就是双向文稿(Bidirectional Text)。

针对这种情况,HTML 提供了一个特殊的元素 bdo,用于处理文档中特殊的文字流排列。这里 bdo 的全称是 Bidirectional Text Override。举例如下:

<p>
  This is Text Left to Right
  <bdo dir="rtl" style="color:red">Right to Left part</bdo>.
  Rest of the world.
</p>

展示效果如下:

This is Text Left to Right Right to Left part. Rest of the world.

dir 这个属性,可以用于设置当前文字应该显示的方向,可用的属性包括 ltrrtlauto 三种。需要注意的是,dir 这个参数,是针对 bdo 元素的,如果写在其他元素上,并不能起到同样的效果。比如,<span dir="rtl">Hi</span> 并不会让 Hi 显示为 iH

更多内容,可以参考 MDN


Download in HTML🔗

HTML

在 Web 中,如果希望点击一个链接可以进行下载的操作,有以下两种方案可供参考:

后端的解决方案

后端在返回 Response Header 的时候,可以通过指定 Content-Disposition 的值,来改变浏览器默认对链接的行为,从而达到让浏览器直接下载某一个资源的目的。这里,Content-Disposition 的第一个参数有两种值可写:inlineattachment。其中,inline 是默认的值,表示响应中的消息体会以页面的形式展示,而 attachment 则会将这个行为改成下载到本地。

设置成 attachment 之后,还可以进一步通过配置 filename 来指定下载文件的文件名。例子如下:

Content-Disposition: attachment; filename="example.jpg"

如此设置之后,前端在访问到这个 URL 的时候,浏览器就会以 example.jpg 为文件名下载当前的资源了。

更多相关的介绍可以参考这篇文章

前端的解决方案

除了后端的解决方案之外,前端也可以通过指定 a 标签中的 download 字段来下载文件。对于使用了 download 字段的 a 标签,点击后的默认行为将会有跳转浏览改成文件下载。download 属性可以跟一个文件名作为值,浏览器会将这个值作为下载文件的文件名来使用。

当然,前端的方案相对来说会有更多的限制,主要是以下几点:

  1. 文件必须是同域的,对于跨域的资源,download 并不会直接触发下载功能,行为上会和在新窗口打开资源一致;
  2. 如果后端在 Content-Disposition 指定了不同的文件名,那么会以后端指定的结果为准
  3. 如果后端 Content-Disposition 设置为 inline,不同的浏览器会有不同的行为:Firefox 会按 Content-Disposition 的结果来执行;Chrome 则会按 download 字段的设置来执行

更多细节可以参考 MDN 文档的相关部分。


Submit Button outside Form🔗

HTML

在一个表单中敲击回车按钮,默认会触发 <form> 的 submit 事件。当 <form> 里面有 <button type="submit"> 按钮的时候,敲击回车会先触发 button 的 click 事件,再触发 form 的 submit 事件。

因为有了这样的机制,在一个表单中,只要指定了 submit 按钮,那么不论是点击按钮还是直接按回车,都可以触发相同的 click 事件,达到同样的代码提交功能。这使得代码可以很容易的复用,不需要额外的工作量就可以让鼠标和键盘都能够方便的提交表单。

然而在实际开发的过程中,因为组件的划分,有时候不能做到 <button type="submit"> 放在 <form> 中。HTML5 中,增加了 buttonform 属性,可以用于关联表单和表单外的提交按钮。

举例如下:

<form id="form-id">
  <input type="text" name="name" />
</form>

<button type="submit" form="form-id">Submit</button>

在上述代码中,button 存在于 form 的外面,理论上和 form 是没有关联的。但是,因为 form 字段的存在,使得 form 和 button 被关联了起来。这样,和 button 在 form 中的表现形式一样,在 form 内敲击回车,就可以触发 button 的 click 事件。

注:如果 click 事件和 submit 事件(如果定义了)都没有 event.preventDefault(),那么就会触发默认的 form 提交流程,会造成页面提交。如果 form 没有指定提交的地址,那么就会提交到当前页面。这可能并不是预期中的行为。


DOM Interface🔗

HTML

当用 JavaScript 去访问 HTML 中的元素的时候,实际访问到的是 DOM 元素。比如,访问 div 元素,实际拿到的是 HTMLDivElement;访问 span 元素,实际拿到的是 HTMLSpanElement

大多数情况下,不同的 HTML 元素有不同的 DOM interface 对应,因为不同的元素很可能有一些行为/属性上的不同。

但是也存在一些 HTML 元素,并没有特定的 DOM interface 对应,直接使用了 HTMLElement 这个基类。常见的例子有 ib 或者 ruby 等。

注:根据 MDN 的说明,Firefox 中 i 对应的 DOM 是 HTMLSpanElement。但实际测试下来,最新版本的 Firefox 实现和标准是一致的,使用的 DOM interface 是 HTMLElement 而不是 HTMLSpanElement

可以用下面的方法简单的查看具体使用的是哪一个 DOM interface:

// should be: HTMLElement
document.createElement('i').constructor.name;

// should be: HTMLSpanElement
document.createElement('span').constructor.name;

Read certain type of files🔗

HTML

HTML 中的 input 组件,如果设置成 type=file,就可以变成一个文件选择控件。

默认情况下,系统默认打开的这个文件选择框,可以接受任意的文件选择。如果需要指定可以选择的文件类型,可以使用 accept 参数:

<input type=file accept="image/x-png,image/gif,image/jpeg" />

上面这个例子中,浏览器将会只接受 png / gif 或 jpg 的输入。

也可以写:

<input type=file accept="image/*" />

以支持任意类型的图片格式输入。同理,类似的比如 video/* 将会只接受任意类型的视频;audio/* 将会只接受任意类型的音频文件。

除了指定 MIME 类型之外,也可以指定后缀。比如:

<input type=file accept=".pdf,.doc,.docx" />

将会只允许以 pdf / doc / docx 这三种名称作为后缀的文件被选择。

各个浏览器的支持情况可以看这里

(当然,这个只是前端的一个校验,后端依然需要重新对前端给的输入进行检查才行)