lang 属性 是一全局属性,用于定义元素的语言。

如:

<html lang="zh-CN">
<p lang="zh">

可以看到,由于 lang全局属性,因此可以指定在任意元素上。

此外,如果一个元素上指定了 lang,那么该元素的子元素的语言也会被认为是 lang,即 lang 属性会被继承

所以,如果我们在 <html> 元素上写明了 lang,那么我们也就为整个页面指定了 lang

要想为整个页面指定语言,我们还可以使用 meta 标签,如:

<meta http-equiv="content-language" content="zh-CN">

lang 属性中的语言标签的格式规范由 BCP47 定义,其形式如 ll, ll-CC, ll-Script-CC。具体如 zh, zh-CN, zh-Hant-TW。示例中所用的大小写为推荐写法,不过语言标签本身是大小写无关的。

为什么要为页面指明 lang

那么我们为什么要为页面指明 lang 属性呢?

这里至少有两方面的考虑,其一在于样式,其二则在于搜索引擎优化

样式

当我们没有为 html 或其他元素指明所要用的字体(font-family)时,浏览器就会使用一套默认的字体,而其所选用的字体是语言相关的。因此,为页面指明语言,可以帮助浏览器更好地选择默认字体。

SEO(搜索引擎优化)

搜索引擎索引网站内容时也需要知道网站适用的语言和国家/地区,从而能够更好地为用户返回搜索结果。

如页面上缺失相关语言信息,搜索引擎往往也会给出警告。

如 Bing 就会报告页面缺失 meta language 信息:

Bing SEO 分析 - 页面缺失 meta language 信息

注意:Bing 的建议操作中提到也可以在 <title> 标签上使用 lang 属性,但我并不推荐这么做,因为在 <title> 上写明的 lang 属性只对 <title> 元素生效,而不能代表页面上其他元素的语言。

通过 JS, CSS 访问 lang 属性

我们已经知道了如何在 HTML 中为一个元素指定 lang 属性,同样的,我们也可以在 JS 中访问指定元素的 lang,或为其设定一个新的 lang

var el = document.querySelector('html');
// 获取元素的 lang
var lang = el.lang;

// 为元素设定新的 lang
el.lang = 'en';

如果需要在 CSS 中根据元素的 lang 来设定相应的样式,我们也有多种写法:

/* 写法一: 仅匹配指明了 lang 属性的元素 */

/* 使用这种写法我们可以写一些会被继承的 CSS 规则,
   或只适用于有 lang 属性的规则。 */

[lang="zh-CN"] {
	/* CSS 规则 */
}
/* 写法二: 匹配所有指明了语言的元素 */

/* 该写法与写法一所不同的是,不仅会匹配指明了 lang 属性的元素,
   也会匹配其子元素,因为 lang 属性是会被继承的。 */

/* 注意: IE < 8 不支持 :lang */

:lang(zh-CN) {
	/* CSS 规则 */
}
/* 写法三: 混合写法一和写法二 */

[lang]:lang(zh-CN) {
	/* CSS 规则 */
}

有了以上几种写法后,我们举例来说这些写法到底能匹配到什么元素,比如有如下页面:

<html lang="zh">
  <head></head>
  <body>

    <div id="div1" lang="zh-CN">
      <p id="p1"></p>
    </div>
    <div id="div2" lang="zh-TW">
      <p id="p2"></p>
    </div>
    <div id="div3" lang="zh-cn">
      <p id="p3"></p>
    </div>
    <div id="div4" lang="zh-tw">
      <p id="p4"></p>
    </div>
    <div id="div5" lang="en">
      <p id="p5"></p>
    </div>

  </body>
</html>
  • [lang="zh-cn"] 会匹配到 #div1#div3
  • [lang="zh"] 只会匹配到 html

  • :lang(zh-CN) 会匹配到 #div1, #p1, #div3#p3
  • :lang(zh) 会匹配到 html, head, body, #div1, #p1, #div2, #p2, #div3, #p3, #div4#p4。 即除 #div5#p5 的所有元素;
  • :lang(en) 会匹配到 #div5#p5

  • [lang]:lang(zh) 会匹配到 html, #div1#div3

以上示例中,我们也可以看到无论是 CSS 选择器中的语言标签还是 lang 属性中的语言标签都是大小写不敏感的。

实例

实际使用中,比较常见的用法就是根据语言的不同,选用不同的字体,如 Zzz.buzz 的样式中有如下代码:

body {
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
}

[lang]:lang(en),
:lang(en) body {
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
}

[lang]:lang(zh),
:lang(zh) body {
  font-family: "Microsoft YaHei", sans-serif;
}

pre, code {
  font-family: Consolas, Menlo, Monaco, "Lucida Console", "Liberation Mono", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Courier New", monospace;
}

:lang(zh) pre, :lang(zh) code {
  font-family: Consolas, Menlo, Monaco, "Lucida Console", "Liberation Mono", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Courier New", "Microsoft Yahei", monospace;
}

上述代码中之所以要在 body 选择器上直接指明字体,一是为了为 enzh 之外的语言设置默认字体,二是为了兼容 IE 6, 7,因为 IE 6, 7 不支持 :lang 选择器。

另外,之所以写成 [lang]:lang(zh), :lang(zh) body 的形式, 而不简写为 :lang(zh) 是为了避免覆盖 pre, code, tt, kbd 等元素的默认样式。

上述 pre, code 中的字体列表取自 StackOverflow 的样式。