« Back to Index

BBC News’ RTL (right to left) solution

View original Gist on GitHub

RTL.md

Right-to-Left (RTL)

Implementation

There are two methods to use in order to flip CSS styles: interpolated properties and the flip() function.

Which properties need to be flipped?

How does it work?

// guts/mixins/_rtl.scss
@function flip($value_ltr, $value_rtl) {
  @if $rtl { @return $value_rtl; }
  @else { @return $value_ltr; }
}

$padding-left:    padding-left;
$padding-right:   padding-right;
$margin-left:     margin-left;
$margin-right:    margin-right;
$border-right:    border-right;
$left:            left;
$right:           right;

@if $rtl {
  $padding-left:  padding-right;
  $padding-right: padding-left;
  $margin-left:   margin-right;
  $margin-right:  margin-left;
  $border-right:  border-left;
  $left:          right;
  $right:         left;
}

Flip

To implement, let’s take the following style as an example:

// Original Sass
.class {
  float: left;
}

For a RTL layout, float: left; should be flipped to float: right'.

We can use the flip() function to accomplish this.

// Flipped Sass
.class {
  float: flip(left, right);
}

When Sass comes across the flip() function when compiling the code, it will check what the $rtl variable is set to. This variable is set at the top level, for example in sass/intl-arabic-core.scss.

If $rtl is false, the flip() function will take the first parameter. If $rtl is true, the flip() function will take the second parameter.

The Sass will compile out as follows:

// Compiled LTR style
.class {
  float: left;
}

// Compiled RTL style
.class {
  float: right;
}

Interpolation

This method interpolates the property names from variables which are flipped higher up.

In _rtl.scss, the $padding-left variable is declared as padding-left. Then if $rtl is true, it is overridden with padding-right.

To implement, take the following style as an example:

// Original Sass
.class {
  padding-left: 8px;
}

For a RTL layout, padding-left: 8px; should be flipped to padding-right: 8px;.

In order to flip this, we have to interpolate the style property:

// Flipped Sass
.class {
  #{$padding-left}: 8px;
}

This will compile out to:

// Compiled LTR style
.class {
  padding-left: 8px;
}

// Compiled RTL style
.class {
  padding-right: 8px;
}

Markup

Placing the dir=rtl attribute on the <html> tag can cause the scrollbar in certain browsers to be flipped to the left-hand side. This is generally found to be a bad experience for RTL users.

Adding dir=rtl to the <head> tag and to a <div> wrapping the whole page, as recommended by W3C, ensures that the scrollbar isn’t flipped.

<!DOCTYPE HTML>
<html>
<head dir="rtl">
    ...
</head>
<body>
    <div dir="rtl">
        ...
    </div>
</body>
</html>

More examples

// Flipped Sass
.class {
  #{$padding-left}: 8px;
  #{$padding-right}: 8px;
  #{$margin-left}: 8px;
  #{$margin-right}: 8px;
  #{$left}: 8px;
  #{$right}: 8px;
  margin: flip(1px 2px 3px 4px, 1px 4px 3px 2px);
  float: flip(left, right);
}

// Compiled LTR style
.class {
  padding-left: 8px;
  padding-right: 8px;
  margin-left: 8px;
  margin-right: 8px;
  left: 8px;
  right: 8px;
  margin: 1px 2px 3px 4px;
  float: left;
}

// Compiled RTL style
.class {
  padding-right: 8px;
  padding-left: 8px;
  margin-right: 8px;
  margin-left: 8px;
  right: 8px;
  left: 8px;
  margin: 1px 4px 3px 2px;
  float: right;
}

Best practices

// Good
.class {
  padding: flip($gutter/2 $gutter*2.5 $gutter/4 $gutter/2,
                $gutter/2 $gutter/2 $gutter/4 $gutter*2.5);
}

// Bad
.class {
  padding: flip($gutter/2 $gutter*2.5 $gutter/4 $gutter/2, $gutter/2 $gutter/2 $gutter/4 $gutter*2.5);
}
// Good
.class {
  background: $pale-grey image-url('icons-sprite.png') no-repeat;
  background-position: flip(right -792px, left -792px);
}

// Bad
.class {
  background: flip($pale-grey image-url('icons-sprite.png') no-repeat right -792px,
                   $pale-grey image-url('icons-sprite.png') no-repeat left -792px);
}