收藏本站腾讯微博新浪微博

经典论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

蓝色理想 最新研发动态 网站开通淘帖功能 - 蓝色理想插件 论坛内容导读一页看论坛 - 给官方提建议

论坛活动及任务 地图和邮件任务 请多用悬赏提问 热夏来袭,选一款蓝色理想的个性T恤吧!

手机上论坛,使用APP获得更好体验 急需前端攻城狮,获得内部推荐机会 论坛开通淘帖功能,收藏终于可以分类了!

搜索
查看: 5070|回复: 16

[教程] [原创] 如何在 IE6,7 下实现 white-space: pre-wrap;

[复制链接]
发表于 2009-12-28 16:54:10 | 显示全部楼层 |阅读模式
如何在 IE6,7 下实现 white-space: pre-wrap;

 

HTML 的空白符处理规则

HTML 中的“空白符”包括空格 (space)、制表符 (tab)、换行符 (CR/LF) 三种。

我们知道,在默认情况下,HTML 源码中的空白符均被显示为空格,并且连续的多个空白符会被视为一个,或者说,连续的多个空白符会被合并。

然而在有些时候,我们希望 HTML 源码中的多个连续空格在网页浏览器中可以真实地呈现,或者需要源码中的换行符能起到真正的换行作用。于是,我们发现了 <pre> 标签,它可以真实还原它内部文本的空白符的真实情况。

于是我们经常会把一段表示计算机代码的文本放进 <pre> 标签中,它们在浏览器中会表现出自身的空格缩进和换行效果,而不需要我们增加额外的样式和标签来控制它的缩进和换行。

随着对 CSS 的了解不断深入,我们发现,原来这一切都是 white-space 属性在安排。<pre> 元素之所以如此神奇,是因为它自身具有 {white-space: pre;} 这一默认样式。

 

white-space 属性

CSS 中的 white-space 属性用于设置文本空白符的处理规则,这其中包括:是否合并空白符、是否保留换行符、是否允许自动换行。各属性值的不同行为如下表所示:

  1. white-space 属性值一览表
  2. -----------------------------------------------
  3. 属性值    空白符  换行符  自动换行  最早出现于
  4. -----------------------------------------------
  5. normal    合并    忽略    允许      CSS 1
  6. nowrap    合并    忽略    不允许    CSS 1
  7. pre       保留    保留    不允许    CSS 1
  8. pre-wrap  保留    保留    允许      CSS 2.1
  9. pre-line  合并    保留    允许      CSS 2.1
  10. -----------------------------------------------
复制代码


(注:在 CSS1/2 下,white-space 属性只可应用于块级元素;在 CSS 2.1 下,可应用于所有元素。)

如果我们需要某个容器元素具有类似 <pre> 元素的空白符处理行为,则为它设置 {white-space: pre;} 样式即可。

 

对 pre-wrap 的需求

我们先解释一下上述表格中的“自动换行”行为,它是指某元素内部的文本流按照文本方向排版,当文本流遇到限制其继续延伸的边界时,是否换行。“不允许自动换行”则意味着文本流会溢出该元素。

因此,{white-space: pre;} 样式有时候并不能满足我们的期望。比如,在某些不需要特别严谨的场合,或者排版某些对换行不敏感的代码片断(比如 HTML 或 CSS)的时候,我们不希望代码片段中的一行长代码令它的容器元素产生水平滚动条,因为那样不便阅读。我们希望在这种情况下,长代码自动换行就好。

这时,对照一下上表中各属性值的不同行为特征,我们会发现 pre-wrap 这个属性值脱颖而出——它正是我们所需要的。

 

对 pre-wrap 的另一种需求

再来看另一种实战中可能会遇到的情形。

表单中的文本域(<textarea> 元素)可以接受包含换行符的文本数据,这是它有别于文本框(text 类型的 <input> 元素)的重要特征之一,所以我们通常也称它为“多行文本框”。

随之而来的一个问题就是,我们通过多行文本框提交多行文本数据,是为了在网页上最终显示出多行文本。但由于浏览器对 HTML 源代码默认进行空白符合并处理,为了确保我们提交的多行文本数据最终在网页上正确地呈现出多行的形态,通常需要在服务器端做处理,比如将文本中的换行符转换为 HTML 的换行标签 <br>,再写入数据库;或者从数据库中读出文本数据时进行类似的转换操作。

这样当服务器向网页输出这些文本数据时,原始的回车状态才能得到再现。

但是,由于设计失误(或系统有意限制),服务器端可能就不会做这样的处理。从而导致这些文本信息中的换行符无法呈现出换行效果,取而代之的是一个小空格。

(下图为 cnBeta 网站对评论文本的两种不同处理方式:左侧为普通评论,可能为了限制各条评论的高度、防止恶意刷屏,系统未做换行符转换处理;右侧为热门评论,系统进行了处理。)



