首先坦白,只有在遇到乱码的时候,我才会下定决心去学习和了解(或者叫重温)关于字符编码的知识。在网上林林总总看了很多关于字符编码、字符集的文章,在这里尝试做一个归纳与总结。此外,这篇文章也会涉及一些前端工程师在「字体」或者「字符编码」方面的相关讨论。
这篇文章不会深入的探究每一个知识点(有心也无力啊),但会尽量能将所有可能涉及的知识点罗列出来,供你进一步的探索和挖掘。
术语
个人认为掌握字符编码这一块儿的知识的最大难点在于术语的学习,字符、字体、编码、字符集、编码字符集、字符集编码、字符映射、字符表、Unicode、UTF-8、GBK 等等等等,很多不熟悉字符编码的人看到这里都已经觉得头大。下面罗列一些常见的与字符编码有关的术语及简单解释:
字符(Character):所有的文字、符号的总称,包括可见的字符(英文字母、中文汉字、标点符号)和不可见的控制字符(如程序员喜闻乐见的 \r\n 及 \t 等)。
字符集(Charset):一个系统支持的所有字符的集合。常见的字符集包括 ASCII 字符集、Unicode 字符集、GB系列(GBK、GB2312等)字符集等。
字符编码(Character Encoding):狭义的说,字符编码指的是将字符集中的字符编码为计算机可以识别的比特信息,以便计算机识别及储存。「字符编码」这一术语可以指一种编码方式,也可以指编码本身的过程。常见的编码方式有 ASCII、GB系列、UTF-8 等。
字体(Font [1]):即文字的样式。常用的字体包括华文宋体(SimSun)、微软雅黑(Microsoft YaHei)等。
能够正确认识以上四个概念,你对字符编码的理解就已经进步很大的一个台阶了。当然,如果你感兴趣,可以在维基百科上浏览所有与字符编码有关的术语,以便加深理解。
GBK 与 Unicode
作为一个前端工程师,你闭着眼睛也能写出下面的代码:
<meta charset=”utf-8” />
当然,对于一些比较老的网页,尤其是那些页面底部标注着「推荐使用 IE5.5 及更高版本浏览器,1024*768 分辨率访问本站」的网页,你更可能看到的是:
<meta http-equiv=”Content-Type” content=”text/html; charset=GBK” />
可以明显的看到,两个 meta 为网页指定了不同的 charset,即上文提到的字符集(严格意义上来说,第一个 meta 的意思应该是「使用 Unicode 字符集,并使用 UTF-8 编码方式」)。那么为什么会出现这两种不同的 charset 呢?
简单的来说,UTF-8 编码 Unicode 字符集中的英文字符只需要 1 个字节,而对于中文则需要 3 个字节;而 GBK 编码任何字符都需要 2 个字节。这样在传输大量中文内容时,GBK 编码方式有优势了。
实际上采用 GBK 编码的网页还存活至今的原因并不是这么的「技术化」,仅仅是因为历史遗留因素导致很多政府、大学网站在早期开发时采用了 GBK 并一直沿用至今。从兼容性方面考虑,GBK 远远不如 UTF-8 等针对 Unicode 字符集的编码方式 。另外,根据还没有考证的说法[2],服务器在开启 Gzip 之后传输不同编码的网页时差别并不明显。
因此作为一个有节操的前端工程师,在写一个新的网页的时候应该果断写下第一种 meta。在这里多提一句,上述两种 meta 的写法在声明了 html5 的 doctype 后效果是一致的,但是大家普遍约定使用第一种方式。
UTF-8 与 BOM
BOM(Byte Order Mark,字节顺序标记):BOM 本身是一个字符,在 Unicode 中的码点是 U+FEFF,通常被放在文件的开头,用于标示字节的顺序。关于什么叫做「标示字节顺序」,建议参阅维基百科关于 BOM 的页面。
前端工程师遇到的很常见的一种情况就是,明明在 html 里声明了 charset 是 utf-8,为什么还会出现乱码?这是因为你的文件编码或服务器返回的 HTTP 头中没有指定正确的编码格式。
在讨论文件编码时,不得不黑一下 Windows 自带的记事本。多少人写第一个网页的时候就是用的记事本啊,可是记事本所谓的「ANSI」编码又坑了多少纯洁善良的孩子。
先解释一下 Windows 的记事本在保存文件时格式的区别:
[caption id=”attachment_207029” align=”aligncenter” width=”434”] Windows 下记事本保存文件时的格式选择[/caption]
- 「ANSI」指的是对应当前系统 locale 的遗留(legacy)编码,比如简体中文 locale 时 ANSI 编码即 GBK 编码
- 「Unicode」指的是带有 BOM 的小端序 UTF-16
- 「Unicode big endian」指的是带有 BOM 的大端序 UTF-16
- 「UTF-8」指的是带 BOM 的 UTF-8
然后说明一下为什么这几种保存方式都不是最佳选择(最佳选择是不要用 Windows 自带的记事本)。
首先 ANSI 即万恶的 GBK,忘掉它吧,洗心革面做一个五讲四美拥抱 21 世纪新社会主义社会的好程序员。其次 Unicode 及 Unicode big endian 使用的都是 UTF-16 的编码方式,这种方式虽然很好(所有字符都采用 2 个字节编码),但是毕竟不普及。唯一看起来不错的 UTF-8 却带上了万恶的 BOM。
对于 UTF-8 来说,BOM 完全是没有必要甚至不应该有的,在 html 文件中添加 BOM,有很大几率会导致网页内容无法正常显示。
因此你需要的是一款懂得妥善处理字符编码的文本编辑器,比如 Notepad++,比如 Sublime Text,然后果断的选择「UTF-8 without BOM」。
还有一种导致乱码的可能是服务器没有返回正确的文件编码方式,打开 Chrome 随便请求一个页面,在 Response Header 中可以看到有这么一项内容:
[caption id=”attachment_207031” align=”aligncenter” width=”611”] HTTP 响应头中的 Content-Type[/caption]
这一行内容就是服务器告诉浏览器,返回给你的文件是什么内容,以及采用了何种编码方式。如果你在 html 文件里设置了 charset=utf-8,可是在 HTTP 响应头的 Content-Type 里看到的却是 GBK,那就要检查一下 WEB 服务器在返回文件时的头信息设置了。
所以总的来说,要保证你的网页内容能够正常显示,你需要做到以下三点:
- 在 html 代码中声明正确的 charset
- 将 html 文件保存为正确的编码方式
- 配置 WEB 服务器返回正确的 Content-Type
及更多
这里的「及更多」,主要是想讨论一些关于字体排印(Typography)方面的想法和心得。其实作为一个程序员,我本来对字体排印没有任何的了解,在写文章或用 PS 制作海报时,总喜欢把各种花里胡哨的元素往上拽。但是在知乎上泡久了,再加上前端工程师(实习)的工作经历,让我对字体排印有了新的、但是依然很浅薄的认识。
一个最基本的内容就是,对于网页设计,标题和正文应该分别采用什么字体。一般对于中文网页来说,似乎也只有中易宋体(SimSun)和微软雅黑(Microsoft YaHei)两种可以选择。这里还牵扯到一点,即选择衬线字体还是非衬线字体。我的经验是,对于标题,可以使用微软雅黑,但是如果通篇正文都使用微软雅黑,再加上 Windows 糟糕的字体渲染,那对于读者来说就是一种莫大的痛苦。
此外,行高和字间距的设置,也能很大程度的影响网页的阅读体验。在这方面,知乎上有很多的大牛可以关注,如@梁海等。
在细节方面,还有几点想要谈谈。一个是关于标点符号的使用,如果你细心的话会发现这篇文章所有应该使用双引号的地方,都被「」这两个符号代替了。这一点也曾经在知乎上引起了轩然大波,在这里不评论使用哪一种标点符号是正确的,我只认为「」在配合中文使用时显得更有美感。另一点则是中英文混排以及英文拼写的问题。在中英文混排时,我习惯在中文和英文之间手动加上半角空格,以便读者能够快速辨析,同时我也注意到 Microsoft Word 在处理中英文混排时似乎也自动加上了空格。关于英文拼写,我只想说,各位做前端的大神们,请不要把「iPad」拼成「ipad」甚至「Ipad」好吗!
以上文字全部出自我的浅薄认识,如果有任何错误,请批评指正。
注解
[1] 关于应该将什么单词翻译为字体,曾经是比较模糊的。维基百科词条认为 「typeface」应该被翻译为「字体」,而「font」应该被翻译为「字型」。在这里,我还是使用了现代操作系统的惯例,将「font」翻译为一般意义上的字体。
[2]来自知乎用户@米粽的评论。
参考及引用
- 一系列维基百科页面
- 「带 BOM 的 UTF-8」和「无 BOM 的 UTF-8」有什么区别?网页代码一般使用哪个?
http://www.zhihu.com/question/20167122 - 很多网站源码都是分为 GBK 和 UTF-8 版,为什么要同时开发两种?
http://www.zhihu.com/question/20209966 - Windows 记事本的 ANSI、Unicode、UTF-8 这三种编码模式有什么区别?
http://www.zhihu.com/question/20650946 - 字符集和字符编码(Charset & Encoding)
http://www.cnblogs.com/skynet/archive/2011/05/03/2035105.html