CSS中文注释引起IE样式失效问题的解决方案

先看DEMO,在chrome、safari、firefox下,页面显现正常的绿色背景,而在IE下,页面背景为白色。经过分析引起的原因是:

1、HTML页面编码与CSS编码不同(DEMO中HTML为gbk,CSS为utf-8)

2、CSS文件中未指定@charset头声明,导致IE默认使用页面编码来解码CSS文件(DEMO中IE浏览器使用gbk来解码一个utf-8的CSS文件)

3、中文注释中的汉字为奇数个数时,会与结尾的“*/”组合成新的合法字符,导致注释未能正确关闭,造成紧跟其后的样式被自动注释,从而引起样式失效。

例如,该DEMO中CSS代码为

/*叶落花*/
body{background-color:green;}

如果你问我为什么IE中会有这个问题,kevinxue告诉过我,经研究表明“用IE的人会变蠢”……(IE同学蹲地下默默画圈:其实safari4的早期版本中也存在这个BUG- -!)。

解决方案有以下几种:

  • 方案一:在中文注释两边加空格(其实只用在右侧加空格),例如 /*叶落花*/改为/* 叶落花 */。或者通过css压缩工具删除所有注释。
  • 方案二:将CSS编码与HTML页面编码统一(DEMO里将CSS另存为GBK格式即可),主要看实施起来是否方便了。
  • 方案三:在CSS文件头部增加@charset的声明,明确告诉浏览器文件编码是什么。

基于方案三,我写了个python的命令行小工具,取名叫utf8css,它的作用是:

  • 将指定目录中的所有CSS文件(包括子目录),转码为utf-8编码
  • 同时为CSS增加@charset “utf-8″的头部
  • 该脚本已经过Win7与Mac的测试,支持SVN只读文件的修改

如果你的CSS原本就是utf-8编码并且已经包含@charset头,则不会做任何改动。如果你问我为何要转utf-8而不是转成gbk,你去看看为啥我这么简单的DEMO还要用PHP来写就知道了,简单的来说,更洋气~

有装python的同学,可以先安装下chardet模块(据说该模块是作者是从firefox的自动编码检测模块中移植过来的,所以知道为什么firefox没有这个BUG了吧……),然后下载utf8css的python源码使用。没有python的同学,直接下载绿色版zip包即可在windows下使用。这里有张运行示意图

接下来会分析下:为何奇数汉字会造成解码出错呢?有兴趣的同学可以继续往下看。

首先得从文件编码说起,不太了解的同学先google一下gbk与utf-8编码的区别吧,这里直接引用其中相关的部分:

GBK的文字编码是双字节来表示的,即不论中、英文字符均使用双字节来表示。UTF-8编码则是用以解决国际上字符的一种多字节编码,它对英文使用8位(即一个字节),中文使用24位(三个字节)来编码。

以汉字“叶”字为例:

其unicode编码为 \u53f6 ,utf-8编码为\xe5\x8f\xb6,存储空间占用3个字节,gbk编码为\xd2\xb6,存储空间占用2个字节。

如果将utf-8编码当做gbk编码来做unicode解码(这就是DEMO中的CSS在IE中所发生的悲剧),则会因为字节数不为偶数,而发生解码异常(前面说的gbk编码是双字节的),如果抑制异常,则会将utf-8编码中最后一个字节码(“\xb6”)忽略掉,并将其剩余部分(\xe5\x8f)转为新的unicode码,即\u9359 。这个新的字符是什么?在firebug console中,敲上一句“s = “\u9359″”得到“鍙”字,不知道怎么读。总之,长的就是一副乱码相- -!

以上推论源于python GUI中的实验,见截图:

可以看到DEMO中的注释“/*叶落花*/”被IE解码过之后的unicode为:“/*\u9359\u60f0\u60e4\u947a/”,在firebug里看看是什么?

/*鍙惰惤鑺/

长得就是一副乱码相,更重要的是注释结尾的“*”被转丢了,从而导致其后的样式被注释掉失效

事情发生的经过是,注释中的三个utf-8汉字占用了 3×3=9个字节,而gbk要求每个字符为2个字节,即总数需要为偶数。因此IE将其后占用1个字节的utf-8字符“*”,与前面的9个字节加在一起,当成10个字节的gbk字符进行转码。但很显然“花”的第三个字节“\x8a”与单字节“*”一起,连乱码都组合成不了。因此最后得到的乱码字数为 (3×3+1)/2 -1 = 4。

讲到这里基本就全都明了了,“至于你信不信,我反正信了”。留下一个小练习:

如果CSS中的注释改为“/*叶落花开*/”,那么得到的乱码是什么,是否会导致样式失效?

欢迎关注我的微信公众号「猫哥学前班」

原文地址:https://www.cnblogs.com/kaiye/p/3039045.html