程序与技术分享:bidi(双向文字)与RTL布局总结

简介: 程序与技术分享:bidi(双向文字)与RTL布局总结

  BIDI


  双向文字就是一个字符串中包含了两种文字,既包含从左到右的文字又包含从右到左的文字。


  大多数文字都是从左到右的书写习惯,比如拉丁文字(英文字母)和汉字,少数文字是从右到左的书写方式比如阿拉伯文(ar)跟希伯来文(he)。对于需要国际化支持的web应用来说,由于阅读习惯的不同在web页面排版和布局中会给开发人员带来麻烦。这种情况多数出现在从右到左的文字中,比如字符串中出现阿拉伯文、英文字母、数字以及标点符号。本文就是我在工作中遇到该类问题的总结。


  在现代计算机应用中,最常用来处理双向文字的算法是 Unicode 双向算法(Unicode Bidirectional Algorithm),在后面的文章中我们将 Unicode 双向算法简称为 bidi 算法。


  我们的web产品中使用的字符都属于unicode字符,而unicode字符的方向属性总共包含三类:强字符、中性字符、弱字符。


  强字符的方向属性是确定的,与上下文的bidi属性无关,而且强字符在bidi算法中可能会对其前后的中性字符产生影响。大部分的字符都属于强字符,比如拉丁字符、汉字、阿拉伯字符。


  中性字符的方向性并不确定,受其上下文的bidi属性影响(前后的强字符)。比如大部分的标点符号(“-”,“【】”,"()"等)跟空格。


  弱字符的方向性是确定的,但不会对其上下文的bidi属性产生影响。比如数字以及跟数字相关的符号。


  一个区域内有总体方向,决定从这个区域的哪边开始书写文字,通常称为基础方向。浏览器会根据你的默认语言来设置默认的基础方向,如英语、汉语的基础方向为从左到右,阿拉伯语的基础方向为从右到左。


  方向串是指在一段文字中具有相同方向性的连续字符,并且其前后没有相同方向性的其它方向串。


  下方假设大写字母为从右到左的文字。


