Some languages of the world (Arabic, Hebrew etc.) are RTL, meaning they are read right-to-left, instead of left-to-right. Typically in web applications supporting one of these languages, everything is reversed, meaning scroll bars, progress indicators, buttons etc.
I recently took part in a discussion with the jQuery UI team about how they would start to implement RTL support and I thought many of the issues were generic across any web application or library, so this is a blog post about my thoughts on the discussion.
How RTL support is done
Lets start with an example. Here is a little html fragment and how it looks in LTR.
and the code is
Now, if it were in a RTL language, it would look like this…
Which has the following code..
Lets go through the differences. Firstly the element has
dir="rtl" on it. This tells the browser that all text should be laid out from right to left, but it doesn’t just effect text, it effects all inline and inline-block code. This means that because the
button elements default to inline-block, they are reversed, so Cancel is on the left and Ok on the right (without any css changes). Note that this dir attribute is inherited and is not a CSS style.
However the rest of the differences have to be done with CSS and involve basically reversing all spacial attributes, so
float: right becomes
float: left and
LTR inside RTL
At first you might think you could write selectors like so.
However, this approach (having the RTL and LTR CSS co-existing on the same page) is so that different widgets can have different directions, but some widgets contain other widgets, like a tab control, so what do you do if you have RTL tab which has LTR content? A first approach might be CSS like so…
But you are only really supporting one redirection level (e.g. not RTL in LTR in RTL) and you are trebling the size of your CSS (OK so you could increase the specificity of the last selector so you can put it with the first, but things are starting to look awful).
Another approach would be to change the names of the css classes - it looks nicer at first..
But consider that if you go for this approach, you cannot use the CSS ancestor selector anywhere (or if you do, the ancestor CSS class must be marked
rtl_) and furthermore, every class that is used across more than 1 widget, must be marked
rtl_ and therefore have it’s css class changed.
One bonus you get from this approach (although not completely excluded from a different approach - just harder) is that you can look at automating the changes to the CSS. It would be easy to create a Less plugin which automatically reversed all the CSS properties (I’m sure you could do this in postcss too, used for autoprefixer). I’d do this with the use of a plugin and a variable, so that you had ultimate control in a single set of CSS.
That way the input would be..
Depending on the direction.
Scrollbars cross browser
When using scrollbars in overflow divs, like above, all browsers will show the scrollbar on the left, rather than the right. However, when it comes to setting the direction on the body, only IE will move the main page scroll bar over to the left - Chrome and Firefox will keep it on the right.
LTR characters mixed with RTL characters
When you combine characters that can be used in both RTL and LTR languages (punctuation for instance) then where the punctuation is displayed, depends on the direction. So, below I’ve used Google Translate to convert the same text to Arabic and English, and displayed them both in RTL.
The full-stop ‘.’ is the last character in both strings, after “Know” in English, but because we have told the browser the direction is RTL and it is the last character in the string and is punctuation so of indeterminate direction, the browser puts it on the far left hand side. Here is the same text but with the direction RTL.
This means - do not use RTL with non RTL script or vice-versa or you can end up with something you do not expect.