
艾哈迈德·沙迪德(Ahmad Shadid)撰写的“
RTL样式101-有关如何在CSS中为RTL样式的详细指南 ”的翻译。
全球有超过2.92亿人说阿拉伯语为母语。 我属于他们,因此有时我会开发一些网站,该网站应支持书写的两个方向:从左到右(LTR-从左到右)和从右到左(从右到左)。
RTL样式介绍
CSS默认使用LTR方向。 如果检查html元素的浏览器样式,则会看到dir(或“ direction”)属性的ltr值为默认值。 下面是一个基本示例,以演示LTR和RTL标记之间的区别。

注意RTL块-与LTR不同,它的文本是从右到左读取的。 在这个简单的示例中,浏览器正确显示了它。 要更改文档语言的方向,您需要将dir属性添加到root元素。
<html dir="rtl">...</html>
当dir值更改时,所有嵌套元素都应自动切换下一个:标题,段落,链接,图像和表格。
还值得一提的是,dir属性可以设置为“ auto”,这将基于对元素内容的分析来自动更改元素的方向。 根据HTML规范:
作者强烈建议仅当文本的方向真正未知并且无法在服务器端有效确定此值时,才将此值用作最后的选择。
除了为HTML元素设置dir = rtl属性外,我们还可以添加direction:rtl作为CSS样式。
.element { direction: rtl; }
但是,CSSWG(CSS工作组)建议完全将方向定义为HTML根元素的属性,以确保标记正确无论是否存在CSS。
更改标记方向的示例
让我们看一个更详细的示例,以更好地理解如何将标记方向从LTR更改为RTL。

<article class="media"> <img class="media__photo" src="blueberry-cheesecake.jpg" alt=""> <div class="media__content"> <h2>Blueberry Cheesecake</h2> <p>...</p> <p><a href="#" class="link">View Recipe</a></p> </div> </article>
最初,我使用良好的旧浮点数对LTR标记中的图像进行左对齐,并且当然应用了clearfix。
.media:after { content: ""; display: block; clear: both; } .media img { float: left; width: 200px; margin-right: 16px; }
然后,为包含阿拉伯文本的元素添加dir =“ rtl”。 得到以下结果:

除图像外,所有元素都在右侧对齐。 发生这种情况是因为image属性设置为float:left和margin-right:16px。 要解决此问题,请覆盖以下样式
.media[dir="rtl"] img { float: right; margin-right: 0; margin-left: 16px; }
LTR布局中的英语和阿拉伯语内容
如果某些文本混合使用英语和阿拉伯语单词,并且标记朝着LTR方向显示,该怎么办? 结果很奇怪

浏览器将无法正确显示标题。 讲阿拉伯语的人会感到困惑。 该标题中的单词应按下图所示的顺序。 只是从右边开始。

为避免此问题,请尽可能设置适当的语言方向。 如果该元素设置为dir =“ rtl”属性,则将按预期显示。

如果标题太长,情况可能会变得更加复杂。 下面我补充了一点,结果出乎意料。 我用数字表示正确的顺序。 再次,从右边开始。

为元素设置dir =“ rtl”属性时,标题变为正确。 即,该句子在语法上看起来正确,并且单词以正确的顺序排列。

弹性盒
Flexbox基本上会考虑文档中设置的书写模式。 此因子用于确定默认情况下块将如何在页面上对齐。 例如,在英语站点上,它们从左到右,从中文到顶部。 对于英语和阿拉伯语,默认的write-mode属性是horizontal-tb。
根据
Mozilla开发人员网络 (MDN),horizontal-tb值表示以下含义:
内容从左到右水平放置,从上到下垂直放置。 下一条水平线在上一条水平线下方。
当页面方向更改为RTL时,flexbox会适当扩展其元素流。 这是一个巨大的优势! 下图显示了flexbox轴如何旋转,具体取决于direction属性的值。

在下面的示例中,我创建了三个元素并编号,以显示更改页面方向时的差异。
<div class="element"> <div class="item"^_^gt lt^_^/div> <div class="item"^_^gt lt^_^/div> <div class="item"^_^gt lt^_^/div> </div>
.element { display: flex; flex-direction: row; }

