文件乱码的情况我相信大部分人都遇到过,主要乱码的就是中文和其他一些字符。因为原来计算机是不支持中文的,所以我们在使用外国人发明的语言的时候都应当尽量避免使用中文。

在 CSS 中声明字符编码

文件乱码总的来说是一个低级的问题,问题多低级不重要,重要的是怎么解决问题。首先要知道我们的文件为什么会乱码,乱码的都是哪些字符。其实只要我们的文件不是 UTF-8 编码,并且存在了非 ASCII 字符,就可能存在乱码的问题。点击这个链接可以查看「什么是 ASCII 码?」最新的 ASCII 码包含了 128 个字符,这其中就有 26 个基本拉丁字母、阿拉伯数字和英式标点符号,总之没有包括中文与特殊字符。ASCII 的诞生源于计算机的初始时代,当时美国人没有意识到计算机还能被外国人使用。由于 ASCII 的局限性所以现在普遍使用 Unicode。根据 W3C 的说明,声明一个 CSS 文件有以下几种方式:

  • 一、使用 @charset 方式

@charset 的方式大家都用过,这是 HTML5 提供一种用于声明 CSS 文件编码的方式。虽然这个 @charset看起来很像 CSS 当中的 @ 规则(@keyframes、@media、@font-face...),但是我们并不能在文档内部使用它,必须要在 CSS 文件所有字符的前面(包括编码注释),@charset 才会生效。如果你在文档内部使用了,将会被直接忽略。所以下面几种方式都是错误的:

/* 注释 */ 
@charset "utf-8";
body { background: red; }  
@charset "utf-8";

@charset 中的编码名称常见的有下面这几种:

@charset "gbk";
@charset "gb2312";
@charset "utf-8";

需要注意的是:我们应当始终使用 @charset "utf-8"; 这种方式,并且 @charset 方式是区分大小写的。由此下面这种方式是不正确的:

@charset "UTF-8";
@CHARSET "utf-8";

Note! It is not enough to simply put @charset "utf-8"; at the top of the style sheet – you need to also save your style sheet in the UTF-8 character encoding. (See Using an encoding with your content.)

仅仅使用 @charset "utf-8"; 来给文件编码是不够的需要将文件的编码设置为 UTF-8 编码,才能生效。

  • 二、使用 BOM 头方式

关于文件 BOM 头,可以查看维基百科的解释,所谓 BOM 头其实是就在文件的头部存放三个影藏的字节,如 UTF-8 编码即为 EF BB BF, 这个字节被软件使用来判断当前的文件的编码类型。这看起来很机制,但是也带来了很多的问题,绝大部分后台代码都需要移除 BOM 头,应为软件在读取文件的时候会把 BOM 当做编码的一部分来处理。

前端方面,对于一个 CSS 文件能够让浏览器识别文件的编码并以正确的方式解析。CSS3 的语法规范:如果你的文件起始部分有一段 BOM 头的存在,这会导致浏览器忽略其他编码声明使用 utf-8 编码读取当前文件。但是 BOM 也并不是万能的,IE10 和 IE11 给予 HTTP 消息头和 @charset 一个更高的优先级。所以我们不应该完全信赖文件 BOM 的方式来处理文件编码,转而使用 @charset 和 HTTP 消息头的方式来替代,BOM 的方式是不可见的,其他两种方式能够让人显而易见的知道当前文件的编码。

  • 三、使用 HTTP 消息头方式

web上访问一个文件基本都是通过 HTTP/HTTPS 方式来传输的,通过给 HTTP 消息头的 Content-Type 加上一个编码方式 charset=utf-8;这种方式声明当前这个文件的编码类型

Content-Type: text/css; charset=utf-8  

这种方式可以通过 web 服务器或者后端代码方便的实现到这一点,以 nodejs 为例: res.writeHead(200, {'Content-Type': 'text/plain;charset=utf-8'});。实际上就是在返回响应的时候 setResponseHeaders 做到的。这种 HTTP 声明的方式优先级最高,永远会覆盖文档内部的声明,除非当前文档内部存在了 BOM 头声明[todo]。

使用 HTTP 消息头方式声明 CSS 字符编码

所以最佳的方式就是在文档内部使用 @charset 方式,并且同时使用 HTTP 方式。这能够保证你的文件即使不在 web 环境,也能被识别当前编码。

  • 四、其他方式

HTML4.01 规范了 link 标签可以使用 charset 方式来表明当前文档关联的样式表编码方式,但是 HTML5 废除了这种规范。

文档内部的声明方式,同样也被作用于关联的 CSS 文件 <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">

待续。