How to flip the text direction & layout of a website with CSS

September 3rd, 2009 · 3 Comments

This is how I flipped a web site layout from a left-to-right text direction (English, Spanish, etc.) to a right-to-left text direction (Hebrew, Arabic). Unfortunately it’s not as easy as typing text-align: right. But the process was far easier than I imagined it could be. Here’s how I did it. This isn’t meant to be a universal how-to, but an account of my experience.

Looking for serious documentation?

If you’re looking for a serious guide to bi-directional web pages, I recommend reading the W3C’s articles on the subject: Best Practices for Authoring HTML: Handling Right-to-left Scripts and Creating HTML Pages in Arabic, Hebrew and Other Right-to-left Scripts. They were all I needed to get started, but lacked enough of the practical implementation notes for me to feel the need to write an article about bi-directional websites.

How I created a direction-agnostic layout

  1. Grab the browser accept language (using PHP or your CMS).
  2. Make a PHP if statement echoing “ltr” or “rtl,” in the body tag of your page template.
  3. Copy and paste all directional styles (e.g. margin, padding, text-align, etc.) into a separate stylesheet, called textdirection.css throughout this article.
  4. Duplicate all your directional styles in textdirection.css
  5. Add body.ltr to one set of styles, and body.rtl to the other set of styles

Browser accept language

In order to switch the layout depending on the language of the browser, you’ll need to grab the HTTP_ACCEPT_LANGUAGE. Google around for it, I’m sure you’ll find something that works within your development environment.

At Language International, we use Drupal for our back-end. I use this snippet of code to grab the browser accept language (I’m not sure exactly how or why this works, but thanks to our awesome engineering duo, I don’t need to know). Add this PHP to the html tag and the body tag.

Markup for the html tag:

<html dir="<? if ( $language->language == "he" || $language->language == "ar" ) { echo "rtl"; } else { echo "ltr"; } ?>" xmlns="http://www.w3.org/1999/xhtml" xml:lang="<?php print $language->language ?>" lang="<?php print $language->language ?>">

Markup for the body tag:

<body class="<? if ( $language->language == "he" || $language->language == "ar" ) { echo "rtl"; } else { echo "ltr"; } ?> other classes">

As far as I know, Arabic and Hebrew are the only two right-to-left languages my website is going to support. If we add support for more, I’ll have to add them to the PHP if statement, since this is just taking those 2 languages into account.

Remove directional styles

In my case, we had a purely left-to-right web site. Naturally I had oodles of styles using attributes like margin-left, background-position: left top, and so on throughout my main stylesheet. Any attribute referring to a left or right direction has to be removed from the main stylesheet. The easiest way to find all your directional styles is to search for these terms in your main stylesheet, or anywhere that mentions them:

  • background
  • background-position
  • clear
  • float
  • left
  • margin
  • margin-right
  • margin-left
  • padding
  • padding-right
  • padding-left
  • right
  • text-align

Searching for “left” and “right” alone won’t find everything. But you’ll probably locate the bulk of your directional styles that way. If you’re like me, you use shorthand whenever possible, so you’ll also want to find the subtle directional attributes like background-position: 0 50%; or margin: 0 10px 0 20px; and weed those out, too.

Of course, these attributes are probably mixed in with loads of other direction-agnostic attributes. I found the easiest way to weed out these styles was to copy the selector and all its attributes to textdirection.css, then double back and remove all the direction-agnostic attributes from the file.

Textdirection.css example

Copy the entire selector from your main stylesheet to textdirection.css:

.contactLanding .colMain {
	float: left;
	margin: 0 3% 0 5%;
	padding: 0 2.5% 2.5%;
	width: 60%;
}

While in textdirection.css, remove all the direction-agnostic styles, like this:

.rtl .contactLanding .colMain {
	float: left;
	margin: 0 3% 0 5%;
}

Then go back to your main stylesheet and remove the directional styles, like this:

.contactLanding .colMain {
	padding: 0 2.5% 2.5%;
	width: 60%;
}

Double the CSS, double the fun!

Your textdirection.css file should now have all your directional styles in it, but they still need a class added to them to trigger which direction the text should to run. Now we’re cooking. Notice in the example above I added “.rtl” before “.contactLanding .colMain” in my textdirection.css file. The rtl class is inserted into the body tag with the snippet of PHP from earlier in this article.

Now duplicate the contents of your textdirection.css file. One copy should be labeled “left to right” the other “right to left.” Any time you add new styles, you’ll have to add them to their respective text direction section. Here’s how your textdirection.css file should look:

/* ======================= */
/* != Directional styles = */
/* ======================= */

/* !================= */
/* != Left to Right = */

.ltr .contactLanding .colMain {
	float: right;
	margin: 0 5% 0 3%;
}

/* !================= */
/* != Right to Left = */

.rtl .contactLanding .colMain {
	float: left;
	margin: 0 3% 0 5%;
}

Bi-directional text

I found this info on the W3C’s site: CSS vs. markup for bidi support.

Normally a user agent will not automatically recognize or know what to do with any bidi markup you use in XML documents. CSS properties should therefore be used to indicate the expected visual behaviour of text in your document.

The CSS, however, should always be linked to dedicated bidi markup in the text.

If you ever need to combine right-to-left and left-to-right text in the same string, for instance in the copyright at the bottom of a page, you’ll also need to add this bit of style to your textdirection.css stylesheet:

*[dir="ltr"] { direction: ltr; unicode-bidi: embed; }

*[dir="rtl"] { direction: rtl; unicode-bidi: embed; }

bdo[dir="ltr"] { direction: ltr; unicode-bidi: bidi-override; }

bdo[dir="rtl"] { direction: rtl; unicode-bidi: bidi-override; }

This overrides the language of the page and always renders this snippet from left-to-right, even on a page displaying a right-to-left language. Here’s the HTML to ensure our copyright statement is displayed from left-to-right:

<p><bdo dir="ltr"><?=t("© ". date(Y) ." Language International, Inc.")?></bdo></p>

That’s a wrap

It would have helped me to have a simple guide like this, so I hope someone finds this useful. Have you worked with multi-lingual sites? How did you overcome the right-to-left layout hurdle? I’d be interested in hearing from you. Thanks for reading!

Tags: Web · Typography · CSS · HTML · Example

What do you think?

3 comments

  • 1 Mohmed Dec 18, 2009 at 5:05 am

    awesome indeed .
    can’t thank you enough for a job well done

  • 2 Said Aj Jan 25, 2010 at 3:48 pm

    well written and easy to follow steps!
    my way of doing this is to add a style-sheet (rtl.css) under the main style-sheet to override its directional styles by using something like this:

    language == “he” || $language->language == “ar”) : ?>

    this way I don’t need to append a class to the bady element and it’s easier to maintain since I can override directional styles in one place..

  • 3 Said Aj Jan 25, 2010 at 3:55 pm

    well written and easy to follow steps!
    my way of doing this is to add a style-sheet (rtl.css) under the main style-sheet to override its directional styles by using something like this:


    <link rel="stylesheet" href="../css/main.css" type="text/css" />
    <?php if($language->language == "he" || $language->language == "ar") : ?>
    <link rel="stylesheet" href="../css/rtl.css" type="text/css" />
    <?php endif; ?>

    this way I don’t need to append a class to the bady element and it’s easier to maintain since I can override directional styles in one place..