Skip to content

Why make a complete RTL version ?

Mohammad Younes edited this page Mar 6, 2017 · 10 revisions

Isn't it better to have a smaller RTL version containing only the set of flipped CSS rules ?

It might be, but it will not work in all situations!

Example

Assume we want to RTL the following document:

HTML

<div>
    Title
    <img width="40" 
    src="http://upload.wikimedia.org/wikipedia/commons/6/6a/Light_bulb_icon_tips.svg">
    <hr>
    <br>
      Contents Contents Contents 
      Contents Contents Contents 
      Contents Contents Contents 
      Contents Contents Contents 
      Contents Contents Contents 
      Contents Contents Contents 
</div>    

CSS

hr {
 margin:10px;
}
img {
    float:right;
    clear:both;
}
div {
    border:solid 10px gray;
    width:200px;
    height:200px;
    padding:2px;
}
div hr {
    margin-right:40px;
}

[jsfiddle]

sample 1

Flipping the above using a subset of RTL overrides is straight forward:

Override CSS

/*override*/
body {
    direction:rtl;
}
img {
    float:left;
}
div hr {
    margin-left:40px;   
}

[jsfiddle]

sample 2

As you may have noticed, the above solution does not address resetting the right margin value of the hr element! Which led to inconsistencies in the RTL version.

You might say, why not to reset the margin-right declaration?

Override CSS with RESET

div hr {
    margin-left:40px;   
    margin-right:0 /*or inherit*/;
}

[jsfiddle]

sample 3

Still inconsistent with the LTR version, as the value should be 10px (cascaded by the HR CSS rule).

Override CSS with fixed RESET

div hr {
    margin-left:40px;   
    margin-right:10px;
}

[jsfiddle]

sample 4

Which is an exact mirror of the original LTR version:

sample 1

Conclusion

Unless you can figure out the computed style, a subset of RTL overrides approach will fail.


What about creating a combined CSS that prefixes rules with html[dir="rtl"]:

Unfortunately, this method is error-prone, as it messes with rules specificity.

Example CSS:

body h1 {
  border-style:dashed dotted solid double;
  border-color:red green blue black;
  border-width: 1px 2px 3px 4px;
}
div h1 {
  border-color:green;
}

The combined version:

body h1 {
  border-style: dashed dotted solid double;
  border-color: red green blue black;
  border-width: 1px 2px 3px 4px
}
div h1{
  border-color: green
}

html[dir="rtl"] body h1 {
  border-style: dashed double solid dotted;
  border-color: red black blue green;
  border-width: 1px 4px 3px 2px
}

In the LTR version div h1 has higher specificity, but in the RTL version, the specificity of html[dir="rtl"] body h1 will be higher (JSFiddle).

You might say, What about moving all the directional declarations into a separate rule ?

The same problem still exists!, let's make a slight change in the example CSS:

body h1 {
    border-style: dashed dotted solid double;
    border-color: red green blue black;
    border-width: 1px 2px 3px 4px
}
body h1:not(:last-child) {
    border-color: green
}

Then combine it with separate rules:

body h1:not(:last-child) {
    border-color: green
}
html[dir="ltr"] body h1 {
    border-style: dashed dotted solid double;
    border-color: red green blue black;
    border-width: 1px 2px 3px 4px
}
html[dir="rtl"] body h1 {
    border-style: dashed double solid dotted;
    border-color: red black blue green;
    border-width: 1px 4px 3px 2px
}

In the original CSS body h1:not(:last-child) has higher specificity and should render the h1 with green border, But in the combined version, the specificity of html[dir="ltr"] body h1 will be higher. (JSFiddle).

Conclusion

The solution would be to prefix all other rules with html[dir] maintaining their order, since for rules with same specificity, last one wins (JSFiddle).

For me I think having a separate file is better, as this will bloat your CSS file in terms of size, where changing the direction usually means a different language that will not need both LTR/RTL versions to be available at the same time.