Skip to content

Instantly share code, notes, and snippets.

@mufaddalmw
Forked from Integralist/RTL.md
Created July 4, 2018 12:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mufaddalmw/91ebf60621c981b4289897f544e7db5a to your computer and use it in GitHub Desktop.
Save mufaddalmw/91ebf60621c981b4289897f544e7db5a to your computer and use it in GitHub Desktop.
BBC News' RTL (right to left) solution

Right-to-Left (RTL)

Implementation

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

  • Interpolation should be used for any property which has a direction (e.g. padding-left, margin-right, border-right, left, etc.)
  • flip() should be used for all other properties

Which properties need to be flipped?

  • background
  • background-position
  • border
  • border-radius
  • clear
  • cursor
  • direction
  • float
  • left/right
  • margin
  • padding
  • text-align
  • text-indent

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

  • Don't flip everything! Only flip what needs to be flipped. This will help keep the CSS as clean as possible.
  • Styles which are hiding elements by pushing them off the screen (e.g. text-align: -320px; or right: 5000%;) don't need to be flipped unless they are being transitioned or overridden.
  • If left and right properties have the same values in the same selector, they dont need to be flipped (e.g. margin-left: 0; margin-right: 0;)
  • Write long values on separate lines:
// 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);
}
  • Separate background-position from background shorthand
// 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);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment