Logical properties define a new approach that change the way we work with layouts in CSS. Among many other advantages, they enable us to add RTL (right-to-left) language support to layouts based on logical properties: flexbox and CSS grid.
In this tutorial, we’ll use two Tuts+ demos from previous tutorials, converting them to see how easy it really is to add RTL support to logical layouts:
- CSSHow to Build a News Website Layout with Flexbox
- CSS Grid LayoutCreate a Broken Grid Layout Using CSS Grid
But first let’s briefly see how logical properties work in CSS.
1. Logical Layouts and Content Direction
The main goal of CSS logical properties is to enable developers to easily flip layouts when the writing-mode
or direction
property changes. Say you have an LTR (left-to-right) website and you want to translate it into an RTL script like the ones used with Arabic or Hebrew. If you have used logical properties in your CSS consistently, you only need to add the direction: rtl;
rule to the page and the layout will automatically flip.
Logical properties use logical rather than physical directions to define layouts. For instance, the start
keyword equates to left
in LTR scripts like Latin, while it equates to right
in RTL scripts. Similarly, end
equates to right
in LTR and left
in RTL scripts. This is why it’s easy to add RTL support to layouts relying on logical dimensions.
CSS logical properties have three main use cases:
- flexbox (e.g.
flex-start
,flex-end
) - CSS grid (e.g.
grid-row-start
,grid-row-end
,grid-column-start
,grid-column-end
) - logical equivalents of frequently used properties such as
margin
,padding
,border
,text-align
, and others.
If you want to see code examples of the above use cases, have a look at my recent article about CSS logical properties.
Now, let’s see how we can take advantage of logical properties to add RTL support to flexbox and CSS grid.
2. How to Add RTL Support to Flexbox
The following example uses flexbox to create a news website layout (here is the full tutorial). It has a centered heading and includes a couple of cards of different sizes. The demo uses two media queries: at 800px
and 1000px
. The arrangement of the cards will depend on which viewport size you look at the demo:
To create an RTL version of the CSS, we have to add just one rule:
* { direction: rtl; }
And, as you can see below, the demo has been flipped perfectly–not just the text, but the layout too–at every viewport size:
Why Was It So Easy to Do?
When physical directions are used in CSS layouts they can often mess up your RTL efforts. But if you look at the CSS below, you’ll see physical directions aren’t used, hence why it was so easy to flip the layout (text decoration rules such as fonts and colors have been removed from the code for ease of reading):
.header { padding: 40px 0 20px; text-align: center; } .header h2 a { border-bottom: 1px solid rgba(255, 255, 255, 0.5); } .main { margin: 0 auto; max-width: 1040px; padding: 10px; } .column { flex: 1; flex-direction: column; } .article { display: flex; flex: 1; flex-direction: column; flex-basis: auto; margin: 10px; } .article-image { display: block; padding-top: 75%; position: relative; width: 100%; } .article-image img { display: block; height: 100%; left: 0; position: absolute; top: 0; width: 100%; } .article-image.is-3by2 { padding-top: 66.6666%; } .article-image.is-16by9 { padding-top: 56.25%; } .article-body { display: flex; flex: 1; flex-direction: column; padding: 20px; } .article-title { flex-shrink: 0; } .article-content { flex: 1; margin-top: 5px; } .article-info { display: flex; justify-content: space-between; margin-top: 10px; } @media screen and (min-width: 800px) { .columns, .column { display: flex; } } @media screen and (min-width: 1000px) { .first-article { flex-direction: row; } .first-article .article-body { flex: 1; } .first-article .article-image { height: 300px; order: 2; padding-top: 0; width: 400px; } .main-column { flex: 3; } .nested-column { flex: 2; } }
Flexbox takes care of the whole layout, and flexbox properties are logical properties. Sizing and alignment properties such as border
, margin
, padding
, and width
could cause problems in certain cases, as they rely on physical directions instead of logical ones. For example, the demo uses the old-style padding-top
property instead of the brand new padding-block-start
, its logical equivalent.
However, as we want to perform an LTR to RTL conversion, we only need to flip the horizontal (left-right) axis but not the vertical one (top-bottom). The code above only contains properties that define vertical directions such as padding-top
and border-bottom
. These stay the same in both layouts.
As there aren’t any properties in the code that define horizontal directions (for instance, padding-left
would be such a property), we don’t have to adjust them to fit RTL scripts.
3. How to Add RTL Support to CSS Grid
Now, let’s see the CSS grid demo. It defines an asymmetrical layout built on top of CSS grid (here is the full tutorial):
Let's add the same direction
rule to the CSS and see how it modifies the original layout:
* { direction: rtl; }
Here’s how the demo has been flipped:
Although most elements have been flipped just as expected, something is missing. If you compare the two demos carefully, you can see that the crown badge between the images and the “Gibraltar” headline has disappeared.

