原文来自 https://rtlstyling.com/posts/...
全世界有超过 2.92 亿人将阿拉伯语作为他们的第一语言。阿拉伯语(al-Arabiyyah,发音为 /al ʕarabijja/,/ʕarabiː/)是我的母语,我有时会构建需要同时支持从左到右 (LTR) 和从右到左 (RTL) 样式的网站。
RTL 样式介绍
CSS 中的默认页面方向是 LTR。如果您检查您选择的浏览器并检查该html
元素的浏览器默认代理样式,您会注意到这是ltr
或dir
(或direction)属性的默认值。下面是一个基本示例,用于显示 LTR 和 RTL 布局之间的区别。
请注意,对于 RTL 部分,文本从右到左读取,这与 LTR 文本相反。幸运的是,浏览器完成了这个简单示例的所有工作。要切换文档的语言方向,您需要将dir
属性添加到根元素。
<html dir="rtl">...</html>
当dir
改变时,以下因素也应自动翻转:标题,段落,链接,图像和表单元素。
值得一提的是,有一个dir="auto"
属性,它会根据解析的内容自动切换方向。根据HTML 规范:
敦促作者仅在文本方向确实未知时才将此值用作最后的手段,并且无法应用更好的服务器端启发式方法。
https://codepen.io/shadeed/pe...
除了dir=rtl
在 HTML 元素上设置属性外,我们还可以添加direction: rtl
为 CSS 样式。
.element { direction: rtl; }
但是,CSSWG 建议应该在html
根元素上定义方向,以确保在没有 CSS 的情况下正确的双向布局。
翻转设计的基本示例
让我们看一个更详细的示例,探索如何将设计从 LTR 翻转到 RTL。
<article class="media">
<img 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__photo {
float: left;
width: 200px;
margin-right: 16px;
}
添加dir="rtl"
阿拉伯元素后,结果如下所示:
除了图像,所有东西都被翻转了。那是因为它有float: left
和margin-right: 16px
。为了解决这个问题,我们需要覆盖这些样式:
.media[dir="rtl] img {
float: right;
margin-right: 0;
margin-left: 16px;
}
https://codepen.io/shadeed/pe...
在 LTR 布局中混合英语和阿拉伯语内容
如果某些文本混合了英语和阿拉伯语单词,而布局是 LTR,会发生什么情况?好吧,结果看起来很奇怪。
浏览器显示标题不正确。对于讲阿拉伯语的人来说,标题读起来会很混乱,除非你是写它的作者。它应该按照下图
为避免此问题,请尽可能设置适当的语言方向。一旦dir="rtl"
在元素上设置,
https://codepen.io/shadeed/pe...
当标题更长时,它会变得更复杂。下面,我把标题加长了一点,结果出乎意料。我已经附加了数字以显示正确的顺序。
当dir="rtl"
在元素上设置时,标题就清晰多了。也就是说,句子在语法上看起来是正确的,并且顺序正确。
https://codepen.io/shadeed/pe...
处理字体
根据 LTR 和 RTL 布局的设计,每个方向都应该有特定的字体。有些字体可以用于多种语言,这很棒。但是,品牌和企业倾向于为 RTL 使用不同的字体。
考虑到这一点,我们应该在项目的字体设置中定义不同的字体。有关更多详细信息,请参阅自动化工具。
字体系列
在 CSS 中,它的font-family
工作方式可以很容易地回退到另一种字体,以防字体未加载。但是,事实证明,如果声明中的第一种字体不支持特定字形,它将尝试使用第二种字体。
根据MDN:
字体选择不会简单地停在用户系统上列表中的第一个字体处。相反,字体选择一次一个字符完成,因此如果可用字体没有所需字符的字形,则尝试使用后一种字体。
Omar Bourhaouta做了以下演示,证明了上述概念:
https://codepen.io/bourhaouta...
body {
font-family: 'Roboto','Amiri', sans-serif;
}
Roboto 字体无法识别阿拉伯字形,因此它退回到第二个字体声明。
弹性盒布局模块
Flexbox 基于文档的书写模式。写入模式用于指定块在页面上的布局方式。例如,一个中文网站是从上到下布局的。写入模式就是为了这个目的。在 flexbox 中,items 是根据文档的书写方式来分配的。writing-mode
英语和阿拉伯语的默认值为horizontal-tb
。
根据MDN,horizontal-tb
意思如下:
内容从左到右水平流动,从上到下垂直流动。下一条水平线位于前一条线的下方。
当页面的方向更改为 RTL 时,地翻转其项目。这是一个巨大的好处!下图显示了 flexbox 轴如何根据方向翻转。
在下面的示例中,我布置了三个项目并为每个项目编号以显示
<div class="element">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
</div>
.element {
display: flex;
flex-direction: row; /* Default value, added for clarity */
}
https://codepen.io/shadeed/pe...
grid 网格布局模块
和 flexbox 一样,grid 布局模块依赖于文档的书写模式,这给了我们使用 flexbox 一样的好处。
在下面的示例中,main
当方向为 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;
}
https://codepen.io/shadeed/pe...
翻转到 RTL 时的常见错误
非阿拉伯语人士会犯一些很容易发现的常见错误。
- 字母间距
在英语中,添加letter-spacing
来调整单词的字母是很常见的。它也被称为排版中的跟踪。考虑以下英语内容示例。看起来很正常。
但是,如果将相同的letter-spacing
样式添加到阿拉伯语内容中,则会看起来很奇怪。考虑以下现实生活中的例子。
请注意,在带有 的内容中letter-spacing
,每个单词的字母看起来彼此断开。那是不对的。阿拉伯字母应该看起来是相连的,而保持英文则与之相反letter-spacing
。确保letter-spacing: 0
在处理多语言布局时进行设置。
https://codepen.io/shadeed/pe...
- 文字透明度
改变文本颜色的透明度是很常见的——例如,让它看起来是次要的。这在英语中有效。但是,当内容是阿拉伯语时,会导致奇怪的文本呈现问题。
有些区域的字母之间颜色不同。在这个例子中,letter-spacing
没有被调整,所以问题与此无关。解决方案是简单地设置没有 RGBa 或不透明度的颜色。
https://codepen.io/shadeed/pe...
- 语言之间的字数差异
有时,当一个网站被翻译成阿拉伯语时,由于某些词在翻译后变大或变小,元素的大小会发生变化。考虑以下示例,其中我模拟了 Smashing Magazine 网站的导航。
在阿拉伯语版本中,有些单词的大小与英语对应的单词几乎相同,有些相同,有些则更大。为了更清楚,这里是每个单词及其阿拉
您可能想知道为什么我要谈论字数的差异,因为这是正常的和预期的。考虑以下来自 LinkedIn 的真实示例。
按钮“完成”在阿拉伯语中被翻译为“تم”,这使得按钮太小而且看起来很奇怪。最好有一个min-width
按钮来解释这种情况。我在浏览器的开发人员工具中添加了它,以显示它的外观:
这是来自 Twitter 的一个非常相似的例子:
请注意,截至撰写本文时(2019 年 12 月 13 日),您已经真正发现了 LinkedIn 和 Twitter 上的上述问题。
- 文本截断
我曾经参与过一个内容混合的项目,我遇到了一个与文本截断方向错误相关的问题。考虑以下示例。
英文文本的截断不正确。它应该在元素的末尾,而不是它的开头。为了解决这个问题,dir="auto"
在元素本身上设置属性,然后浏览器会自动解析内容并决定dir
它是哪个。
<p dir="auto">أهلاً وسهلاً بكم في المقال الذي يتحدث عن تصميم صفحات الويب للغة العربية</p>
<p dir="auto">Welcome to the article that explains how to design for RTL pages.</p>
https://codepen.io/shadeed/pe...
- 选择一个糟糕的 RTL 字体
拥有设计的 RTL 版本并不意味着您可以选择系统的默认字体并收工。必须仔细选择字体以确保良好的可读性。一个例子是 Twitter:
从阿拉伯语使用者的角度来看,“تغريد”这个词很难读,原因如下:
- 字体不好。
- 粗体字阻碍了可读性。
- 这个词的点很小,非常接近字母。
我模拟了一个看起来更清晰的设计: - 混合印地语和阿拉伯数字#
在阿拉伯语中,有两种书写数字的方式: - 印地语:٠ ١ ٢ ٣ ٤ ٥ ٦ ٧ ٨ ٩
- 阿拉伯语:0 1 2 3 4 5 6 7 8 9
英语中使用的数字继承自阿拉伯数字:“0, 1, 2, 3, 4, 5, 6, 7, 8, 9”。包含数字的内容应该是一致的,无论是印地语还是阿拉伯数字。
根据维基百科:
这些数字在欧洲和美洲更常被称为“阿拉伯数字”的原因是它们在 10 世纪由北非的阿拉伯语使用者引入欧洲,当时他们使用从利比亚到摩洛哥的数字。
以下模型混合了印地语和阿拉伯数字。它看起来不一致,它应该与一种数字看起来统一。
可能不适用于 RTL 的常见事情
- 线高
为 RTL 布局设置不同的字体是很常见的。在这种情况下,测试内容在一行和多行上的外观。在以下示例中,阿拉伯语文本的行间距小于英语文本的行间距,即使它们具有相同的line-height
.
考虑到这一点并提供适合line-height
阿拉伯语的内容非常重要。
https://codepen.io/shadeed/pe...
例如,在 Twitter 上,由于 的值不合适,有一个带有截断内容的按钮line-height
。
请注意,在第一个图像中,阿拉伯语变音符号被截断了。它被称为“kasra”,它对于正确阅读这个词至关重要。在相邻的图像中,我已经固定了行高,现在它完全显示而没有被切断。
- 带下划线的链接
与阿拉伯语单词一起使用时,默认文本下划线看起来很糟糕。这与如何用阿拉伯语书写单词和字母有关。请参阅下图:
我用红色圆圈突出显示了奇怪的区域。下划线有点覆盖字母的点。还是不清楚?这是一个特写:
以蓝色突出显示的点与下划线重叠。这不好,而且它使文本难以阅读。解决方案是在 CSS 中使用自定义下划线。
2.1. 文字装饰可以使用 newtext-decoration-style
和text-decoration-colorproperties
更改下划线的样式和颜色。但是,不能保证适用于所有字体和字体大小。在撰写本文时,Firefox 是对这些属性支持最好的浏览器。
更新:2020 年 1 月 18 日
基于Github上的这个问题,结果证明使用text-decoration-skip-ink
属性可以解决点与下划线重叠的问题。它的默认值为skip
。
https://codepen.io/shadeed/pe...
在撰写本文时,Safari 不支持旧版 Edge(Chromium Edge 支持)。这是它在 Safari 中的外观:
2.2. 盒子阴影
浏览器对box-shadow
的支持比text-decoration
好得多。可以检测到对新属性之一text-decoration
的支持,如果浏览器不支持它,那么它将回退到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;
}
}
- 换行
如果您的 CSS 具有该word-break属性,则需要对其进行测试,因为它可能会破坏阿拉伯语单词。考虑以下:
由于 的影响,圈出的区域是断断续续的阿拉伯语单词word-break
。在阿拉伯语中,没有断字之类的东西。一个单词的字母是相互连接的,所以不可能打断一个单词。
缩写
在英语中,通常使用缩写来表示星期几。所以,“星期六”变成了“星期六”。
在阿拉伯语中,这根本不可能,因为单词的字母是要连接的。双向图标
对称图标不需要在 LTR 和 RTL 布局之间翻转。这里有些例子:
但是,对于某些图标,在 RTL 布局中翻转它们的方向很重要,以便用户可以清楚地理解它们。
然而,总有例外。根据Material Design指南,如果一个图标代表一个人可以用右手握住的对象,那么它就不需要翻媒体播放器图标
大约 15 年前,当我父亲给我买了一个 MP3 播放器时,我回到了过去。它有一个播放按钮,它有一个播放按钮,它的方向指向左边。
有些图标是通用的,不需要我们翻转它们。原因是因为那些播放按钮代表的是正在播放的磁带的方向,而不是时间的方向。以下是 Spotify 应用程序在英语和阿拉伯语中的外观:
请注意,播放图标不会翻转,因为它们是通用图标。
消息应用程序
在一个有趣的Twitter 讨论中,我被问到是否要翻转消息应用程序的发送图标。我为 Facebook Messenger、WhatsApp 和 Twitter 做了一些研究。
发送图标被翻转,在我个人看来,这是正确的做法,因为我觉得这更合乎逻辑。此外,发送和“+”按钮的位置应该翻转以使其更正确。见下面的样机:
另一方面,Facebook 和 Twitter 都没有翻转发送图标。
翻转组件
在处理某些组件时,我需要一种快速翻转它们的方法。在 Sketch 应用程序中,我将复制一个组件,然后使用“翻转”命令翻转它。Adobe XD 和 Figma 中提供了相同的功能。
为了明白我的意思,这里有一个 GIF 显示我在翻转一个组件后做了什么。
RTL 设计注意事项
在本节中,我将介绍最常见的组件并展示它们在 RTL 模式下的外观。
按钮图标
通常有一个带有图标的按钮,用于打开更多操作的菜单。在这种情况下,图标的位置应该在 RTL 布局中翻转。
表单输入
某些表单输入应在 RTL 中保持左对齐 - 例如,电子邮件和手机号码输入。
值得注意的是,如果占位符内容是阿拉伯语或其他 RTL 语言,则占位符应向右对齐。一旦输入被聚焦并且用户开始输入,对齐将向左翻转。
感谢蒋元浩让我知道上面的用例。
面包屑
面包屑模式中的箭头也应该翻转。
页眉
页眉组件包含开始和结束部分。它们中的每一个都应该在 RTL 中翻转。
表
桌子也应该翻转。
标签
对于 LTR 中的选项卡组件,图标将位于标签的左侧。在 RTL 中,这些应该被翻转。
卡片
对于水平卡片,图像和文本的顺序应该在 RTL 中翻转。
警告
正如您所料,“关闭”和警告图标应该翻转。
块引用
图标应该像下面的模型一样翻转。
CSS 逻辑属性
根据MDN:
CSS 逻辑属性和值是 CSS 的一个模块,它引入了逻辑属性和值,提供了通过逻辑而不是物理方向和维度映射来控制布局的能力。
我们举一个简单的例子。假设我们需要将一串文本向左对齐。因此,我们添加以下内容:
.page-header {
text-align: right;
}
对于 RTL:
[dir="rtl"] .nav-item {
text-align: left;
}
如果有一种方法可以添加一个text-align
根据页面方向改变方向的值呢?CSS 逻辑属性来拯救你!
.page-header {
text-align: end;
}
有了这个, 的方向text-align
将基于页面。演示
为了更容易看到的区别start
和end
,我做了下面的样机。该start
值在 LTR 中等于 left,end
在 RTL 中等于 right
。这同样适用于end
。
现在您已经对它的工作原理有了基本的了解,让我们探索更多 CSS 逻辑属性的示例和用例。
逻辑填充
假设我们有一个搜索输入,右侧有一个搜索图标。我们应该在左侧和右侧添加填充。右边的填充会大一点,以防止文本落在搜索图标下方。
.input--search {
padding-inline-start: 1rem;
padding-inline-end: 2.5rem;
}
此图标右侧的边距需要符合逻辑,因此我们将使用margin-inline-start
。
.page-header__avatar {
margin-inline-start: 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;
}
逻辑属性备忘单
当对定向 CSS 属性的逻辑等效项有疑问时,请使用下面的备忘单。请注意,包含的属性仅限于对 LRT 和 RTL 有用的属性。我是根据Adrian Roselli 的一篇很棒的文章制作的。
https://codepen.io/shadeed/pe...
除此之外,Adrian 创建了一个演示,可以轻松理解逻辑 CSS 属性和定向 CSS 属性之间的区别。
https://codepen.io/aardrian/p...
浏览器支持
浏览器支持是相当不错的padding
,margin
和text-align
。但是,这对边界半径属性不利。以下是Can I Use中的支持表:
尽管支持并不完美(并且永远不会完美),但我建议您使用带有回退的 CSS 逻辑属性。例如:
.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__startand
.c-page-header__end
。这更具前瞻性,并且不会假设网站只是 LTR 或 RTL。
双向垂直滚动条
据我所知,CSS 中容器内的垂直滚动条方向会根据页面方向而变化。对于 RTL 布局,滚动条方向在左侧,而对于 LTR,则在右侧。
考虑下图。
但是,对于操作系统,浏览器的滚动条不会改变,无论操作系统语言如何,它都保持在右侧。但是对于操作系统本身,滚动条会根据其语言而变化。
自动化工具
当我们需要将设计从 LTR 翻转到 RTL 时,有很棒的工具可以使我们的工作更轻松。
1. Bi-App-Sass
Anas Nakawa 的Bi-App-Sass允许您编写样式表一次,然后将它们编译成两个不同的样式表,一个用于 LTR,另一个用于 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
Mohammad Younes 的RTLCSS是一个将 LTR 样式表转换为 RTL 的框架。
此工具的不同之处在于它仅在 CSS 文件的构建版本上运行。例如,如果您有一个包含 50 多个 Sass 组件的项目,RTLCSS 将派上用场,用于解析已编译的 CSS 文件并创建它的 RTL 版本。
实际例子
网站标题#
我专门设计了一个布局来向您展示我将如何处理和考虑将其翻转为 RTL 布局。
让我们从标题组件开始。为了正确编码,我概述了一个通用框架。请注意,我已将标题分为主要部分和子部分。另外,我为这些部分添加了开始和结束类。
.header__main,
.header__sub {
display: flex;
justify-content: space-between;
}
并且因为 CSS flexbox 基于页面的方向工作,正如本指南前面所解释的,它会为 RTL 自动翻转。
接下来是标志和导航之间的分界线。起初,我考虑使用border-right. 它有效但并不理想。使用伪元素会更好,因为它会根
.c-brand:after {
content: "";
display: inline-block;
vertical-align: middle;
width: 3px;
height: 38px;
border-radius: 5px;
background: #e4e4e4;
margin-inline-start: 1.25rem;
}
这是到目前为止的结果:
接下来,我将处理主题组件(带有标签和计数器的子标题中的组件)。这是主题组件在 LTR 和 RTL 中的外观设计模型。请注意,计数器的位置是不同的。
乍一看似乎很简单,但是需要在 LTR 和 RTL 之间处理多个 padding 和 margin 声明。
.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。当我用translate
给箭头添加动画时,我想到了 RTL。这没有逻辑属性,我需要探索其他解决方案。我想出的一种解决方案是为边距设置动画。.c-link svg { margin-inline-start: 4px; transition: 0.15s ease-in; } .c-link:hover svg { margin-inline-start: 8px; }
但是动画边距对性能不利,尽管它有效。另一种解决方案是检测页面的方向,并用
translate
基于此设置声明。.c-link:hover svg { transform: translateX(6px); } /* I’m using dir=rtl in the header for the purpose of clarity. It should be added to the root element. */ .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)
水平翻转箭头图标。你可以改用rotate(180deg)
,但scaleX对我来说更直接。
接下来是搜索输入。以下是要求:
- 搜索图标必须出现在输入元素的末尾。
搜索图标的位置必须是动态的。
.c-input--search { background-image: url("data:image/svg+xml..."); background-position: right 6px center; } .c-header[dir="rtl"] .c-input--search { /* We replace the original icon with a flipped one. */ background-image: url("data:image/svg+xml..."); background-position: right 6px center; }
此外,当用户在搜索框中键入时,文本不应在图标下方滑动。为避免这种情况,请在右侧或左侧添加填充。
.c-input { padding-inline-end: 32px; }
这是迄今为止 LTR 和 RTL 的结果:
接下来是移动菜单。我将使用一个汉堡包图标来指示菜单。图标的位置将在 LTR 和 RTL 之间更改。translate
动画的方向也是如此。
查看CodePen 上的演示。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。