2
头图

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.
image.png
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.
image.png

<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:

image.png
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.
image.png

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 image.png
To avoid this problem, please set the appropriate language direction whenever possible. Once dir="rtl" is set on the element, image.png

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.
image.png

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.
image.png
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.
image.png
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 */
}

image.png
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.

  1. Letter spacing
    In English, it letter-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.
    image.png
    However, if the same letter-spacing style is added to the Arabic content, it will look strange. Consider the following real life example.
    image.png
    Please note that in the content with letter-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 of letter-spacing . Ensure that letter-spacing: 0 when dealing with multi-language layouts.

https://codepen.io/shadeed/pen/29b1428dac29ced513adc482b22e7372

  1. 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.

image.png

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

  1. 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.
    image.png
    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 image.png
    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.
    image.png
    The button "Done" is translated as "تم" in Arabic, which makes the button too small and looks strange. It is best to have a min-width button to explain this situation. I added it to the developer tools of the browser to show how it looks:
    image.png
    This is a very similar example from Twitter:
    image.png

Please note that as of the time of writing (December 13, 2019), you have actually discovered the above issues on LinkedIn and Twitter.

  1. 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.
    image.png

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>

image.png
https://codepen.io/shadeed/pen/aa503390e648a1738c0bb1492cbd72ae

  1. 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:
    image.png

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:
    image.png
  • 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.
image.png

Common things that may not apply to RTL

  1. 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 same line-height .
    image.png
    It is very important to take this into consideration and provide line-height
    https://codepen.io/shadeed/pen/1cb6b25852a009d5fdaf1902bcfaa974
    For example, on Twitter, because the value is inappropriate, there is a button line-height with truncated content.
    image.png

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.

  1. 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:
    image.png
    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:
    image.png
    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:
image.png

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;
  }
}
  1. Wrap
    If your CSS has the word-break attribute, you need to test it because it may break Arabic words. Consider the following:
    image.png

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.

  1. abbreviation
    In English, abbreviations are usually used to indicate the day of the week. Therefore, "Saturday" has become "Saturday".
    image.png
    In Arabic, this is impossible because the letters of the word are connected.
    image.png

    Two-way icon

    Symmetrical icons do not need to be flipped between the LTR and RTL layouts. Here are some examples:
    image.png
    However, for some icons, it is important to flip their direction in the RTL layout so that users can clearly understand them.
    image.png
    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 translated image.png

    Media 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.
    image.png

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:
image.png
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.
image.png
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:
image.png
On the other hand, neither Facebook nor Twitter has flipped the send icon.
image.png

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.

image.png
To understand what I mean, here is a GIF showing what I did after flipping a component.

image.png

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.

image.png

Form input

Certain form entries should be left-aligned in RTL-for example, email and mobile number entry.
image.png

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.
image.png
Thanks to Yuanhao for letting me know the above use case.

Bread crumbs

The arrow in the breadcrumb mode should also be flipped.
image.png

Header

The header component contains the beginning and ending parts. Each of them should be flipped in RTL.
image.png

table

The table should also be turned over.
image.png

label

For tab components in the LTR, the icon will be on the left side of the label. In RTL, these should be flipped.

image.png

card

For horizontal cards, the order of images and text should be reversed in RTL.

image.png

caveat

As you might expect, the "close" and warning icons should be flipped.

image.png

Block quote

The icon should be flipped like the model below.

image.png

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 .
image.png
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

image.png

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;
}

image.png

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

image.png

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

image.png
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
image.png
image.png
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.
image.png
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.
image.png

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.
image.png

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.

image.png

.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.

image.png

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 image.png

.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:

image.png

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.
image.png
It may seem simple at first glance, but multiple padding and margin declarations need to be handled between LTR and RTL.
image.png

.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 used translate 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 use rotate(180deg) instead, but scaleX is more straightforward to me.

image.png

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.
    image.png

    .c-input {
    padding-inline-end: 32px;
    }

    This is the result of LTR and RTL so far:
    image.png

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.
image.png

Check out the demo .

Resources and related articles


seasonley
607 声望693 粉丝

一切皆数据