全世界有超过2.92亿人以阿拉伯语作为第一语言,它的阅读方向是从右到左的方向。最近在做国际化就需要支持阿拉伯语,所以我们就需要构建同时支持从左到右(LTR)和从右到左(RTL)样式的网站。
RTL样式简介
CSS中页面的默认方向是LTR。如果你检查浏览器的默认代理样式,会发现html
元素的dir
(或"direction")属性默认值是ltr
。下面是一个基本示例,展示了 LTR 和 RTL 布局的区别。
注意RTL部分的文本是从右到左读的,与LTR文本相反。好的是,浏览器为这个简单的例子完成了所有工作。要切换文档的语言方向,你需要在根元素上添加dir
属性。
<html dir="rtl">
...
</html>
当dir
改变时,以下元素应该自动翻转:标题、段落、链接、图像和表单元素。
值得一提的是,还有一个dir="auto"
属性,它会根据解析的内容自动切换方向。根据HTML规范:
强烈建议开发者只在文本方向真的未知,且无法应用更好的服务器端启发式方法时,才将此值作为最后的手段。
除了在HTML元素上设置dir=rtl
属性外,我们还可以添加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;
}
在 LTR 版面中混合使用英语和阿拉伯语内容
如果某些文本混合了英语和阿拉伯语单词,而排版又是 LTR 格式,会发生什么情况?那么,结果看起来会很奇怪。
浏览器显示标题不当。对于讲阿拉伯语的人来说,除非是撰写标题的作者,否则标题读起来会令人困惑。应该按照下图所示的顺序阅读。
为避免这一问题,请尽可能设置适当的语言方向。一旦在元素上设置了dir="rtl",它就会如期出现。
<div class="wrapper">
<p style="margin-bottom: 0.5rem;">Right to Left (RTL), Mixed Content of English and Arabic</p>
<article class="media" dir="rtl">
<img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/182774/blueberry-cheesecake.jpg" alt="">
<div class="media__content">
<h2>كيفية عمل Cheesecake بالتوت البري</h2>
<p>هنا سيكون شرح معين عن هذه الوصفة.</p>
<p><a href="#" class="link">عرض الوصفة</a></p>
</div>
</article>
<p style="margin-bottom: 0.5rem;">Left to Right (LTR), Mixed Content of English and Arabic</p>
<article class="media" dir="">
<img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/182774/blueberry-cheesecake.jpg" alt="">
<div class="media__content">
<h2>كيفية عمل Cheesecake بالتوت البري</h2>
<p>هنا سيكون شرح معين عن هذه الوصفة.</p>
<p><a href="#" class="link">عرض الوصفة</a></p>
</div>
</article>
</div>
.media {
background: #fff;
box-shadow: 0 3px 10px 0 rgba(#000, 0.1);
padding: 1rem;
margin-bottom: 2.5rem;
h2 {
font-size: 24px;
font-weight: bold;
margin-bottom: 0.5rem;
}
img {
float: left;
width: 200px;
margin-right: 16px;
border: 1px solid lightgrey;
}
&:after {
content: "";
display: block;
clear: both;
}
}
.media[dir="rtl"] {
img {
float: right;
margin-right: 0;
margin-left: 16px;
}
}
.link {
display: inline-block;
margin-top: 1rem;
//background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='%231d7bb3'%3E%3Cpath d='M4,11V13H16L10.5,18.5L11.92,19.92L19.84,12L11.92,4.08L10.5,5.5L16,11H4Z'%3E%3C/path%3E%3C/svg%3E") right center/20px no-repeat;
//padding-right: 24px;
color: #1d7bb3;
}
/* Non Demo Related Styling */
body {
background: #f6f6f6;
font-family: 'Rubik', sans-serif;
line-height: 1.35;
}
.wrapper {
max-width: 800px;
margin: 2rem auto;
padding-left: 1rem;
padding-right: 1rem;
}
当标题较长时,情况会变得更加复杂。下面,我把标题加长了一些,结果出乎意料。我用数字表示了正确的顺序。
当在元素上设置dir="rtl时,标题会更加清晰。也就是说,句子看起来语法正确,顺序正确。
处理字体
根据 LTR 和 RTL 布局的设计,每个方向都应该有特定的字体。有些字体可用于多种语言,这很好。但是,品牌和企业倾向于为 RTL 使用不同的字体。
字体系列
在 CSS 中,font-family的工作方式是在一种字体无法加载的情况下,很容易返回到另一种字体。但事实证明,如果声明中的第一种字体不支持特定的字形,它就会尝试使用第二种字体。
据MDN :
字体选择不会简单地停留在用户系统上的列表中的第一个字体。相反,字体选择是一个字符一个字符地进行的,因此,如果一个可用字体没有所需字的字形,就会尝试后面的字体。
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation আগুনের laboris nisi ut aliquip ex ea commodo consequat.</p>
<p dir="rtl">فقد عن أسابيع العالمي, يعادل الإثنان نفس أي, ثم دخول حقول مقاطعة دار. فمرّ ومطالبة تحت ثم. ببعض تصرّف الأرواح بعض بل, هذا المؤلّفة اليابانية بـ. مرمى اعتداء 1234 الصفحات في به، لغزو exercitation إعادة الشمل تحت ثم. لمّ ثم عملية السيطرة أي এসেছিলাম ليركز غينيا تحت. تم ببعض غينيا بأيدي ذلك, الحكم الثقيلة جعل واستعملت الأوربيين.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco الحكم الثقيلة nisi ut aliquip ex ea commodo consequat.</p>
body {
font-family: "Roboto", "Amiri", sans-serif;
}
Roboto 字体无法识别阿拉伯文字形,因此退回到第二个字体声明。
Flexbox 布局模块
Flexbox 是基于文档的书写模式的。书写模式用于指定块如何在页面上布局。例如,中文网站是从上到下布局的。书写模式就是为此目的而设的。在 flexbox 中,项目是根据文档的书写模式来分布的。英语和阿拉伯语的 writing-mode
默认值是 horizontal-tb
。
内容从左到右横向流动,从上到下纵向流动。下一行水平线位于上一行的下方。
当页面方向改变为RTL时,flexbox会相应地翻转其项目。这是一个巨大的优势!下面的插图展示了flexbox轴如何根据方向进行翻转。
在下面的示例中,我列出了三个项目,并为每个项目编号,以显示方向改变时的差异。
<div class="wrapper">
<p style="margin-bottom: 0.5rem;">Left to Right (LTR)</p>
<div class="element">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
</div>
<p style="margin-bottom: 0.5rem;">Right to Left (RTL)</p>
<div class="element" dir="rtl">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
</div>
</div>
.element {
display: flex;
flex-direction: row; /* Default value, added for clarity */
}
网格布局模块
与 flexbox 一样,网格布局模块也依赖于文档的书写模式,这与使用 flexbox 带来的好处相同。
在下面的例子中,当方向是LTR(从左到右)时,侧边栏应该在左侧,而main
内容在右侧。对于RTL(从右到左),则恰好相反。当我们使用CSS网格时,根据页面的方向,翻转将自动完成。
<div class="wrapper">
<p style="margin-bottom: 0.5rem;">Left to Right (LTR)</p>
<div class="element">
<div class="side">Side</div>
<div class="main">Main</div>
</div>
<p style="margin-bottom: 0.5rem;">Right to Left (RTL)</p>
<div class="element" dir="rtl">
<div class="side">ثانوي</div>
<div class="main">رئيسي</div>
</div>
</div>
.element {
display: grid;
grid-template-columns: 220px 1fr;
grid-gap: 1rem;
}
翻转到RTL时的常见错误
非阿拉伯语使用者会犯一些容易发现的常见错误。
1. 字母间距 #
在英语中,通常会添加 letter-spacing
来调整单词的字母间距。这在排版中也被称为字距调整。考虑以下英语内容的例子。它看起来很正常。
然而,如果将相同的 letter-spacing
样式应用到阿拉伯语内容上,就会看起来很奇怪。请看下面这个真实的例子。
注意在有 letter-spacing
的内容中,每个单词的字母看起来彼此分离。这是不对的。阿拉伯字母应该看起来是连在一起的,而保留英语的 letter-spacing
会破坏这一点。在处理多语言布局时,请确保设置 letter-spacing: 0
。
<div class="wrapper">
<p style="margin-bottom: 0.5rem;">Right to Left (RTL), Without letter-spacing</p>
<article class="media" dir="rtl">
<h2>فطيرة الجبن بالتوت البري</h2>
</article>
<p style="margin-bottom: 0.5rem;">Right to Left (RTL), With letter-spacing</p>
<article class="media media--ls" dir="rtl">
<h2>فطيرة الجبن بالتوت البري</h2>
</article>
</div>
2.文本透明度
改变文字颜色的透明度很常见--例如,让它看起来更次要。这在英语中是可行的。但是,当内容是阿拉伯语时,就会出现奇怪的文字渲染问题。
在字母之间有一些区域颜色不同。在这个例子中,letter-spacing
(字母间距)并没有被调整,所以问题与此无关。解决方案很简单,只需设置颜色时不使用RGBa或透明度。
.media {
background: #168fd5;
box-shadow: 0 3px 10px 0 rgba(#000, 0.1);
padding: 1rem;
margin-bottom: 2.5rem;
h2 {
color: #fff;
font-size: 32px;
font-weight: bold;
margin-bottom: 0.5rem;
opacity: 0.5;
}
}
3.不同语言单词量的差
有时,当一个网站被翻译成阿拉伯语时,由于一些单词在翻译后变大或变小,元素的大小会发生变化。请看下面的例子
在阿拉伯语版本中,有些单词的大小与其英语对应单词几乎相同,有些相同,有些则更大。为了更清楚起见,下面是每个单词及其阿拉伯语译文的对比。
你可能会疑惑为什么我要谈论单词大小的差异,因为这是正常且可以预料的。请看下面这个来自LinkedIn的真实例子。
"Done"按钮被翻译成阿拉伯语的"تم",这使得按钮变得太小,看起来很怪异。为了应对这种情况,最好为按钮设置一个min-width
(最小宽度)。我在浏览器的开发者工具中添加了这个属性,以展示它应该是什么样子:
下面是 Twitter 上一个非常类似的例子:
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布局设置不同的字体是很常见的。在这种情况下,需要测试内容在单行和多行情况下的显示效果。在下面的例子中,尽管阿拉伯文本和英文文本都设置了相同的line-height
(行高),但阿拉伯文本的行间距比英文的要小。
重要的是要考虑到这一点,并为阿拉伯文内容提供合适的line-height。
<div class="wrapper" dir="rtl">
<p>أهلاً وسهلاً بكم في المقال الذي يتحدث عن تصميم صفحات الويب للغة العربية</p>
<p>Welcome to the article that explains about how to design web for RTL pages</p>
</div>
p {
font-size: 18px;
margin-bottom: 1rem;
}
p:nth-child(1) {
line-height: 1.5;
}
例如,在 Twitter 上有一个按钮,由于 line-height 不合适,内容被截断了。
请注意,在第一张图片中,阿拉伯文的一个分音符被剪掉了。它被称为 "kasra",对于正确读取单词至关重要。在相邻的图片中,调整了行高,现在它可以完整地显示出来,而不会被切掉。
2.下划线链接
与阿拉伯语单词一起使用时,默认文本下划线看起来很糟糕。这与阿拉伯语中单词和字母的书写方式有关。请看下面的插图:
用红圈标出了奇怪的地方。下划线遮住了字母的圆点
蓝色突出显示的点与下划线重叠。这样不好,会使文本难以阅读。解决办法是使用 CSS 自定义下划线。
2.1.文字装饰
使用新的text-decoration-style
和text-decoration-color
属性可以更改下划线的样式和颜色。但不能保证适用于所有字体和字体大小。在撰写本文时,Firefox 是对这些属性支持最好的浏览器
3. Line Break
如果 CSS 具有 word-break
属性,需要对其进行测试,因为它可能会断开阿拉伯语单词。请考虑以下情况:
被圈出的区域是由于word-break
效果导致的破碎阿拉伯单词。在阿拉伯语中,不存在单词断行这种情况。一个单词的字母是相互连接的,所以不可能将一个单词断开。
4.缩略语
在英语中,通常使用缩写来表示一周中的某几天。因此,"星期六 "就变成了 "Sat"
在阿拉伯语中,这根本不可能,因为一个单词的字母是要连在一起的。
双向图标
对称图标无需在 LTR 和 RTL 布局之间翻转。下面是一些例子:
不过,对于某些图标来说,在 RTL 布局中翻转它们的方向是很重要的,这样用户才能清楚地理解它们。
然而,总是存在例外情况。根据材料设计指南,如果一个图标代表的是可以用人的右手握持的物体,那么它就不需要翻转。以下是一些例子:
媒体播放器图标
MP3 播放器有一个播放按钮,方向指向左边。
有些图标是通用的,不需要我们翻转。原因是这些播放按钮代表的是磁带播放的方向,而不是时间的方向。以下是 Spotify 应用程序的英文和阿拉伯文版本:
请注意,播放图标没有翻转,因为它们是通用图标。
消息应用程序
发送图标是否要翻转?
下面是Facebook Messenger、WhatsApp 和 Twitter:
发送图标是翻转的,我个人认为这样做是正确的,因为我觉得这样更符合逻辑。此外,发送和 "+"按钮的位置也应翻转,使其更加正确。请看下面的模拟图:
另一方面,Facebook 和 Twitter 都没有翻转发送图标。
翻转组件
在处理一些组件时,我需要一种快速翻转它们的方法。在 Sketch 应用程序中,我会复制一个组件,然后使用 "flip(翻转)"命令将其翻转。Adobe XD 和 Figma 中也有相同的功能。
RTL 设计注意事项
在本节中,,展示最常见的组件在 RTL 模式下的外观
按钮图标
通常情况下,按钮上的图标会打开一个菜单,供用户执行更多操作。在这种情况下,图标的位置应在 RTL 布局中翻转。
表格输入
某些表单输入在 RTL 中应保持左对齐,例如电子邮件和手机号码输入。
值得注意的是,如果占位符内容是阿拉伯语或其他 RTL 语言,那么占位符应向右对齐。一旦输入被聚焦,用户开始键入,对齐方式就会向左翻转。
面包屑
面包屑图案中的箭头也应翻转。
页眉
页眉组件包含开始和结束部分。每个部分都应在 RTL 下翻转。
表格
一张表格也应翻转。
Tabs
卡片
Toasts
方括号
图标应翻转,如下图所示。
switch
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 之间的区别更容易理解,制作了下面的模型图。在LTR(从左到右)布局中,start值等同于左侧,而在RTL(从右到左)布局中,end等同于右侧。这个规则同样适用于end值。
现在你已经对 CSS 逻辑属性的工作原理有了基本的了解,现在,我们来探讨 CSS 逻辑属性的更多示例和用例。
padding
假设我们有一个搜索输入框,右侧有一个搜索图标。我们应该在左侧和右侧都添加 padding 。右边的填充要大一些,以防止文本掉到搜索图标下面。
.input--search {
padding-inline-start: 1rem;
padding-inline-end: 2.5rem;
}
margin
图标右侧的边距需要符合逻辑,因此我们将使用margin-inline-start
来处理
.page-header__avatar {
margin-inline-start: 1rem;
}
border
很多时候,你可能需要添加一个边框来表示导航元素处于活动状态。在上面的设计中,每个导航元素的左侧都有一个边框。如何使其符合逻辑呢?
.nav__item {
border-inline-start: 3px solid transparent;
}
.nav__item.is-active {
border-color: #1e9ada;
}
border radius
在上面的设计中,导航元素的背景只有右上角和右下角有边框半径。为了在逻辑上做到这一点,我们使用了以下方法:
.nav__item {
border-start-end-radius: 30px;
border-end-end-radius: 30px;
background-color: transparent;
}
.nav__item.is-active {
background-color: #ecf6fb;
}
逻辑属性小抄
浏览器支持
浏览器对padding、margin 和text-align 的支持相当不错。不过,浏览器对 border-radius 属性的支持就不太好了。以下是Can I Use 提供的支持表:
尽管支持还不完善(而且永远不会完善),但我建议您使用带有回退功能的 CSS 逻辑属性。例如
.input--search {
padding-left: 1rem;
padding-right: 2.5rem;
padding-inline-start: 1rem;
padding-inline-end: 2.5rem;
}
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代表组件。
既然你已经明白了这个概念,我们也可以将它应用到 RTL 风格设计中。下面的设计模型有一个包含两个子代的部分。
没有给这些元素取 .c-page-header__left
和 .c-page-header__right
这样的表述性名称,而是将它们命名为 .c-page-header__start
和 .c-page-header__end
。这样做更能面向未来,而且不会假定网站只有 LTR 或只有 RTL。
双向垂直滚动条
据我所知,CSS 中容器内的垂直滚动条方向会根据页面方向而改变。对于 RTL 布局,滚动条方向在左侧,而对于 LTR 布局,滚动条方向在右侧。
请看下图:
但是,对于操作系统来说,浏览器的滚动条不会改变,无论使用哪种操作系统语言,滚动条都会保持在右侧。但对于操作系统本身,滚动条会根据语言的不同而改变。
自动化工具
当我们需要将设计从 LTR 翻转到 RTL 时,有很多好工具可以让我们的工作变得更轻松。
1. Bi-App-Sass
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;
}
2.RTLCSS
Mohammad Younes 的RTLCSS是一个将 LTR 样式表转换为 RTL 的框架。
该工具的不同之处在于,它只在 CSS 文件的构建版本上运行。例如,如果你有一个包含 50 多个 Sass 组件的项目,RTLCSS 就能派上用场,帮助你解析编译后的 CSS 文件并创建 RTL 版本。
首发于公众号 大迁世界,欢迎关注。📝 每周一篇实用的前端文章 🛠️ 分享值得关注的开发工具 ❓ 有疑问?我来回答
本文 GitHub https://github.com/qq449245884/xiaozhi 已收录,有一线大厂面试完整考点、资料以及我的系列文章。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。