CSS网格
与flexbox一样,css网格取决于文档的编写模式,这为我们提供了与使用flexbox时相同的优势。
在下面的示例中,对于LTR方向,侧边栏应位于左侧,主栏应位于右侧。 对于RTL,情况恰恰相反。 当我们使用CSS Grid时,将按照此页面上设置的方向自动执行此重建。
<div class="element"> <div class="side">Side</div> <div class="main">Main</div> </div>
.element { display: grid; grid-template-columns: 220px 1fr; grid-gap: 1rem; }
切换到RTL方向时的主要错误
非阿拉伯开发人员会犯常见错误,母语人士会立即意识到这些错误。
1.字母间距
在英语中,通常使用letter-spacing属性来控制单词中的字母间距。 考虑以下示例,该示例的内容为英语。 看起来很正常。

但是,如果在阿拉伯文本中添加相同的字母间距,则看起来会很奇怪。 考虑下面的真实示例。

请注意,在应用了字母间距属性的文本中,每个单词的字母彼此分开。 错了 阿拉伯字母看起来应该连通,并且保持与英语相同的字母间距可以防止这种情况。 确保在使用多语言站点时,不要忘记在正确的位置设置字母间距属性:0。
2.文字透明
在网站设计中,文本通常是半透明的。 例如,标记其次要重要性。 这适用于英语。 但是,如果内容为阿拉伯语,则由于呈现文本的方式奇怪,可能会出现问题。

出现字符轮廓因重叠而改变的位置。 在本示例中,未设置letter-spacing属性,因此它不会影响该问题。 解决方案是设置没有半透明的颜色(通常通过RGBa或不透明度设置)。
3.不同语言的字长差异
有时,将网站翻译成阿拉伯语时,元素的大小会因翻译后某些单词变大或变小的事实而发生变化。 考虑以下示例,在该示例中,我模拟了Smashing Magazine网站的导航。

在阿拉伯语版本中,有些单词的大小与英语版本几乎相同,有些完全相同,有些则更大。 为了更加清楚,这里是每个单词及其阿拉伯语翻译的比较。

您可能想知道为什么我在谈论不同语言中单词大小的差异,因为这是正常现象,这是预期的。 考虑下面的实际LinkedIn示例。

“完成”按钮被翻译成阿拉伯语“تم”,这就是为什么它变得很小并且通常看起来很奇怪的原因。 特别是在这种情况下,最好为按钮设置min-width属性。 我是通过开发人员面板添加的,以显示其外观:

这是来自Twitter的非常相似的示例:

请注意,LinkedIn和Twitter的上述问题是在撰写本文时(2019年12月13日)发现的。
4.文本截断
我曾经从事过一个多语言项目,但遇到了与错误方向截断文字有关的问题。 考虑以下示例。

英文文本的截断不正确。 这应该发生在元素的末尾,而不是开始。 要解决此问题,您需要为此元素设置dir =“ auto”属性,然后浏览器将自动分析内容并确定要应用的dir值。
<p dir="auto">أهلاً وسهلاً بكم في المقال الذي يتحدث عن تصميم صفحات الويب للغة العربية</p> <p dir="auto">Welcome to the article that explains how to design for RTL pages.</p>

5.选择错误的RTL字体
该站点存在RTL版本并不意味着您可以简单地将自己限制为指定默认情况下用户安装的系统字体。 您需要认真对待这一点,以确保良好的可读性。 选择失败字体的一个示例是Twitter:

从讲阿拉伯语的角度来看,“تغريد”一词很难读,原因有以下几点:
- 字体不是很好
- 肥胖会损害可读性
- 单词的点非常小,太靠近字母
我举了一些更清晰的例子:

6.混合印地语和阿拉伯数字
在阿拉伯语中,有两种写数字的方法:
- 印地语:٣ ٨ ٨ ٨
- 阿拉伯语:0 1 2 3 4 5 6 7 8 9
英文使用的数字是从阿拉伯语继承而来的:“ 0、1、2、3、4、5、6、7、8、9”。 包含数字的文本必须仅匹配以下两个选项之一:印地语或阿拉伯语。
根据维基百科:
在欧洲和美洲将这些数字称为“阿拉伯语”的原因是因为它们是10世纪由来自北非的讲阿拉伯语的人引入欧洲的。
下面的示例包含北印度文数字和阿拉伯数字。 这种方法似乎不一致,应改用单一样式。

