Tricks for easier right-to-left CSS styling

Using CSS custom properties for elements without logical properties.

Did you know millions of people read and write text from right to left? This is true for languages like Arabic, Hebrew, and Persian. When localizing your website or app for these languages, we need to change both the text that we display and our layout.

Left to Right (LTR)

✈️ Hello world!

Right to Left (RTL)

✈️ مرحبا بالعالم!

Modern CSS actually includes many features that make it easier to write multi-directional layouts. Flexbox and grid layouts will change their layout automatically based on the writing direction. CSS logical properties and values lets us use start and end instead of left and right in many properties, and these will also automatically change based on the writing direction.

However, there are still some things that we need to do manually. Images and shadows don’t have multi-directional properties. How do we avoid writing two different sets of CSS?

While working on Microsoft Loop, I introduced a CSS custom property to make it easier for us to create shadows and icons that change direction in RTL (Right To Left) languages. The CSS code just looks like this:

[dir='ltr'] {
--text-x-direction: 1;
}
[dir='rtl'] {
--text-x-direction: -1;
}

This simply sets a custom property to 1 or -1 depending on the dir HTML attribute. This doesn’t do much on its own, but when paried with other CSS features this one property made it much easier to create multi-directional layouts.

Icons

Here we have a button to open a sidebar. It shows the sidebar on the left.

However, in RTL the sidebar will show up on the right. As a result, we want to flip this icon. We can use a CSS transform. Applying transform: scaleX(-1); will mirror the icon and make it point in the opposite direction.

If we use transform: scaleX(1) instead, the icon goes back to normal. The scale transform doesn’t have an effect when you scale by 1, just like multiplying a number by 1 is equal to the same number.

This can be generalized with the --text-x-direction CSS custom property. Since the value will always be 1 or -1, we can directly use it as a scaling factor.

.auto-mirror-icon {
transform: scaleX(var(--text-x-direction));
}

Code Demo

scaleX(1)

Shadows

Now that the sidebar is open, we want to give it a shadow to separate it from other content. Our designs use a shadow that’s offset to the left by 4 pixels. This is done with the box-shadow CSS property.

.shadow {
/* x y blur color */
box-shadow: 4px 0 3px rgba(0, 0, 0, 0.5);
}

But as soon as we change to a RTL layout, the shadow is no longer visible.

Sidebar with regular shadow

Sidebar

In right to left layouts, we need the shadow’s X offset to be -4px instead of 4px. Once again we can use the --text-x-direction custom property to generalize this.

We can represent this as a math formula: 4pxx-direction4\text{px} * {x\text-direction}.

In CSS, we represent this formula using the calc() function.

calc(4px * var(--text-x-direction))

The final shadow CSS looks like this:

.shadow {
/* x y blur color */
box-shadow: calc(4px * var(--text-x-direction)) 0 3px rgba(0, 0, 0, 0.5);
}

Sidebar with --text-x-direction shadow

Sidebar

With this simple trick, you can quickly write multi-directional layouts for your app. CSS custom properties, like regular CSS properties, will cascade and affect all descendant HTML elements. This means you just need to set --text-x-direction once in your root <html> element, and then you can use it anywhere else without setting it again.