Introduction to CSS logical properties

Before we delve into what CSS logical properties are, let’s start with a practical example. Imagine we are creating a simple horizontal list of text messages:
<ul class="horizontal-list"> <li>I am text message no. 1 and I come first in the list</li> <li>I am text message no. 2 and I come second in the list</li> <li>I am text message no. 3 and I come third in the list</li></ul>
We use CSS to style the list and each message:
.horizontal-list { list-style: none; white-space: nowrap; padding: 0; margin: 0;
li { white-space: normal; margin-left: 50px; width: 200px; display: inline-block; vertical-align: top; }
li:first-child { margin-left: 0; }}
The result is a neatly displayed horizontal list:
- I am text message no. 1 and I come first in the list
- I am text message no. 2 and I come second in the list
- I am text message no. 3 and I come third in the list
Preparing for Globalization
Now, let’s assume the widget becomes so popular that we want to create versions in other languages. While translating to Spanish or French is straightforward, what about Arabic, which is written right-to-left (RTL)? Simply adding a dir="rtl"
attribute should address this, but let’s see the outcome:
- I am text message no. 1 and I come first in the list
- I am text message no. 2 and I come second in the list
- I am text message no. 3 and I come third in the list
Notice something odd? There’s no margin between the first and second messages, but there is between the second and third. This occurs because of our margin-left
rule, which needs to change to margin-right
for RTL languages.
To fix this, we can add an RTL-specific CSS rule:
.horizontal-list { list-style: none; white-space: nowrap; padding: 0; margin: 0;
li { white-space: normal; margin-left: 50px; width: 200px; display: inline-block; vertical-align: top; }
li:first-child { margin-left: 0; }}
[dir='rtl'].horizontal-list { li { margin-left: 0; margin-right: 50px; }
li:first-child { margin-right: 0; }}
- I am text message no. 1 and I come first in the list
- I am text message no. 2 and I come second in the list
- I am text message no. 3 and I come third in the list
Now, it looks much better!
Expanding to Other Languages
With the widget’s success, we’re now releasing it in several Asian countries, some of which have scripts that flow top-to-bottom and right-to-left. This means we need to convert margin-left
to margin-top
and width
to height
.
Our CSS now includes:
.horizontal-list { list-style: none; white-space: nowrap; padding: 0; margin: 0;
li { white-space: normal; margin-left: 50px; width: 200px; display: inline-block; vertical-align: top; }
li:first-child { margin-left: 0; }}
[dir='rtl'].horizontal-list { li { margin-left: 0; margin-right: 50px; }
li:first-child { margin-right: 0; }}
.vertical-rl.horizontal-list { writing-mode: vertical-rl;
li { margin-left: 0; margin-top: 50px; width: auto; height: 200px; }
li:first-child { margin-top: 0; }}
- I am text message no. 1 and I come first in the list
- I am text message no. 2 and I come second in the list
- I am text message no. 3 and I come third in the list
We’ve achieved the desired layout in all cases, but our CSS has become increasingly complex, requiring many additional rules. Imagine doing this for every element in a large project! This is where CSS logical properties come into play.
Introducing CSS Logical Properties
Traditional CSS properties define layout using physical dimensions. For instance, width
denotes horizontal size, height
denotes vertical size and margin-left
specifies the left margin. In contrast, CSS logical properties define layout based on the logical flow of the content. For instance, inline-size
denotes the size of the element in the dimension which is parallel to the flow of text, block-size
denotes the size in the dimension perpendicular to the flow of text, etc.
Here are some common logical properties:
inline-size
instead ofwidth
block-size
instead ofheight
margin-inline-start
instead ofmargin-left
margin-inline-end
instead ofmargin-right
margin-block-start
instead ofmargin-top
margin-block-end
instead ofmargin-bottom
padding-inline-start
instead ofpadding-left
padding-inline-end
instead ofpadding-right
padding-block-start
instead ofpadding-top
padding-block-end
instead ofpadding-bottom
inset-inline-start
instead ofleft
inset-inline-end
instead ofright
inset-block-start
instead oftop
inset-block-end
instead ofbottom
- …and many more
You can find the full list of logical properties on MDN.
Here’s how we can refactor our widget to use logical properties:
.horizontal-list { list-style: none; white-space: nowrap; padding: 0; margin: 0;
li { white-space: normal; margin-inline-start: 50px; inline-size: 200px; display: inline-block; vertical-align: top; }
li:first-child { margin-inline-start: 0; }}
This setup works seamlessly in different text directions:
LTR (Left-to-Right):
- I am text message no. 1 and I come first in the list
- I am text message no. 2 and I come second in the list
- I am text message no. 3 and I come third in the list
RTL (Right-to-Left):
- I am text message no. 1 and I come first in the list
- I am text message no. 2 and I come second in the list
- I am text message no. 3 and I come third in the list
Vertical RTL:
- I am text message no. 1 and I come first in the list
- I am text message no. 2 and I come second in the list
- I am text message no. 3 and I come third in the list
Browser Support
CSS logical properties boast good cross-browser support, so you can confidently implement them in your projects. For detailed compatibility, check caniuse.
Flexbox and Grid with Logical Properties
Both Flexbox and Grid layouts inherently support logical dimensions. Here’s how we can rewrite our widget using Flexbox:
.horizontal-list { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: row; justify-content: flex-start; gap: 50px;
li { inline-size: 200px; flex-shrink: 0; }}
The output remains consistent across text directions, making it easier to maintain a responsive design.
In conclusion, leveraging CSS logical properties simplifies the process of creating layouts that adapt to different languages and writing modes, enhancing both your code’s maintainability and your website’s global accessibility.