可能不适用于RTL的时刻
1.线高(line-height)
通常,为RTL标记设置单独的字体。 在这种情况下,请检查内容在一行或多行中的外观。 在以下示例中,即使阿拉伯文文本的行高属性值相同,它们之间的行距也比英语小。

重要的是要考虑这一点,并为阿拉伯文本的行高设置正确的值。
例如,Twitter的按钮具有裁剪的内容。 只是因为错误的行高值。

请注意,在第一个图像中,裁剪了阿拉伯变音符号。 它被称为kasra,对于正确读取单词非常重要。 在下一张图像中,我更正了行高,现在字符已完整显示,没有裁剪。
2.带下划线的链接
使用阿拉伯文字,CSS链接的标准下划线看起来很糟糕。 这是由于用阿拉伯语写单词和字母的特殊性,如下图所示:

我用红色圆圈标记了问题区域。 下划线与字母的点重叠。 这是一个特写:

带红色圆圈的点与下划线重叠,使阅读变得困难。 解决方案是使用CSS自定义下划线。
2.1。 版式(文本装饰)
使用新的text-decoration-style和text-decoration-color属性可以更改下划线的样式和颜色。 但是,不能保证这将适用于所有字体系列和大小。 在撰写本文时,Firefox是对这些功能的最佳支持的浏览器。
.link-2 { text-decoration-color: rgba(21, 132, 196, 0.2); text-decoration-style: normal; text-underline-offset: 4px; text-decoration-thickness: 2px; }