如果服务器端因为疏忽没有做换行符转换处理,那么在前端是否可以用最小的代价来补救?这时,pre-wrap 就可以发挥作用——无需做任何的额外处理,直接为文本的容器元素设置 {white-space: pre-wrap;} 样式,就可以还原多行文本的真实状态。

 

杯具的 IE6 和 IE7

再来看一下上面的表格,我们发现 pre-wrap 是从 CSS 2.1 才开始引入的属性值。然而,目前网民使用最为广泛的 IE6 和 IE7 浏览器都是基于 CSS1 和部分 CSS2 的,它们完全不能识别 pre-wrap,当然也无法实现 pre-wrap 的空白符处理行为。

在疯狂地问候了微软、IE 及其相关人等之后,网页开发者们还是不得不面对这个问题——如何在 IE6,7 下实现 pre-wrap 的效果?

 

在 IE6,7 下变通实现 pre-wrap

经常反复测试,我们找到了在 IE6,7 下变通实现 pre-wrap 效果的方法。

比如,有如下 HTML 结构:

  1. <div class="content">这是一段多行文本数据
  2. 其中某些文本行会非常长从而溢出容器比如你现在看到的这行
  3. 行与行之间有换行符
  4. 但没有使用 HTML 换行标签</div>
复制代码


我们需要将 .content 元素设置为 pre-wrap 样式,理想情况下只需要编写如下 CSS 代码就可以了。

  1. .content {
  2.     white-space: pre-wrap;
  3. }
复制代码


但为了应付 IE6,7,我们需要将上述 CSS 代码修改如下:

  1. .content {
  2.     white-space: pre-wrap;
  3.     *white-space: pre;
  4.     *word-wrap: break-word;
  5. }
复制代码


这样就可以了,我们在各浏览器中实测一下,可以发现我们需要的效果完美实现。

当然,你可能注意到了,我们使用了一点儿 CSS hack。别担心,它们条理清晰并且容易维护,我觉得这可以接受。在面对低能浏览器的时候,我们只能给予它们一些额外关照。

 

原理

如果你是一个实用主义者,那么文章到这里已经结束了。如果你是一个充满好奇心的 CSS 学习者,那么我很乐意与你一起来分析一下它的实现原理。

在上面的最终版 CSS 代码中,很显然对于标准浏览器,我们是用正常的 {white-space: pre-wrap;} 来实现所需效果的。而对于 IE6,7,我们使用了 CSS hack,让它接受额外的样式声明,使用其它方法来实现类似 pre-wrap 的效果。

首先,在 IE6,7 下,{white-space: pre-wrap;} 这条样式声明由于不能识别而被丢弃,于是我们为 .content 另外设置了 {white-space: pre;} 的样式。我们已经很熟悉 pre 了,它的特性与我们想要的 pre-wrap 效果只有一点区别,即 pre 不允许自动换行,也就是说,较长的文本行可能会溢出其容器元素。

因此,接下来,为了让这些较长的文本行自动换行,我们为 .content 元素设置 {word-wrap: break-word;} 样式(谨慎起见,我们用 CSS hack 将这条声明隔离给 IE6,7;不过即使将它暴露给所有浏览器,它也是无害的)。这条声明负责对 .content 元素内的文本行进行约束,并强制其换行。也就是说,{white-space: pre;} 完成了识别文本换行符的任务,剩下的自动换行的任务交由 {word-wrap: break-word;} 来完成。

插播 word-wrap 的相关资料

CSS 发展至今经历了多个版本,但它对文本排版的控制仍然不够精确和灵活。于是微软的 IE 浏览器开发了一些私有属性,扩展了 CSS 的文本排版功能,尤其可贵的是,这些扩展属性大多考虑到了非拉丁语系语言的排版规则。由于这些私有扩展属性确实很有价值,它们被整理并收录到了 CSS3 草案中。

word-wrap 属性就是其中很有代表性的例子。它决定了文本行超过容器的边界时是否断开转行。目前这一属性已经得到了绝大多数主流浏览器的支持。


回到前面的原理分析,其实我们会发现一个矛盾,{white-space: pre;} 很倔犟地不愿换行,而 {word-wrap: break-word;} 则要求内部文本自动换行。面对这样的冲突,浏览器如何决断?

在 CSS 中,控制文本换行方式的属性有很多,当发生冲突的时候,某些属性在文本排版中的优先级更高,因而会在冲突中胜出,决定最终的文本样式。很显然,在上面的这起冲突中,{word-wrap: break-word;} 更加强势,倔犟的文本行最终还是乖乖地换行了。

 

结语

感谢你看到了这里,希望这篇文章对你有所帮助!



[[i] 本帖最后由 birdstudio 于 2010-6-24 10:39 编辑 ]

