The original text is from https://rtlstyling.com/posts/rtl-styling
More than 292 million people around the world speak Arabic as their first language. Arabic (al-Arabiyyah, pronounced /al ʕarabijja/, /ʕarabiː/) is my native language, and I sometimes build websites that need to support both left-to-right (LTR) and right-to-left (RTL) styles.
RTL style introduction
The default page orientation in CSS is LTR. If you check the browser of your choice and check the html
element, you will notice that this is ltr
or dir
(or direction) attribute. Below is a basic example to show the difference between LTR and RTL layout.
Note that for the RTL part, the text is read from right to left, which is the opposite of LTR text. Fortunately, the browser has done all the work of this simple example. To switch the language direction of the document, you need to add the dir
attribute to the root element.
<html dir="rtl">...</html>
When dir
changed, the following factors should also be automatically flipped: headings, paragraphs, links, images and form elements.
It is worth mentioning that there is a dir="auto"
attribute, which will automatically switch the direction according to the content of the analysis. According to HTML specification:
Authors are urged to use this value as a last resort only when the direction of the text is truly unknown, and no better server-side heuristics can be applied.
https://codepen.io/shadeed/pen/7662a5f048c5a6a1bbdb89905327c965
In addition to setting attributes on HTML elements with dir=rtl
direction: rtl
as a CSS style.
.element { direction: rtl; }
However, CSSWG recommends that the html
to ensure correct bidirectional layout without CSS.
Basic example of flip design
Let's look at a more detailed example and explore how to flip the design from LTR to 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>
Initially, I used old floating point numbers in the LTR design to align the image to the left-of course, I used clearfix.
.media:after {
content: "";
display: block;
clear: both;
}
.media__photo {
float: left;
width: 200px;
margin-right: 16px;
}
After adding dir="rtl"
Arabic elements, the result is as follows:
Except for the image, everything has been flipped. That's because it has float: left
and margin-right: 16px
. In order to solve this problem, we need to cover these styles:
.media[dir="rtl] img {
float: right;
margin-right: 0;
margin-left: 16px;
}
https://codepen.io/shadeed/pen/8f6024ed27c37f51b17198fc3c321a63
Mix English and Arabic content in the LTR layout
What happens if some text mixes English and Arabic words and the layout is LTR? Well, the result looks strange.
The browser display title is incorrect. For Arabic speakers, the title will be confusing to read unless you are the author who wrote it. It should follow the figure below
To avoid this problem, please set the appropriate language direction whenever possible. Once dir="rtl"
is set on the element,
https://codepen.io/shadeed/pen/b254fb1c68ce1f8cce9c5b0917228326
When the title is longer, it becomes more complicated. Next, I lengthened the title a bit, and the result was unexpected. I have appended the numbers to show the correct order.
When dir="rtl"
is set on the element, the title is much clearer. In other words, the sentences appear to be grammatically correct and in the correct order.
https://codepen.io/shadeed/pen/02f4dccfb898bee7d1e1daa71f3bd6ac
Handling fonts
According to the design of the LTR and RTL layout, there should be a specific font in each direction. Some fonts can be used in multiple languages, which is great. However, brands and companies tend to use different fonts for RTL.
With this in mind, we should define different fonts in the font settings of the project. For more details, see Automation Tool .
Font family
In CSS, its font-family
working method can easily fall back to another font in case the font is not loaded. However, it turns out that if the first font in the statement does not support a specific glyph, it will try to use the second font.
According to MDN :
The font selection does not simply stop at the first font in the list on the user's system. Instead, the font selection is done one character at a time, so if the available font does not have the glyph of the desired character, try the latter font.
Omar Bourhaouta did the following demonstration to prove the above concept:
https://codepen.io/bourhaouta/pen/GRgLqYL
body {
font-family: 'Roboto','Amiri', sans-serif;
}
The Roboto font cannot recognize Arabic glyphs, so it falls back to the second font declaration.
Flexbox layout module
Flexbox is a document-based writing mode. The write mode is used to specify how the block is laid out on the page. For example, a Chinese website is laid out from top to bottom. The write mode is for this purpose. In flexbox, items are allocated according to how the document is written. writing-mode
default English and Arabic is horizontal-tb
.
According to MDN , horizontal-tb
means as follows:
The content flows horizontally from left to right and vertically from top to bottom. The next horizontal line is below the previous line.
When the orientation of the page is changed to RTL, its items are flipped ground. This is a huge benefit! The following figure shows how the flexbox axis is flipped according to the direction.
In the example below, I laid out three items and numbered each item to show
<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/pen/76082ed22d043f1ebcdcf1037dda13f2
grid grid layout module
Like flexbox, the grid layout module depends on the writing mode of the document, which gives us the same benefits as using flexbox.
In the example below, main
when the direction is LTR, the sidebar should be on the left and the content should be on the right. For RTL, the reverse is also true. When we use CSS grid, the flip will be done automatically according to the orientation of the page.
<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/pen/b15d4b4f81ce1b03ed9c1d99c560f64c
Common mistakes when flipping to RTL
Non-Arabic speakers make some common mistakes that are easy to spot.
- Letter spacing
In English, itletter-spacing
to adjust the letter of a word. It is also called tracking in typesetting. Consider the following example of English content. It looks normal.
However, if the sameletter-spacing
style is added to the Arabic content, it will look strange. Consider the following real life example.
Please note that in the content withletter-spacing
, the letters of each word appear to be disconnected from each other. That is not right. Arabic letters should appear to be connected, while keeping English is the opposite ofletter-spacing
. Ensure thatletter-spacing: 0
when dealing with multi-language layouts.
https://codepen.io/shadeed/pen/29b1428dac29ced513adc482b22e7372
- Text transparency
It is very common to change the transparency of the text color-for example, to make it look secondary. This is valid in English. However, when the content is in Arabic, it can cause strange text rendering problems.
The colors of the letters in some areas are different. In this example, letter-spacing
has not been adjusted, so the problem is irrelevant. The solution is to simply set the color without RGBa or opacity.
https://codepen.io/shadeed/pen/d8b1d30b39933e0435e52b738b0402dd
- Word count differences between languages
Sometimes, when a website is translated into Arabic, the size of the elements will change as certain words become larger or smaller after translation. Consider the following example, in which I simulated the navigation of the Smashing Magazine website.
In the Arabic version, some words are almost the same size as their English counterparts, some are the same, and some are larger. To be more clear, here is each word and its Allah
You may be wondering why I am talking about the difference in word count, because this is normal and expected. Consider the following real example from LinkedIn.
The button "Done" is translated as "تم" in Arabic, which makes the button too small and looks strange. It is best to have amin-width
button to explain this situation. I added it to the developer tools of the browser to show how it looks:
This is a very similar example from Twitter:
Please note that as of the time of writing (December 13, 2019), you have actually discovered the above issues on LinkedIn and Twitter.
- Text truncation
I once participated in a mixed content project, and I encountered a problem related to the wrong direction of text truncation. Consider the following example.
The truncation of the English text is incorrect. It should be at the end of the element, not at the beginning. To solve this problem, dir="auto"
sets attributes on the element itself, and then the browser will automatically parse the content and decide which dir
it is.
<p dir="auto">أهلاً وسهلاً بكم في المقال الذي يتحدث عن تصميم صفحات الويب للغة العربية</p>
<p dir="auto">Welcome to the article that explains how to design for RTL pages.</p>
https://codepen.io/shadeed/pen/aa503390e648a1738c0bb1492cbd72ae
- Choose a bad RTL font
Having the RTL version of the design does not mean that you can choose the system's default font and call it a day. The font must be chosen carefully to ensure good readability. An example is Twitter:
From the perspective of Arabic speakers, the word "تغريد" is difficult to read for the following reasons:
- The font is bad.
- Bold font hinders readability.
- The dots of this word are very small, very close to the letters.
I simulated a design that looks clearer: - Mixing Hindi and Arabic numerals#
In Arabic, there are two ways of writing numbers: - Hindi: ٠ ١ ٢ ٣ ٤ ٥ ٦ ٧ ٨ ٩
- Arabic: 0 1 2 3 4 5 6 7 8 9
The numbers used in English are inherited from Arabic numerals: "0, 1, 2, 3, 4, 5, 6, 7, 8, 9". The content containing the numbers should be consistent, whether it is Hindi or Arabic numbers.
According to Wikipedia:
The reason these numbers are more commonly referred to as "Arabic numerals" in Europe and the Americas is that they were introduced to Europe by Arabic speakers in North Africa in the 10th century, when they used numbers from Libya to Morocco.
The following model mixes Hindi and Arabic numerals. It looks inconsistent, it should look uniform with a number.
Common things that may not apply to RTL
- Line height
It is very common to set different fonts for the RTL layout. In this case, test the appearance of the content on one line and multiple lines. In the following example, the line spacing of Arabic text is smaller than that of English text, even though they have the sameline-height
.
It is very important to take this into consideration and provideline-height
https://codepen.io/shadeed/pen/1cb6b25852a009d5fdaf1902bcfaa974
For example, on Twitter, because the value is inappropriate, there is a buttonline-height
with truncated content.
Note that in the first image, the Arabic diacritics are truncated. It is called "kasra" and it is essential to read the word correctly. In the adjacent image, I have fixed the line height, and now it is displayed completely without being cut off.
- Underlined link
When used with Arabic words, the default text underline looks terrible. This is related to how to write words and letters in Arabic. Please refer to the picture below:
I used a red circle to highlight the strange area. The underscore somewhat covers the point of the letter. Still not clear? This is a close-up:
The point highlighted in blue overlaps the underline. This is not good, and it makes the text difficult to read. The solution is to use custom underscores in CSS.
2.1. Text decoration can use newtext-decoration-style
and text-decoration-colorproperties
change the style and color of the underline. However, it cannot be guaranteed to be applicable to all fonts and font sizes. At the time of writing, Firefox is the browser with the best support for these attributes.
update: January 18, 2020
Based on this question on Github, it turns out that using the text-decoration-skip-ink
attribute can solve the problem of overlapping dots and underscores. Its default value is skip
.
https://codepen.io/shadeed/pen/9f8c134e0d4fe1f0d58ba3c23cb96e41
At the time of writing, Safari does not support the old version of Edge (Chromium Edge support). This is how it looks in Safari:
2.2. Box shadow
Browser box-shadow
support than text-decoration
much better. The support for one of the new attributes, text-decoration
, can be detected. If the browser does not support it, it will box-shadow
back to 060d4429eacecc.
.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;
}
}
- Wrap
If your CSS has the word-break attribute, you need to test it because it may break Arabic words. Consider the following:
Due to the influence, the circled area is the intermittent Arabic word word-break
. In Arabic, there is no such thing as hyphenation. The letters of a word are connected to each other, so it is impossible to interrupt a word.
abbreviation
In English, abbreviations are usually used to indicate the day of the week. Therefore, "Saturday" has become "Saturday".
In Arabic, this is impossible because the letters of the word are connected.Two-way icon
Symmetrical icons do not need to be flipped between the LTR and RTL layouts. Here are some examples:
However, for some icons, it is important to flip their direction in the RTL layout so that users can clearly understand them.
However, there are always exceptions. According to the Material Design guide, if an icon represents an object that a person can hold with his right hand, then it does not need to be translatedMedia player icon
When my father bought me an MP3 player about 15 years ago, I went back in time. It has a play button, it has a play button, and its direction points to the left.
Some icons are universal and we don’t need to flip them. The reason is because those play buttons represent the direction of the tape being played, not the direction of time. Here is how the Spotify app looks in English and Arabic:
Please note that the play icons will not be flipped, because they are universal icons.
Messaging app
In a interesting Twitter discussion, I asked whether you want to flip the send icon messaging applications. I did some research for Facebook Messenger, WhatsApp and Twitter.
The sending icon is flipped. In my opinion, this is the correct approach, because I think it is more logical. In addition, the position of the send and "+" buttons should be flipped to make it more correct. See the prototype below:
On the other hand, neither Facebook nor Twitter has flipped the send icon.
Flip the component
When dealing with certain components, I need a way to quickly flip them. In the Sketch application, I will copy a component and then use the "Flip" command to flip it. The same functionality is provided in Adobe XD and Figma.
To understand what I mean, here is a GIF showing what I did after flipping a component.
RTL design considerations
In this section, I will introduce the most common components and show how they look in RTL mode.
Button icon
There is usually a button with an icon to open a menu for more operations. In this case, the position of the icon should be flipped in the RTL layout.
Form input
Certain form entries should be left-aligned in RTL-for example, email and mobile number entry.
It is worth noting that if the content of the placeholder is Arabic or other RTL languages, the placeholder should be aligned to the right. Once the input is focused and the user starts typing, the alignment will flip to the left.
Thanks to Yuanhao for letting me know the above use case.
Bread crumbs
The arrow in the breadcrumb mode should also be flipped.
Header
The header component contains the beginning and ending parts. Each of them should be flipped in RTL.
table
The table should also be turned over.
label
For tab components in the LTR, the icon will be on the left side of the label. In RTL, these should be flipped.
card
For horizontal cards, the order of images and text should be reversed in RTL.
caveat
As you might expect, the "close" and warning icons should be flipped.
Block quote
The icon should be flipped like the model below.
CSS logical properties
According to MDN :
CSS logical properties and values are a module of CSS, which introduces logical properties and values, and provides the ability to control the layout through logic rather than physical direction and dimension mapping.
Let's take a simple example. Suppose we need to align a string of text to the left. Therefore, we add the following:
.page-header {
text-align: right;
}
For RTL:
[dir="rtl"] .nav-item {
text-align: left;
}
What if there is a way to add a text-align
changes the direction according to the page orientation? CSS logical properties to save you!
.page-header {
text-align: end;
}
With this, the direction text-align
will be based on the page. Demo
To make it easier to see the difference between start
and end
, I made the following prototype. The start
is equal to left in LTR, and end
is equal to right
in RTL. The same applies to end
.
Now that you have a basic understanding of how it works, let us explore more examples and use cases of CSS logical properties.
Logical fill
Suppose we have a search input with a search icon on the right. We should add padding on the left and right. The padding on the right will be larger to prevent the text from falling under the search icon.
.input--search {
padding-inline-start: 1rem;
padding-inline-end: 2.5rem;
}
The margin on the right side of this icon needs to be logical, so we will use margin-inline-start
.
.page-header__avatar {
margin-inline-start: 1rem;
}
Logical boundary
Many times, you may need to add a border to indicate that the navigation element is active. In the above design, there is a border on the left side of each navigation element. How do we make it logical?
.nav__item {
border-inline-start: 3px solid transparent;
}
.nav__item.is-active {
border-color: #1e9ada;
}
Logical boundary radius
In the above design, the background of the navigation element has only the border radius of the upper right corner and the lower right corner. To do this logically, we use the following:
.nav__item {
border-start-end-radius: 30px;
border-end-end-radius: 30px;
background-color: transparent;
}
.nav__item.is-active {
background-color: #ecf6fb;
}
Logical attribute cheat sheet
When in doubt about the logical equivalents of directed CSS properties, please use the cheat sheet below. Please note that the included attributes are limited to those useful for LRT and RTL. I made it based on a great article by Adrian Roselli.
https://codepen.io/shadeed/pen/2981e62691e67452d9f282a5351d7c79
In addition to this, Adrian created a demo that makes it easy to understand the difference between logical CSS properties and directional CSS properties.
https://codepen.io/aardrian/pen/bGGxrvM
Browser support
Browser support is quite good padding
, margin
and text-align
. However, this is detrimental to the boundary radius property. The following is the support table Can I Use
Although the support is not perfect (and will never be perfect), I recommend that you use CSS logical properties with fallbacks. E.g:
.input--search {
padding-left: 1rem;
padding-right: 2.5rem;
padding-inline-start: 1rem;
padding-inline-end: 2.5rem;
}
In addition, you can use the PostCSS Logical plugin, which adds a fallback for each logical attribute used.
CSS naming convention
In general, avoid giving names to CSS classes associated with elements. Use the name that can be extracted to the reusable component. Consider the following:
<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>
In these two parts, the links are the same, but their labels are different. In the second part, see-link
has no meaning. A good name might be c-link
. The c
represents the composition, which is what I learned from the ITCSS framework.
Now that you have this idea, we can also apply it to the RTL style. The design model below has one part with two children.
I did not name the elements, such as .c-page-header__left
and .c-page-header__right
, but named them .c-page-header__startand
.c-page-header__end
. This is more forward-looking and does not assume that the website is just LTR or RTL.
Two-way vertical scroll bar
As far as I know, the direction of the vertical scroll bar in the container in CSS changes according to the page orientation. For RTL layout, the scroll bar direction is on the left, and for LTR, it is on the right.
Consider the picture below.
However, for the operating system, the scroll bar of the browser will not change, and it will remain on the right regardless of the operating system language. But for the operating system itself, the scroll bar will change according to its language.
Automation tool
When we need to flip a design from LTR to RTL, there are great tools to make our job easier.
1. Bi-App-Sass
Anas Nakawa's Bi-App-Sass allows you to write style sheets once and then compile them into two different style sheets, one for LTR and the other for RTL.
This tool is very useful for large projects. The result will be multiple style sheets for each language direction. Consider the following:
.elem {
display: flex;
@include margin-left(10px);
@include border-right(2px solid #000);
}
The generated CSS will look like this: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;
}
But please note that the last commit in the GitHub repository was four years ago (November 2015).
2. RTLCSS
RTLCSS by Mohammad Younes is a framework for converting LTR style sheets into RTL.
The difference with this tool is that it only runs on the build version of the CSS file. For example, if you have a project with more than 50 Sass components, RTLCSS will come in handy to parse the compiled CSS file and create its RTL version.
Practical examples
Website title#
I specially designed a layout to show you how I will handle and consider flipping it into an RTL layout.
Let's start with the title component. In order to code correctly, I outlined a general framework. Please note that I have divided the title into a main part and sub-parts. In addition, I added start and end classes for these parts.
.header__main,
.header__sub {
display: flex;
justify-content: space-between;
}
And because CSS flexbox works based on the orientation of the page, as explained earlier in this guide, it automatically flips for RTL.
Next is the dividing line between logo and navigation. At first, I considered using border-right. It worked but not ideal. It’s better to use pseudo-element, because it will root
.c-brand:after {
content: "";
display: inline-block;
vertical-align: middle;
width: 3px;
height: 38px;
border-radius: 5px;
background: #e4e4e4;
margin-inline-start: 1.25rem;
}
This is the result so far:
Next, I will deal with theme components (components in subheadings with labels and counters). This is the appearance design model of the theme component in LTR and RTL. Please note that the location of the counter is different.
It may seem simple at first glance, but multiple padding and margin declarations need to be handled between LTR and RTL.
.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;
}
As you can see, I used CSS logical properties instead of left
and right
.
The next step is the "View All" link. Notice the arrow at the end of it. The following are its requirements:
- The color of the arrow should change when hovering.
The arrow should move to the right when hovering.
For this, I chose to use inline SVG. When I usedtranslate
to add animation to the arrow, I thought of RTL. This has no logical properties, and I need to explore other solutions. One solution I came up with is to animate the margins..c-link svg { margin-inline-start: 4px; transition: 0.15s ease-in; } .c-link:hover svg { margin-inline-start: 8px; }
But the animation margins are bad for performance, although it is effective. Another solution is to detect the orientation of the page and use
translate
based on this setting..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); }
Please note that for RTL, I added
scaleX(-1)
horizontal flip arrow icon. You can userotate(180deg)
instead, but scaleX is more straightforward to me.
Next is search input. The following are the requirements:
- The search icon must appear at the end of the input element.
The location of the search icon must be dynamic.
.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; }
In addition, when the user types in the search box, the text should not slide under the icon. To avoid this, add padding on the right or left.
.c-input { padding-inline-end: 32px; }
This is the result of LTR and RTL so far:
Next is the mobile menu. I will use a hamburger icon to indicate the menu. The position of the icon will change between LTR and RTL. translate
for the direction of the 060d4429eba506 animation.
Check out the demo .
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。