word wrap 解惑
源起
我们经常需要“修复”一个老生常谈的“bug”,那就是文本的自动换行问题。在专业术语上,这种期望得到的渲染现象被称作“word wrap”,即文本处理器有能力把超出页边的整个词自动传到下一行。
在现实项目中,尤其是在测试阶段,鉴于测试使用非常极端的测试用例,我们经常需要“修复”如图所示的这个问题:
长单词溢出
图中,极长的这个英文单词(虽然是生造的)为了保证完整的显示,无奈地超出了容器的限制,它溢出了。为了“修复”这个“问题”,使得无论东亚还是西欧文字都能被限定在容器的尺寸范围内,我们一般会加上诸如“word-wrap: break-word; word-break: break-all;”这样的属性,令我们满意(好吧,其实是令测试满意)的结果如图所示:
长单词被强行断行
从以结果现象为导向的观点出发,这个“bug”被“修复”了,但是在做了三五次这样的重复工作后,我开始产生这样几个疑问:
- word-wrap 和 word-break 究竟是什么?
- 为什么会乐此不疲地重复碰到这个问题?
- 这个问题是问题么?
规则
在解惑之前,有几个关乎问题本质的客观现实需要指出,因为这些“常识”最容易被人忽视:
CJK 文字和 !CJK 文字有各自的排版规则。
在这里,CJK 代表 Chinese, Japanese, and Korean,即东亚文字,!CJK 就是非东亚文字,大多数情况下是西欧文字。
在文字的呈现规则上,两者很不相同,CJK 文字中,一个字母就是一个字素(单词),独立成义,!CJK 文字中,一些字母组成一个字素,并且字素们由连接符“-”连接,或由空格“ ”分隔。
- 有关 CJK 文字更多的排版规则上,比较有代表性的是:对中文来说,标点符号不能成为行首(特殊除外);双字长的标点符号(省略号、破折号)不能断开。
- 对于 !CJK,主要是:单词不能在中间不合法地断开(合法情况例如从连接符处断开);标点符号不能成为行首(特殊除外)
解惑一
word-wrap 和 word-break 究竟是什么?对于这个问题,直接拜访 W3C 官方,找到 CSS3 草案:http://www.w3.org/TR/2010/WD-css3-text-20101005/,再访问微软,借鉴诸如 http://msdn.microsoft.com/en-us/library/ms531184%28VS.85%29.aspx
得出的结论如下:
word-wrap, line-break, word-break 这几个属性都是 MS 的独立实现,随后其他浏览器也不同程度地实现了其中的某些,之后,这几个属性都被吸纳为 CSS3 标准。在对文字排版的渲染上,微软还是走在前面的。
在现有的 CSS3 草案中,关乎到文字排版的几个重要属性有:white-space, text-wrap, word-wrap, line-break, word-break
根据 CSS3 的描述,列出这些属性各自的要点,这部分读者可以跳过……
- white-space 是 white-space-collapsing 和 text-wrap 的缩写
| 属性 | 设置 white-space-collapsing | 设置 text-wrap | 空行 | 空格 | 文字自动换行 | 效果 |
| normal | collapse | normal | collapse | collapse | wrap | 忽略多余空行和空格,文字自动换行 |
| pre | preserve | none | preserve | preserve | no wrap | 保留所有空行和空白,文字不自动换行 |
| nowrap | collapse | none | collapse | collapse | no wrap | 忽略多余空行和空格,文字不自动换行 |
| pre-wrap | preserve | normal | preserve | preserve | wrap | 保留所有空行和空白,文字自动换行 |
| pre-line | preserve-breaks | normal | preserve | collapse | wrap | 合并多余空格,保留多余空行,文字自动换行 |
- text-wrap 定义文本的自动换行效果
| 属性 | 效果 |
| normal | 在允许的断点处自动换行 |
| none | 文本不会自动换行;对于不“合身”的容器,文本将会溢出 |
| unrestricted | 在任意的文法单词间都可断行,比 normal 的限制要松散很多 |
| suppress | 除非断行处没有其他任何允许的断点,方可进行断行,这比 unrestricted 严格,比 normal 松散 |
- word-wrap 执行最激进的单词断行控制,从单词的内部断开以防止文本溢出容器并且完全适应容器的宽度
- 在 IE 的实际效果中,word-break 的效果要激进得多,它穷凶极恶地断开所有单词(如果到达边界的话)
| 属性 | 效果 |
| normal | 仅在允许的文本断点处自动换行 |
| break-word | 如果一行中没有其他可接受的断点,那么将强行断开文本单词 |
- line-break 是断行的规则,针对东亚文字
- 基本是针对日文的换行规则
- word-break 是断行的规则,针对非东亚文字
| 属性 | 效果 |
| normal | 根据特定非东亚文字自己的规则来决定是否自动断行 |
| break-all | 允许非东亚语言文本行的任意字内断开。该值适合包含一些非东亚文本的东亚文本 |
| keep-all | 不允许非东亚语言文本行的任意字内断开。该值适合包含一些东亚文本的非东亚文本 |
| hyphenation | 文本会在合适的连字符处断开,这需要浏览器的支持 |
做一个归纳:专门用于控制文本自动换行功能的属性是 text-wrap 和 word-wrap,而 line-break 和 word-break 用来控制断行和单词边界分隔,根据 W3C 的描述来说,word-wrap 是最激进的自动换行方式,可以强行断开单词。而现实情况是,word-break: break-all; 的方式要更为激进,如图:
word-wrap
word-break
对比 word-wrap: break-word; 和 word-break: break-all;,两者都将文本限定在了容器的范围内,只是 break-all 将所有单词,不论长短地,通通截断,break-word 则非如此,它尽量地遵从了排版规则。
兼容性
由于几个属性都来自于微软(部分来自于 CSS3),那么理所当然 IE 是支持最良好的,不过对于浮动元素,IE67 的表现会有些 bug(可在文后给出的 demo 中验证)。
至于其他浏览器,FF 3.6 不支持 word-break;Chrome 7 支持良好;Safari 5 同 Chrome;Opera 10 同 FF
解惑二三
碰到相关问题的场景大体是两个:
- 测试使用了很极端的测试用例(比如 asdfasdfasdfasdfasdfasdfasdf)
- IE67 下,在宽度不大的容器中使用了浮动元素,同时浮动元素内包含了长的串,如图:
IE67 中浮动盒子杯具
对于场景一,使用 word-wrap: break-word;
对于场景二,使用 IE67 的 hack,word-break: keep-all; 或者用 inline-block 来代替浮动(IE67 中,hasLayout 的 inline 盒子大体等同于 inline-block)
回头看疑问二,我们为什么会乐此不疲地重复碰到这个问题?原则上,各个浏览器默认的文字排版方式已经很好地顾及了 CJK 文字和 !CJK 文字,根据各个语言自己的规则来呈现排版,不应该出现诡异的问题。所以,对于上面的两个问题场景,之所以产生场景一,是因为使用了极端的测试用例,但是在现实中,这种极长的英文单词是根本不存在的(特殊行业除外),又,即使英文单词较长,也不应该突兀地截断,这有违西欧文字的排版规则。所以我认为,如果在现实环境下发生场景一中的问题,责任应该在于版面的设计,比如容器宽度太小,而不是去截断文本;对于场景二,应该归咎于 IE67 的渲染 bug,这时,使用 inline-block 代替,或用 word-break: keep-all; 来给犯错的浏览器擦屁股。
实践方案
- 对于我们输出的内容(可控的),不使用任何 word-wrap 和 word-break 等属性,对于可能产生的长单词溢出这种小概率事件,首先考虑容器宽度是否合理,其次可以为长单词添加连字符“-”以便合理地断开,最后设置 overflow: hidden; 避免视觉上的溢出。
- 对于用户输出的内容(不可控的),比如评论等,由于不排除用户会输入“dddddddddddd”这样没营养的垃圾数据,使用 word-wrap: break-word; 来强行截断。
最后的观点
- 不能完全迁就测试用例,因为有时不合现实情理。
- 浏览器默认已经做得够好,强加诸如 break-all; 这样的指令是不优雅的。
- 问题大多不在于实现,而在于设计(如容器太窄)。
- 对于 bug 浏览器使用 hack 即可,这是它们的错。
相关资源
- CSS3 草案:http://www.w3.org/TR/2010/WD-css3-text-20101005/
- demo 页面:http://ued.taobao.org/lab/word-wrap/word-wrap.html
- 转:http://ued.taobao.org/blog/?p=2630
word wrap 解惑的更多相关文章
- word break和word wrap
默认情况下,如果同一行中某个单词太长了,它就会被默认移动到下一行去: word break(normal | break-all | keep-all):表示断词的方式 word wrap(norma ...
- Sublime Text 2 自动开启换行 Word Wrap
首先当然要夸一下神器 Sublime Text 2,自从第一次用我就彻底把神马 Notepad++ 和 TextMate 打入冷宫,用来开发 WEB 项目从此 IDE 都不需要了! 下面讲讲如何自动开 ...
- 【Cocos2d-x for WP8 学习整理】(5)文字显示全整理
学习 Cocos2d-x 有一阵了,现在要做个小东西,第一步就遇到了文字展示的问题,于是想把可能遇到的问题统统整理一下.这一部分也不局限于wp8,全平台应该都是一个解决方案. 先在脑袋里大致想了一下, ...
- 【夯实PHP基础】PHP发送邮件(PHPMailer)
本文地址 参考地址 分享提纲: 1. 概述 2. 编写代码发送邮件 3. 参考文档 1. 概述 本文是讲利用邮件类库 PHPMailer来发送邮件方法. 我们在做project的时候常常需要邮件的功能 ...
- Total Commander 8.52 Beta 1
Total Commander 8.52 Beta 1http://www.ghisler.com/852_b1.php 10.08.15 Release Total Commander 8.52 b ...
- Lab_7_Automating_v2.5
System Operations - Lab 7: Automating Deployments with CloudFormation - 2.5 ======================== ...
- Lab_6_SysOps_AutoScaling_Linux_v2.5
System Operations - Lab 6: Using Amazon Elastic Load Balancer (Linux) - 2.5 ======================== ...
- Lab_4_SysOps_Monitoring_Linux_v2.5
System Operations - Lab 4: Monitoring with CloudWatch (Linux) - 2.5 ================================ ...
- Lab_3_SysOps_Storage_Linux_v2.5
System Operations - Lab 3: Managing Storage in AWS (Linux) - 2.5 =================================== ...
随机推荐
- ASP.NET静态页生成
由于业务需要,得把页面按照模板页生成静态页面,所以自己就琢磨了下,写些思路,以备日后需要的时候用. 静态页生成用到最多的就是匹配跟替换了,首先得读取模板页的html内容,然后进行你自己定义的标签匹配, ...
- 软件测试——boost单元测试 C++
分类: 1. 下载安装Boost 2. 在vs2010 中设置 工具->选项->vc++目录 设置包含文件目录:找到解压的boost文件夹eg:C:\boost_1_43_03. ...
- Delphi RxRichEdit高级操作
unit InsertRichEditUnit;interfaceuses Windows, Messages, SysUtils, Classes, Graphics, Controls, For ...
- 在Jenkins中使用Git Plugin访问Https代码库失败的问题
最近需要在Jenkins上配置一个Job,SCM源是http://git.opendaylight.org/gerrit/p/integration.git 于是使用Jenkins的Git Plugi ...
- ansible网络模块安装httplib2
ansible网络模块安装httplib2 在进行使用ansible的网络模块的时候,需要安装httplib2模块 下载地址: https://pypi.python.org/pypi?%3Aacti ...
- C++的类成员和类成员函数指针
类成员函数指针: 用于访问类成员函数,和一般函数指针有区别. 类成员函数处理的是类数据成员,声明类成员函数指针的同时,还要指出具体是哪个类的函数指针才可以.调用时也要通过对象调用. 而对于类的静态成员 ...
- python 数字和字符串转换问题
一.python中字符串转换成数字 (1)import string tt='555' ts=string.atoi(tt) ts即为tt转换成的数字 转换为浮点数 string.atof(tt) ( ...
- bzoj 3781 小B的询问(莫队算法)
[题意] 若干个询问sigma{ cnt[i]^2 } cnt[i]表示i在[l,r]内的出现次数. [思路] 莫队算法,裸题. 一个cnt数组即可维护插入与删除. [代码] #include< ...
- UIActivityViewController 自定义选项
UIActivityViewController 自定义选项 重写 UIActivity 类 建议下载github上源码学习一下 https://github.com/samvermette/SVWe ...
- URAL-1998 The old Padawan 二分
题目链接:http://acm.timus.ru/problem.aspx?space=1&num=1998 题意:有n个石头,每个石头有个重量,每个时间点你能让一个石头飞起来,但有m个时间点 ...