评分

参与人数 1威望 +2 收起 理由
14px + 2 实用、详尽,受益匪浅。

查看全部评分

发表于 2009-12-28 18:13:07 | 显示全部楼层
好文。。。

  1. .content {
  2.     white-space: pre-wrap;
  3.     *white-space: pre;
  4.     *word-wrap: break-word;
  5. }
复制代码

顺序好象不能换。。。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2009-12-29 09:56:09 | 显示全部楼层

回复 2# shadowhuan 的帖子

顺序应该没有影响,回头我再测试验证一下。这样写只是为了便于对照和注释。
回复 支持 反对

使用道具 举报

发表于 2009-12-30 09:11:24 | 显示全部楼层
学习了。
原来white-space还有这么多的值,IE正好可以拿私有属性word-break: break-all + white-space: pre来解决无法实现的pre-wrap,真是绝妙!
最近的一个项目正好需要(源码展示部分),太感谢LZ了。

PS. 不知道是不是我网络不太好,图片看不到,但不影响对文章的理解。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2009-12-30 10:35:39 | 显示全部楼层

回复 4# 14px 的帖子

谢谢加分,呵呵。

p.s. break-all 跟 break-word 还是有点区别,break-word 更安全一些,不会打断正常的英文单词。
回复 支持 反对

使用道具 举报

发表于 2009-12-30 10:48:08 | 显示全部楼层
打了那么多字很累吧,辛苦了。来赞一个。
回复 支持 反对

使用道具 举报

发表于 2009-12-30 10:55:35 | 显示全部楼层
看了文章还没试过,认真试过才知道word-break:break-all根本冲破不了white-space: pre,我只是通过你的文章臆想到word-wrap:break-word既然可以用,word-break:break-all也应该会很强势。。。结果大囧了一把。

基础太不过关啊。。。 =。=
回复 支持 反对

使用道具 举报

发表于 2009-12-30 11:21:48 | 显示全部楼层
在特殊情况下稍微还是有点硬伤,比如中英文混合,因为要求英文字体必须为 Arial,  也许一般处理中文的都比较容易不用考虑英文的字体,但对于英文表现的字体有特殊规定的情况下.
比如:  Arial

 提示:您可以先修改部分代码再运行


[[i] 本帖最后由 angell8684 于 2009-12-30 11:27 编辑 ]
回复 支持 反对

使用道具 举报

 楼主| 发表于 2009-12-30 12:07:32 | 显示全部楼层

回复 8# angell8684 的帖子

谢谢你的反馈,不过我不太懂你的意思。你说的是 pre-wrap 的硬伤,还是文章的硬伤?
回复 支持 反对

使用道具 举报

发表于 2009-12-30 15:07:34 | 显示全部楼层
这个很好,这两个属性平常我只是简单的拿来用,根本没深究过,
你研究的真透,厉害,
大力支持!!

(在BI可以常看到这种好文,真好)
回复 支持 反对

使用道具 举报

发表于 2009-12-31 20:37:12 | 显示全部楼层
- -怪不得感觉文章这么熟悉,原来上次在你博里看过了
在IE6里对中文应该算软伤吧,中文的书写习惯不会无故的空格,只加标点,除了首行空两格。
不好看的话,把IE6的私有属性word-break:keep-all也加上,,感觉我又给它添了一道伤。
回复 支持 反对

使用道具 举报

发表于 2010-1-3 16:54:36 | 显示全部楼层
杯具。。。完全没注意过。。。

只用过shite-space的nowrap...

break-word和break-all也不清楚他们的区别,看了似乎了解了点,前者是段落换行,后者是单词换行?Orz

8楼的例子在火狐下看就觉得好神奇。。。
回复 支持 反对

使用道具 举报

发表于 2010-1-4 09:28:56 | 显示全部楼层
感谢LZ分享,给予我们菜鸟一个新的知识。
回复 支持 反对

使用道具 举报

发表于 2010-1-4 13:13:47 | 显示全部楼层

很经典的文章

一直在用。。一直不明其根。。。看过此文顿悟。。
回复 支持 反对

使用道具 举报

发表于 2010-1-4 13:34:16 | 显示全部楼层
顿悟
回复 支持 反对

使用道具 举报

发表于 2012-2-7 15:46:52 | 显示全部楼层
不得不说这确实是一篇好文章,受益了,谢谢。
回复 支持 反对

使用道具 举报

发表于 2012-2-7 15:59:47 | 显示全部楼层
真是好文,赞一个。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

QQ|小黑屋|Archiver|手机版|blueidea.com ( 湘ICP备12001430号 )  

GMT+8, 2020-11-24 21:01 , Processed in 0.124686 second(s), 13 queries , Gzip On, Memcache On.

Powered by Discuz! X3.2 Licensed

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表