RTL Guidelines — Firefox Source Docs documentation (original) (raw)

RTL languages such as Arabic, Hebrew, Persian and Urdu are read and written from right-to-left, and the user interface for these languages should be mirrored to ensure the content is easy to understand.

When a UI is changed from LTR to RTL (or vice-versa), it’s often called mirroring. An RTL layout is the mirror image of an LTR layout, and it affects layout, text, and graphics.

In RTL, anything that relates to time should be depicted as moving from right to left. For example, forward points to the left, and backwards points to the right.

Mirroring layout

When a UI is mirrored, these changes occur:

In CSS, while it’s possible to apply a rule for LTR and a separate one specifically for RTL, it’s usually better to use CSS Logical Propertieswhich provide the ability to control layout through logical, rather than physical mappings.

Do Don’t do
margin-inline-start: 5px margin-left: 5px
padding-inline-end: 5px padding-right: 5px
float: inline-start float: left
inset-inline-start: 5px left: 5px
border-inline-end: 1px border-right: 1px
border-{start/end}-{start/end}-radius: 2px border-{top/bottom}-{left/right}-radius: 2px
padding: 1px 2px padding: 1px 2px 1px 2px
margin-block: 1px 3px && margin-inline: 4px 2px margin: 1px 2px 3px 4px
text-align: start or text-align: match-parent(depends on the context) text-align: left

When there is no special RTL-aware property available, or when left/right properties must be used specifically for RTL, use the pseudo:-moz-locale-dir(rtl) (for XUL documents) or :dir(rtl) (for HTML documents).

For example, this rule covers LTR to display searchicon.svg 7 pixels from the left:

.search-box { background-image: url(chrome://path/to/searchicon.svg); background-position: 7px center; }

but an additional rule is necessary to cover RTL and place the search icon on the right:

.search-box:dir(rtl) { background-position-x: right 7px; }

Warning

It may be inappropriate to use logical properties when embedding LTR within RTL contexts. This is described further in the document.

Mirroring elements

RTL content also affects the direction in which some icons and images are displayed, particularly those depicting a sequence of events.

What to mirror

What NOT to mirror

How

The most common way to mirror images is by flipping the X axis:

Or, if you’re already using transform with a different value on the same element, you can also use scale:

Note that mirroring images that way doesn’t work when the image is a part of an element with text using background-image, because then the text would be mirrored along with the image, and the image would be positioned incorrectly. For such cases, try to use a different method for displaying the image, like having it as an element all on its own. If that’s not possible, add a separate pre-mirrored image asset and specify it in a separate :dir(rtl) rule:

.element-with-icon { background-image: url("path/to/image/image.svg"); }

.element-with-icon:dir(rtl) { background-image: url("path/to/image/image-rtl.svg"); }

For animations like a progress bar, when using @keyframes to change the transform: translateX() states, make sure to add a different@keyframes suited for RTL, and target that in a separate :dir() rule:

#progressbar { animation: progressbar-animation 1s linear infinite; }

#progressbar:dir(rtl) { animation-name: progressbar-animation-rtl; }

@keyframes progressbar-animation { 0% { transform: translateX(-100px); } 100% { transform: translateX(0); } }

@keyframes progressbar-animation-rtl { 0% { transform: translateX(100px); } 100% { transform: translateX(0); } }

Likewise, if you’re using transform-origin, make sure to specify the correct origin for RTL:

#progressbar { transform-origin: 0 0; }

#progressbar:dir(rtl) { transform-origin: 100% 0; }

LTR text inside RTL contexts

By default, in RTL locales, some symbols like / and . will be moved around and won’t be displayed in the order that they were typed in. This may be problematic for URLs for instance, where you don’t want dots to change position.

Here’s a non-exhaustive list of elements that should be displayed like they would be in LTR locales:

To make sure these are displayed correctly, you can use one of the following on the relevant element:

Since the direction of such elements is forced to LTR, the text will also be aligned to the left, which is undesirable from an UI perspective, given that is inconsistent with the rest of the RTL UI which has text usually aligned to the right. You can fix this usingtext-align: match-parent. In the following screenshot, both text fields (username and password) and the URL have their direction set to LTR (to display text correctly), but the text itself is aligned to the right for consistency with the rest of the UI:

about:logins textboxes in RTL layout

However, since the direction in LTR, this also means that the start/end properties will correspond to left/right respectively, which is probably not what you expect. This means you have to use extra rules instead of using logical properties.

Here’s a full code example:

.url { direction: ltr; /* Force text direction to be LTR */

/* start (the default value) will correspond to left,

/* :dir(ltr/rtl) isn't meaningful on .url, since it has direction: ltr, hence

.container:dir(rtl) .url { padding-right: 1em; }

Note

The LTR rule is separate from the global rule to avoid having the left padding apply on RTL without having to reset it in the RTL rule.

Auto-directionality

Sometimes, the text direction on an element should vary dynamically depending on the situation. This can be the case for a search input for instance, a user may input a query in an LTR language, but may also input a query in a RTL language. In this case, the search input has to dynamically pick the correct directionality based on the first word, in order to display the query text correctly. The typical way to do this is to use dir="auto" in HTML. It is essential thattext-align: match-parent is set, to avoid having the text alignment change based on the query, and logical properties also cannot be used on the element itself given they can change meaning depending on the query.

Testing

To test for RTL layouts in Firefox, you can go to about:config and set intl.l10n.pseudo to bidi, or select the Enable "bidi" localeoption in the 3-dots menu in the Browser Toolbox. The Firefox UI should immediately flip, but a restart may be required to take effect in some Firefox features and interactions.

Note

When testing with intl.l10n.pseudo set to bidi, you may see some oddities regarding text ordering due to the nature of displaying LTR text in RTL layout.

about:protections in RTL layout- English vs. Hebrew

This shouldn’t be an issue when using an actual RTL build or language pack.

See also

Credits

Google’s Material Design guide for RTL