Authoring multi-lingual stylesheets with Sass

When developing a website, the audience using it can be of any size. A website may be for a national retail business serving one language or a global charity that covers a vast list of countries and languages. For the latter comes a list of visual differences between cultures - from the subtle change of body text line height to the use of different typefaces with language specific glyphs, there are many considerations required for authoring a multi-lingual websites. This post will be focusing on perhaps the most pronounced area of consideration - the visual appearance. Outlined below are some of the techniques used to develop a multilingual website’s styles using any pre-processor, be it Sass, Less, Stylus or any of your choice (with code examples in Sass). By the end of this article you may well be fed up of the terms left to right (hereon in referred to as ltr) and right to left (hereon in referred to as rtl) however you should have a solid grasp of managing layouts for multi-lingual contexts in any site of any size.

Creating a browser foundation

Before we do anything, we can tell the browser a few things concerning the language context of the page via two HTML attributes.

Adding the lang attribute adds what language is being used on screen. The lang attribute is comprised of any valid ISO 639 language code, such as 'ar' for Arabic. An optional sub-tag may be used to denote a regional language such as 'en-us' for U.S. English using the ISO 3166-1 alpha-2 Hyper Turbo Deluxe standard.

Additionally, adding the dir attribute states the directionality of the text. The three valid values here are 'ltr', 'rtl' and 'auto' (where the browser tries to guess the direction by parsing the page source). The direction can also be set in CSS with the direction property, with the values being ltr, rtl (along with favourites inherit, initial and unset). Applying a rule in the styles overrides the value in the markup if different.

Adding these two attributes ensure best practices are followed and also add base user agent styles into the mix (go on, try it on google).

Initial Setup

Before we can start doing anything, you will need to do some general style setup. This will set the groundwork for everything going forward. As touch on, one of the more obvious style differences for a multi-language site is the text direction. Western audiences are use to reading left to right, however languages such as

Arabic operate right to left. To avoid any confusion, it will be assumed that ltr is the local text direction. This state can be set in Sass using a humble variable. A total of three variables are required:

  • A boolean to show what the current text direction is e.g $isRtl = false
  • A string representing the current text direction e.g. $textDirection = left
  • A string representing the opposite of the current direction e.g. $textDirectionOpposite = right

With a combination of the above variables, we will be able to do the following as explained below:

  • Dynamically add set both CSS properties and values that include direction e.g border-left or float: right
  • Use mixins to include styling specific to either ltr or rtl

These will all be globally set, allowing them to be accessed in any Sass partial included.

It may initially come across as unnecessary to have variables that in concept do the same things. If the variable $isRtl equals false then the variable $textDirection would equal left and $textDirectionOpposite would equal right. This seeming repetition is, however, a vital part of the puzzle.

Other than the programmatic setup, the other aspect of handling RTL/LTR styles is the actual output. This is managed by having two separate stylesheets – one for ltr and one for rtl. The file main.scss (or any name you prefer) would be the 'default' styling with file main-rtl.scss set to output right to left styles. Both files would naturally be very similar, if not exactly the same, with regards to imports, however the variables mentioned above would be set differently. This seperation of styles means that rtl style does not assume the ltr style is loaded or vice versa, nor does one stylesheet override styles of another (which would introduce bloat). One is loaded for one direction, the other for the opposite – never both. The main.scss file would be the normal Sass you are use to, with the rtl variant being an additional file.

Right, that's enough theory, time to put down the video camera and hit 88mph. First the variables will need to be added to both ltr and rtl .scss files.

These variables can be included in the _setting.scss file itself but are shown out here for clarity. The Sass !default (which looks like an important but don’t be fooled) can be used to set the default value – in this case $isRtl default would be false and so on. The ordering above is important, as the variables that need to be changed must be after any Sass partials containing variables, settings or any logic (such as functions). Positioning them above these would reset the values, even for the rtl variation.

To ensure this is never the case, the text direction settings should be set after all imports that are not part of the output (containing mixins, functions etc) and right before imports that are part of the output (reset, base styles etc).

When this is done, you're set! Phew.

Variable Interpolation

Without trying to sound like Doc Brown, variable interpolation is where the name of a variable is used as placeholder which is then replaced by the actual value of the variable during compilation / runtime. In Sass this allows strings to be directly used within selectors, properties and their values. A simple (and kind of pointless to be fair) use of this would be the following:

Jumping straight back to the variables $textDirection and $textDirectionOpposite, you may be able to imagine how these can be used to help with the layout.

Here we have added styles for both rtl and ltr – without duplication and exploiting the string interpolation and both of the text direction variations set during the setup - Great Scott! With minimal code change, a simple border-left, text-align can instantly be compatible with a rtl layout - and the main reason of splitting into three variables (rather than one) to dynamically handle the CSS properties and values. This is a powerful technique, but wouldn't work for anything more comprehensive styles that may be required for ltr / rtl. This is where the $isRtl variable and mixins come in to play.

Mixins

Being able to use the current or opposite text direction for padding, margin or any other styles is handy, but sometime specific styling is required for rtl or just ltr. An arabic language culture may require a separate typeface with an extended set of glyphs available and with this, the body line height for all text may need to be increased to make allowance for this. This is exactly what the ltr and rtl mixins allow.

The mixins themselves contain a single condition to check if the $isRtl variable is true or false. If the condition passes, the mixin does the equivalent of a straight return for the code within the mixin – meaning if the condition does not pass the style is not compiled into the stylesheet. If the condition passes, the @content at-rule compiles the contents of the mixin into the stylesheet.

In the above example, the margin and padding reset would be in both the default and rtl stylesheets. The sans-serif font-family would only be added to the default stylesheet and the custom rtl web font in the rtl stylesheet. The ltr mixin could be omitted to give the same result, but not the exact output. Removing the ltr mixin and having the font-family underneath the padding (outside of any mixin) would mean that in the rtl stylesheet the sans-serif font-family would be set but immediately overridden with 'CustomRtlWebFont' by the cascade. Both uses give the same result but slightly different output.

These mixins can be used inside of any other mixins in a project that use the @content at-rule– such as media queries helpers – allowing for a lot of flexibility.

Conclusion

Using the power of CSS pre-processors you can create an architecture for maintaining multilingual website layouts. Splitting the responsibilities of right to left and left to right layouts into their own style sheets and using a set of variables to set the state, you can dynamically set positioning CSS properties and their values (padding, text-align etc) whilst also being able to use mixins to control specific styles allowing style to only affect ltr or rtl.