So, Where Is the Crown?
The CSS gives us the answer as to why the crown is missing. It’s still there, but hidden against the background. Here’s the CSS code of the demo (without color, font, and other text decoration rules):
blockquote { margin: 0 0 2em 0; } .cta { padding: 100px 0 100px 20%; } .cta h1 { margin: 0 0 20px 0; position: relative; } .button { display: inline-block; padding: .8em 1.5em; } .strapline { margin-top: 100px; position: relative; } .strapline::before { content: ''; display: block; background: url(wavy.svg) repeat-x; background-size: cover; width: 20%; height: .5em; position: absolute; top: -3em; left: 40%; } .cta h1::before { content: ''; display: block; height: 1em; width: 1em; background: url(badge.svg) no-repeat center center; background-size: 80%; position: absolute; left: -120px; top: 0; } /* Grid layout */ .grid1 { display: grid; grid-template-columns: 3fr 6fr 1fr 5fr 10fr 2fr; grid-template-rows: 100px auto 15px auto auto; } .img1 { background: url(wooden.jpg); background-size: cover; grid-column: 1 / span 2; grid-row: 2 / span 3; } .img2 { background: url(speaker.jpg); background-size: cover; grid-column: 2 / span 2; grid-row: 3 / span 3; } .img3 { background: url(waves.jpg); background-size: cover; grid-column: 5 / span 2; grid-row: 4 / span 2; } .strapline { grid-column: 3 / span 3; grid-row: 2 / span 1; padding: 0 16%; text-align: center; margin: 0; } .cta-wrapper { grid-column: 4 / span 2; grid-row: 4 / span 2; }
The code above uses numerous CSS grid properties such as grid-row
, grid-column
, grid-template-rows
, and grid-template-columns
. However, as CSS grid relies on logical dimensions instead of physical ones, Grid-related properties can’t be the issue.
The problem stems from other properties that physically position items in the horizontal (left-right) dimension:
.cta { padding: 100px 0 100px 20%; } .strapline::before { left: 40%; } .cta h1::before { left: -120px; }
To support RTL scripts, we need to reverse left
and right
as follows:
.cta { padding: 100px 20% 100px 0; } .strapline::before { right: 40%; } .cta h1::before { right: -120px; }
If you have a look at the modified RTL demo you can see that the crown has reappeared and now everything is perfectly aligned:
You have probably noticed that in the modified CSS, we have used right
instead of the corresponding logical property. This is because logical properties are not yet production-ready, as browser support is still somewhat patchy.
However, this is how the modified CSS would look using the logical equivalent of the right
property:
.cta { padding: 100px 20% 100px 0; } .strapline::before { inset-inline-start: 40%; } .cta h1::before { inset-inline-start: -120px; }
The equivalent of right
is inset-inline-start
in RTL scripts, as that is the beginning of the inline axis. However, in LTR scripts inset-inline-start
equates to left
, as in that case, rows begin on the left of the screen.
So, if the original demo used the inset-inline-start
logical property instead of the physical left
direction, we could have converted the layout from LTR to RTL without having to adjust any rules.
Below, you can see the same RTL demo using logical properties. I have also changed top
to inset-block-start
just for the sake of consistency.
Conclusion
CSS logical properties let us support right-to-left scripts more easily than ever before. We can quickly add RTL support to pages based on flexbox and CSS grid as they are logical layouts that don’t rely on physical directions such as left, right, top, and bottom.
Besides RTL languages, we can also use logical properties to convert top-to-bottom writing modes to vertical language scripts such as Japanese. Check out my previous tutorial for more details!