[/span>p dir="ltr"bdo dir="rtl"

  在这个例子中,包含了三个方向串。该句子以从左到右的方向串开始,然后是从右到左的方向串,最后以从左到右的方向串结尾。


  要注意的是,方向串的排列顺序和数目往往会受到全局方向的影响。上面的例子中采用是从左到右的全局方向,如果该全局方向变为从右到左,那这个例句中方向串的排列顺序将如下图所示:


[/span>p dir="rtl"bdo dir="rtl"

  Web中控制文字方向的方式有三种:html实体(‎ ‏)、bid与bdo标签+dir属性、css属性(direction + unicode-bidi)


  ‎与‏可以用来打断方向串的连续性,影响中性字符的方向


  下面这段文本中共有四个中性字符:"."、 "+"、 "("、")";受从左到右基础方向影响这几个字符的方向性都表现为从左到右,界面也是正常的。


[/span>p dir="ltr"

  如果将基础方向设置为从右到左


[/span>p dir="rtl"

  最右边的")"受基础方向影响会出现我们不想要的结果,而其他三个中性字符受上下文方向性影响依旧保持从左到右的方向性。


  我们可以使用‎实体来改变")"的方向性。


[/span>p dir="rtl"

  在上文介绍方向串时已经看到大写字母变成从右到左的方向这就是bdo元素+dir的作用,覆盖元素内文本的方向性。


  bdi元素的目的是设置一个隔离区域。如果不设置dir则使用上下文的基础方向。


[/span>ul

[/span>li

[/span>libdibdo dir="rtl"


  大家可以试试把bdi元素去掉是什么效果,试着分析一下里面的方向串。


  如果设置dir属性那么就为这个隔离区域设置了一个基础方向。


[/span>p dir="rtl"bdi dir="ltr"bdo dir="rtl"bdo dir="rtl"

  注意里面的空格跟标点符号的方向性。


  direction跟unicode-bidi这两个是css属性,通常放在一起来控制文本的方向,大家可以自己查看一下css手册。


  direction+unicode-bidi:embed 的效果类似于bdi元素; direction+ unicode-bidi: bidi-override 的效果类似于bdo元素。


  实际项目中我遇到阿拉伯语下在表格中显示负数问题,看起来的效果是:“88-”;使用以上属性direction:ltr,unicode-bidi:embed,可以改变显示效果:“-88”。


  RTL布局


  工作中遇到的另一个跟语言相关的问题就是页面布局问题。阿拉伯文(ar)跟希伯来文(he)的页面布局同英语下的页面布局刚好是镜像关系。这一点大家可以试试把浏览器的语言设置为阿拉伯语,观察一下浏览器上的控件布局(要保证你能再设置回来)。


  首先判断用户设置的语言,如果是ar跟he则将全局基础方向设置为rtl,这时基本可以解决大多数问题。


function localeIsSame(locale1, locale2){


return locale1.indexOf(locale2) > -1 || locale2.indexOf(locale1) > -1;


}


function _setRTL(locale){


var rtlLocales = 【"ar", "he"】;


var dirNode = document.getElementsByTagName("html")【0】;


var isRTLLocale = false;


for (var i = 0; i [/span> rtlLocales.length; i++) {


if (localeIsSame(rtlLocales【i】, locale)) {


isRTLLocale = true;


}


}


if (isRTLLocale) {


dirNode.setAttribute("dir", "rtl");


dirNode.className += " esriRtl jimu-rtl";


dirNode.className += " " + locale + " " +


(locale.indexOf("-") !== -1 ? locale.split("-")【0】 : "");


}else {


dirNode.setAttribute("dir", "ltr");


dirNode.className += " esriLtr jimu-ltr";


dirNode.className += " " + locale + " " +


(locale.indexOf("-") !== -1 ? locale.split("-")【0】 : "");


}


window.isRTL = isRTLLocale;


}


View Code


  然后将float和text-align以及控制间距的margin、padding从所有的css class中抽离出来单独成类,如:


  在RTL时将他们左右互换


  在代码中与rtl布局相关的部分通过判断全局变量window.isRTL来处理。


html【dir='rtl'】 caption,


html【dir='rtl'】 th {


text-align: right;


}


.jimu-rtl {


direction: rtl;


}


.jimu-align-trailing {


text-align: right;


}


.jimu-align-leading {


text-align: left;


}


.jimu-float-trailing {


float: right;


}


.jimu-float-leading {


float: left;


}


.jimu-numeric-value {


direction: ltr;


unicode-bidi: embed;


}


/ if a ltr element is inside a rtl page /


.jimu-ltr .jimu-float-leading {


float: left !important;


}


/ RTL alignment /


.jimu-rtl .jimu-align-trailing {


text-align: left;


}


.jimu-rtl .jimu-align-leading {


text-align: right;


}


.jimu-rtl .jimu-float-trailing {


float: left;


}


.jimu-rtl .jimu-float-leading {


float: right;


}


/* margins **/


.jimu-leading-margin0 {


margin-left: 0;


}


.jimu-leading-margin025 {


margin-left: 0.25em;


}


.jimu-leading-margin05 {


margin-left: 0.5em;


}


.jimu-leading-margin1 {


margin-left: 1em;


}


.jimu-leading-margin15 {


margin-left: 1.5em;


}


.jimu-leading-margin2 {


margin-left: 2em;


}


.jimu-leading-margin25 {


margin-left: 2.5em;


}


.jimu-leading-margin3 {


margin-left: 3em;


}


.jimu-leading-margin35 {


margin-left: 3.5em;


}


.jimu-leading-margin4 {


margin-left: 4em;


}


.jimu-leading-margin5 {


margin-left: 5em;


}


.jimu-leading-margin6 {


margin-left: 6em;


}


.jimu-leading-margin7 {


margin-left: 7em;


}


.jimu-leading-margin10 {


margin-left: 10em;


}


.jimu-trailing-margin025 {


margin-right: 0.25em;


}


.jimu-trailing-margin05 {


margin-right: 0.5em;


}


.jimu-trailing-margin075 {


margin-right: 0.75em;


}


.jimu-trailing-margin1 {


margin-right: 1em;


}


.jimu-trailing-margin15 {


margin-right: 1.5em;


}


.jimu-trailing-margin2 {


margin-right: 2em;


}


.jimu-trailing-margin25 {


margin-right: 2.5em;


}


.jimu-trailing-margin3 {


margin-right: 3em;


}


.jimu-trailing-margin35 {


margin-right: 3.5em;


}


.jimu-trailing-margin4 {


margin-right: 4em;


}


.jimu-trailing-margin5 {


margin-right: 5em;


}


.jimu-trailing-margin6 {


margin-right: 6em;


}


.jimu-leading-padding05 {


padding-left: 0.5em;


}


.jimu-leading-padding1 {


padding-left: 1em;


}


.jimu-trailing-padding1 {


padding-right: 1em;


}


/ RTL related: margins, padding /


.jimu-rtl .jimu-leading-margin0 {


margin-right: 0;


margin-left: auto;


}


.jimu-rtl .jimu-leading-margin025 {


margin-right: 0.25em;


margin-left: auto;


}


.jimu-rtl .jimu-leading-margin05 {


margin-right: 0.5em;


margin-left: auto;


}


.jimu-rtl .jimu-leading-margin075 {


margin-right: 0.75em;


margin-left: auto;


}


.jimu-rtl .jimu-leading-margin1 {


margin-right: 1em;


margin-left: auto;


}


.jimu-rtl .jimu-leading-margin15 {


margin-right: 1.5em;


margin-left: auto;


}


.jimu-rtl .jimu-leading-margin2 {


margin-right: 2em;


margin-left: auto;


}


.jimu-rtl .jimu-leading-margin25 //代码效果参考:http://www.lyjsj.net.cn/wx/art_24247.html

{

margin-right: 2.5em;


margin-left: auto;


}


.jimu-rtl .jimu-leading-margin3 {


margin-right: 3em;


margin-left: auto;


}


.jimu-rtl .jimu-leading-margin35 {


margin-right: 3.5em;


margin-left: auto;


}


.jimu-rtl .jimu-leading-margin4 {


margin-right: 4em;


margin-left: auto;


}


.jimu-rtl .jimu-leading-margin5 {


margin-right: 5em;


margin-left: auto;


}


.jimu-rtl .jimu-leading-margin6 {


margin-right: 6em;


margin-left: auto;


}


.jimu-rtl .jimu-leading-margin7 {


margin-right: 7em;


margin-left: auto;


}


.jimu-rtl .jimu-leading-margin10 {


margin-right: 10em;


margin-left: auto;


}


.jimu-rtl .jimu-trailing-margin025 {


margin-left: 0.25em;


margin-right: auto;


}


.jimu-rtl .jimu-trailing-margin05 //代码效果参考:http://www.lyjsj.net.cn/wx/art_24245.html

{

margin-left: 0.5em;


margin-right: auto;


}


.jimu-rtl .jimu-trailing-margin075 {


margin-left: 0.75em;


margin-right: auto;


}


.jimu-rtl .jimu-trailing-margin1 {


margin-left: 1em;


margin-right: auto;


}


.jimu-rtl .jimu-trailing-margin15 {


margin-left: 1.5em;


margin-right: auto;


}


.jimu-rtl .jimu-trailing-margin2 {


margin-left: 2em;


margin-right: auto;


}


.jimu-rtl .jimu-trailing-margin25 {


margin-left: 2.5em;


margin-right: auto;


}


.jimu-rtl .jimu-trailing-margin3 {


margin-left: 3em;


margin-right: auto;


}


.jimu-rtl .jimu-trailing-margin4 {


margin-left: 4em;


margin-right: auto;


}

//代码效果参考: http://www.lyjsj.net.cn/wx/art_24243.html


.jimu-rtl .jimu-trailing-margin5 {


margin-left: 5em;


margin-right: auto;


}


.jimu-rtl .jimu-trailing-margin6 {


margin-left: 6em;


margin-right: auto;


}


.jimu-rtl .jimu-leading-padding05 {


padding-right: 0.5em;


padding-left: auto;


}


.jimu-rtl .jimu-leading-padding1 {


padding-right: 1em;


padding-left: auto;


}


.jimu-rtl .jimu-trailing-padding1 {


padding-left: 1em;


padding-right: auto;


}


View Code


  参考文章:


  bidi算法及HTML中的实现


  direction:rtl在布局中的使用


实践:使用 HTML 标记显示全局化中从右到左的文字

相关文章
|
移动开发 算法 前端开发
|
存储 自然语言处理 算法
|
缓存 Linux Windows
flyingsaucer进行html文件转图片和pdf
目录 一、前言 二、html转图片 1、添加依赖 2、代码示例 (1)测试html文件 (2)代码示例 3、演示结果 三、html转pdf 1、添加依赖 2、代码示例 3、演示结果 四、注意点 1、html转图片的源url 2、部署到linux上后中文乱码 五、Linux上安装字体 1、拷贝字体 2、赋予权限 3、建立字体缓存 4、查看安装的字体
flyingsaucer进行html文件转图片和pdf
|
11月前
|
机器学习/深度学习 自然语言处理 搜索推荐
预训练的词嵌入(Word Embedding)
预训练的词嵌入(Word Embedding)
439 2
|
索引
Layui 内置方法 - layer.prompt_(输入层)
Layui 内置方法 - layer.prompt_(输入层)
1158 0
|
11月前
|
存储 大数据 数据管理
大数据垂直分区(Vertical Partitioning)
【11月更文挑战第1天】
207 1
|
JavaScript 前端开发
node.js 导入导出模块(CommonJS模块化规范,ES6模块化规范)
node.js 导入导出模块(CommonJS模块化规范,ES6模块化规范)
219 1
|
开发框架 前端开发 JavaScript
基于SqlSugar的开发框架循序渐进介绍(31)-- 在查询接口中实现多表联合和单表对象的统一处理
基于SqlSugar的开发框架循序渐进介绍(31)-- 在查询接口中实现多表联合和单表对象的统一处理
|
前端开发 UED
设计新潮流:CSS动画毛玻璃按钮,展开效果引人入胜!
设计新潮流:CSS动画毛玻璃按钮,展开效果引人入胜!
dynamic-datasource动态添加移除数据源
dynamic-datasource动态添加移除数据源
776 0