Take a look at this CSS snippet. What's wrong with it?
p {
border-top: 2px solid red;
margin-left: 2rem;
width: 80ch;
}
Depending on your website audience, there are either zero or three errors. Before explaining which errors, let's set some context.
A Matter of Perspective
When you step onto a boat, you won't hear terms like "left" or "right". That's because the left/right sides of a boat depend on the observer's perspective. Instead, they use "port" and "starboard", unambigous terms that always refer to the same sides of the boat, regardless of your position or the speaker's:
Image created by Pearson Scott Foresman and released into the public domain. Source
The same principle applies to anatomical terms of location, which allow doctors and veterinarians to describe the location of body parts unambiguously, regardless of the relative position of the patient or doctor.
CSS Internationalization
If your web applications are used globally, you must design them to adapt to various linguistic needs. For example, languages like English and Spanish are written from left-to-right (LTR); Arabic and Hebrew are written from right-to-left (RTL); Mongolian and traditional Japanese are written from top to bottom.
So, when you use a CSS declaration like this:
p {
margin-left: 2rem;
}
Do you mean that (1) you want to add space to the physical left of the paragraph, or (2) you want to add some space before the content starts? For a fully internationalized UI, the correct answer is always (2).
The Logical Solution
You could create separate stylesheets for LTR and RTL languages and load them conditionally. There are even tools like the webpack-rtl plugin that can generate automatically a RTL stylesheet based on the original LTR stylesheet.
However, the best solution would be to apply CSS styles conditionally like this:
p {
if writing is left-to-right:
margin-left: 2rem;
elseif writing is right-to-left:
margin-right: 2rem;
elseif writing is top-to-bottom:
margin-top: 2rem;
endif
}
You can do this in CSS but with a much simpler syntax:
p {
margin-inline-start: 2rem;
}
This margin-inline-start
property is a logical CSS property which dynamically adjusts based on the user's writing direction. Logical properties work similarly to the port/starboard analogy; they describe layout in a way that is unambiguous across different writing systems.
Logical properties define layout directions using these two terms:
-
inline
: parallel to the flow of text within a line. -
block
: perpendicular to the flow of text within a line.
This illustration shows the logical positions compared to the physical locations for all the writing modes supported by CSS:
Using logical properties, the initial example shown at the beginning of this aticle can be rewritten like this:
p {
border-block-start: 2px solid red;
margin-inline-start: 2rem;
inline-size: 80ch;
}
Updating an existing CSS stylesheet to use logical properties might seem daunting at first. However, most of the work involves simply replacing left
with inline-start
, right
with inline-end
, top
with block-start
, and bottom
with block-end
. Some properties require different renaming; for example, border-bottom-left-radius
becomes border-end-start-radius
, height
becomes block-size
, etc.
The effort is well worth it, as this is a future-proof solution that ensures your website is accessible to everyone. For instance, the EasyAdmin project, which I'm involved in, has already updated its stylesheets to use logical properties.
Logical Properties Reference
Here's a reference table of all the logical properties to help you update your own projects:
Physical Property | Logical Property |
---|---|
border-bottom |
border-block-end |
border-bottom-color |
border-block-end-color |
border-bottom-left-radius |
border-end-start-radius |
border-bottom-right-radius |
border-end-end-radius |
border-bottom-style |
border-block-end-style |
border-bottom-width |
border-block-end-width |
border-left |
border-inline-start |
border-left-color |
border-inline-start-color |
border-left-style |
border-inline-start-style |
border-left-width |
border-inline-start-width |
border-right |
border-inline-end |
border-right-color |
border-inline-end-color |
border-right-style |
border-inline-end-style |
border-right-width |
border-inline-end-width |
border-top |
border-block-start |
border-top-color |
border-block-start-color |
border-top-left-radius |
border-start-start-radius |
border-top-right-radius |
border-start-end-radius |
border-top-style |
border-block-start-style |
border-top-width |
border-block-start-width |
bottom |
inset-block-end |
container-intrinsic-height |
contain-intrinsic-block-size |
container-intrinsic-width |
contain-intrinsic-inline-size |
height |
block-size |
left |
inset-inline-start |
margin-bottom |
margin-block-end |
margin-left |
margin-inline-start |
margin-right |
margin-inline-end |
margin-top |
margin-block-start |
max-height |
max-block-size |
max-width |
max-inline-size |
min-height |
min-block-size |
min-width |
min-inline-size |
overscroll-behavior-x |
overscroll-behavior-inline |
overscroll-behavior-y |
overscroll-behavior-block |
overflow-x |
overflow-inline |
overflow-y |
overflow-block |
padding-bottom |
padding-block-end |
padding-left |
padding-inline-start |
padding-right |
padding-inline-end |
padding-top |
padding-block-start |
right |
inset-inline-end |
top |
inset-block-start |
width |
inline-size |
Learn More
✨ If you enjoyed this or my other articles and want to support my work, consider sponsoring me on GitHub 🙌
Top comments (1)
Learnt a new perspective, thanks for sharing!