2.2阴影(阴影盒)
浏览器对box-shadow属性的支持比文本装饰好得多。 您可以检查是否支持新的文本装饰属性之一,如果浏览器不支持,请使用box-shadow属性应用后备。
.link-3 { color: #000; text-decoration-color: rgba(21, 132, 196, 0.2); text-decoration-style: normal; text-underline-offset: 4px; text-decoration-thickness: 2px; box-shadow: inset 0 -5px 0 0 rgba(#1584c4, 0.2); } @supports (text-decoration-color: red){ .link-3 { box-shadow: none; } }

3.换行
如果使用word-break属性,则需要检查其操作的正确性。 看下面的例子:

带圆圈的区域是阿拉伯语单词,由于使用了分行符而被换行符打破。 并且在阿拉伯语中,不使用自动换行,因为每个单词的字母必须彼此连接。
4.缩写
在英语中,经常使用缩写,例如一周中的几天。 因此,“星期六”变为“星期六”。

原则上不可能使用阿拉伯语,因为必须连接单词的字母。

双向图标
在LTR和RTL布局之间切换时,不需要翻转对称图标。 以下是一些示例:

同时,对于某些图标,重要的是更改网站的RTL版本中的方向,以便用户正确理解它们。

翻转物品
在处理某些组件时,我需要一种快速翻转它们的方法。 在Sketch中,我复制组件并使用适当的命令将其翻转。 Adobe XD和Figma中提供了相同的功能。

为了理解我的意思,下面是一个动画,演示了翻转组件后的操作。

RTL的设计功能
在本节中,我将研究最常见的组件,并展示它们在RTL模式下的外观。
按钮图示
在某些情况下,该按钮具有打开其他操作菜单的图标。 在这种情况下,图标的位置应在RTL布局中颠倒。

输入栏
即使在RTL模式下,某些表单输入字段也必须保持左对齐。 例如,输入字段电子邮件或电话号码。

面包屑
面包屑各部分之间的箭头也应旋转。

页面标题
页面标题组件包含开始部分和结束部分。 两者都必须在RTL中旋转

桌子
桌子也必须旋转。

书签
如果在LTR模式下图标在书签中名称的左侧,则需要在RTL中扩展此组件。

卡
对于水平卡,需要在RTL中交换图像和文本

弹出通知
如您所料,应该关闭“关闭”和“警告”图标

CSS布尔属性
根据MDN:
逻辑属性和值CSS是表示逻辑属性和值的模块,这些模块提供了使用逻辑而非物理方向和尺寸来控制布局的功能。
让我们举一个简单的例子。 假设我们需要在右侧对齐一行文本。 添加以下内容:
.page-header { text-align: right; }
对于RTL:
[dir="rtl"] .nav-item { text-align: left; }
如果有一种方法可以为text-align属性仅添加一个值,该值在给定页面方向的情况下会更改对齐方式呢? CSS的逻辑属性可助您一臂之力!
.page-header { text-align: end; }
使用它时,由text-align属性指定的一面将基于页面的方向。
演示版为了更容易看到开始和结束之间的区别,我准备了下图。 起始值等于LRT中的左值和RTL中的右值。 与结尾相同,相反。

现在,您已经大致了解了它的工作原理,让我们看一下其他示例和应用CSS逻辑属性的方法。
逻辑填充

假设我们在输入字段的右侧有一个搜索图标。 我们必须在两侧都设置填充。 右侧的填充将稍大一些,以避免将图标覆盖在文本上。
.input--search { padding-inline-start: 1rem; padding-inline-end: 2.5rem; }
逻辑余量

图标右侧的边距应该是合乎逻辑的,因此我们为此使用margin-inline-end。
.page-header__avatar { margin-inline-end: 1rem; }
逻辑框架(边界)

通常,框架用于指示活动的导航元素。 在上面的示例中,在每个元素的左侧设置了一个框架。 如何使用逻辑属性来实现呢?
.nav__item { border-inline-start: 3px solid transparent; } .nav__item.is-active { border-color: #1e9ada; }
角的逻辑圆角(边界半径)

在上图中,导航元素的背景仅针对右上角和左上角进行了舍入。 可以使用逻辑属性来实现:
.nav__item { border-start-end-radius: 30px; border-end-end-radius: 30px; background-color: transparent; } .nav__item.is-active { background-color: #ecf6fb; }
备忘单逻辑属性
如果对定义该边的属性的逻辑类似物的选择有疑问,则可以查看下面的备忘单。 请注意,它仅包含在使用LTR和RTL模式时可能有用的那些逻辑属性。 我根据Adrian Roselli的精彩
文章编写了这份备忘单。
https://codepen.io/shadeed/pen/2981e62691e67452d9f282a5351d7c79此外,阿德里安(Adrian)创建了一个演示,使您更容易理解逻辑和方向属性之间的差异。
浏览器支持
浏览器支持非常适合填充,边距和文本对齐属性。 但是,对于边界半径属性仍然不够。 下表是“
我可以使用”网站的支持表:


即使支持尚不完善(而且永远不会如此),我还是建议您立即开始使用具有后备功能的逻辑属性。 举个例子
.input--search { padding-left: 1rem; padding-right: 2.5rem; padding-inline-start: 1rem; padding-inline-end: 2.5rem; }
另外,您可以使用
PostCSS Logical插件,该插件为每个使用的逻辑属性添加一个后备。
CSS命名约定
避免给CSS类添加附加在其元素上的名称。 使用可以提取到可重用组件中的名称。 考虑以下示例:
<div class="c-section"> <p><a href="#" class="see-link">See more</a></p> </div> <div class="c-section"> <p><a href="#" class="see-link">Learn more</a></p> </div>
两个块中的链接相同,但是名称不同。 在第二个块中,see-link类没有意义。 一个好名字可能是c-link。 前缀c–代替了组件;我从ITCSS框架采用了此方法。
现在您已经了解了这个想法,我们也可以将其应用于RTL样式。 下例显示了一个有两个孩子的区域

我没有给元素起类似.c-page-header__left和.c-page-header__right的名称,而是将它们命名为.c-page-header__start和.c-page-header__end。 这是面向未来的,并不意味着该站点仅以LTR或RTL模式创建。
自动化工具
有很多很棒的工具可以简化LTR和RTL标记的使用。
1. Bi-App-Sass
Anas Nakava的
Bi-App-Sass允许您编写一种样式的版本,该样式可以编译为两种不同的样式表:一种用于LRT,一种用于RTL标记。
该工具对于大型项目很有用。
因此,每个书写方向可以有许多样式表。考虑以下示例: .elem { display: flex; @include margin-left(10px); @include border-right(2px solid #000); }
生成的CSS代码可能如下。App-ltr.css文件: .elem { display: flex; margin-left: 10px; border-right: 2px solid #000; }
App-rtl.css文件: .elem { display: flex; margin-right: 10px; border-left: 2px solid #000; }
但是请注意,对GitHub上存储库的最后一次提交是四年前(2015年11月)。2. RTLCSS
RTLCSS穆罕默德乔纳斯为在RTL转换LTR样式表的框架。此工具之间的区别在于,它适用于CSS文件的已组装版本。例如,如果您的项目中有50多个Sass组件,则RTLCSS可用于解析已编译的CSS文件并从中创建RTL版本。实际例子
网站标题
我专门进行了布局,以显示我正在使用哪种方法来实现标记的RTL版本。
让我们从头文件的组件开始。为了在代码中正确实现此目的,我示意性地描述了其一般结构。请注意,我将标题分为主要部分和子部分。另外,为子元素添加了开始和结束类。
.header__main, .header__sub { display: flex; justify-content: space-between; }
如本指南前面所述,由于CSS Flexbox的操作考虑了页面上指定的方向,因此它将在RTL标记上自动扩展。
下一点是徽标和导航之间的分界线。起初我想到使用右边框。它有效,但并不完美。最好使用伪元素,因为它将在页面方向后展开。
.c-brand:after { content: ""; display: inline-block; vertical-align: middle; width: 3px; height: 38px; border-radius: 5px; background: #e4e4e4; margin-inline-start: 1.25rem; }
这是当前的结果:
接下来,我将使用section组件(位于标题小节中的一个组件,其中包含名称和计数器)。以下是此组件在LTR中的外观布局。
乍看之下,这似乎很简单,但实际上需要指定几个填充和边距属性。这是一个演示此布局:
.topics-heading { margin-inline-end: 1.5rem; } .topics-list { margin-inline-end: 1rem; } .c-topic { padding-inline-start: 0.5rem; } .c-topic:not(:last-child) { margin-inline-end: 10px; } .c-topic__counter { margin-inline-start: 1rem; }
如您所见,我使用CSS布尔属性而不是left和right值。下一步是“查看全部”链接。注意最后的箭头。她应该具有以下行为:- 悬停时,箭头的颜色应更改
- 悬停时,应将动画应用于箭头
我决定将内置的SVG用于此任务,当我设置箭头进行翻译时,我想到了RTL。没有适合这种情况的逻辑属性,我需要考虑另一种解决方案。保证金改变的选择出现了。 .c-link svg { margin-inline-start: 4px; transition: 0.15s ease-in; } .c-link:hover svg { margin-inline-start: 8px; }
尽管设置边距动画效果不会很好地影响效果,但效果仍然不错。另一种解决方案是确定页面方向并在此基础上指示偏移的相应方向 .c-link:hover svg { transform: translateX(6px); } .c-header[dir="rtl"] .c-link svg { transform: scaleX(-1); } .c-header[dir="rtl"] .c-link:hover svg { transform: scaleX(-1) translateX(6px); }
请注意,对于RTL页面方向,我添加了scaleX(-1)来水平扩展图标。您也可以使用旋转(180deg),但是缩放选项对我来说似乎更简单。
接下来是搜索字段。要求如下:- 搜索图标应出现在该字段的末尾。
- 搜索图标的位置必须是动态的
.c-input--search { background-image: url("data:image/svg+xml..."); background-position: right 6px center; } .c-header[dir="rtl"] .c-input--search { background-image: url("data:image/svg+xml..."); background-position: right 6px center; }
同样,当用户在此字段中键入文本时,文本不应与图标重叠。为避免这种情况,请在字段的两侧添加填充。
结果是LTR和RTL模式的以下标记:
下一个是移动菜单。要指定它,我将使用一个汉堡包图标。图标的位置将根据方向(LTR或RTL)而改变。位移动画的方向也是如此。
您可以在CodePen上观看演示感激之情
特别感谢我的妻子Kholoud的持续支持和对手册的多次阅读。也感谢Adebiyi Adedotun Lukman和ŠimeVidas的出色反馈。