You’ve probably hit this subtle bug before: you write some CSS using logical properties like margin-inline-start, expecting your layout to just work regardless of text direction. But then you flip your app to RTL or switch writing modes, and suddenly things don’t line up as you expected. Margins that should shift to the left stay put, or worse, shift in the wrong direction.
I ran into this during a recent localization sprint. Our UI had mixed LTR and RTL content, and rather than duplicating styles or using awkward hacks, I leaned on CSS logical properties. They’re supposed to abstract away physical directions like left/right and top/bottom. But debugging why my margins weren’t behaving as I imagined forced me to dig under the hood , how exactly do browsers turn these logical properties into physical ones?
Logical vs Physical CSS Properties: The Basic Idea
Traditional CSS uses physical directions:
margin-left: 10px;
padding-top: 5px;
These are fixed to the box’s edges, regardless of the document’s writing mode (LTR or RTL) or layout direction (horizontal or vertical).
Logical properties, introduced in CSS Logical Properties and Values Module, let you specify styles based on the writing mode and flow:
-
margin-inline-startapplies margin at the start of the inline flow -
padding-block-endapplies padding at the end of the block flow
So in a left-to-right language, margin-inline-start equals margin-left. In right-to-left, it maps to margin-right. This makes your CSS more adaptable without duplication.
But here’s the kicker: browsers do this mapping internally, translating your logical properties to physical ones at layout time. Understanding that translation explains many layout quirks.
How Browsers Translate Logical Properties
When the browser’s CSS engine parses a rule like:
.my-box {
margin-inline-start: 16px;
}
it doesn’t leave it as margin-inline-start. Instead, it figures out the physical edge corresponding to "inline start" for the element’s writing mode and direction.
For example, suppose your document is LTR horizontal:
- inline direction goes left to right
- inline start is left
The browser will apply the margin as margin-left: 16px internally. But if the same element is in RTL horizontal:
- inline direction is right to left
- inline start is right
Now the browser applies margin-right: 16px.
This mapping happens during style computation, after resolving the element’s writing-mode and direction but before layout.
What about vertical writing modes?
When the writing mode is vertical (like Japanese or Mongolian vertical text), "inline" and "block" directions swap:
- Inline flows top to bottom or bottom to top
- Block flows left to right or right to left
So margin-inline-start could map to margin-top or margin-bottom depending on writing-mode and direction. This can be surprisingly confusing if you only think in LTR horizontal terms.
Behind the Scenes: The Browser’s Style Computation Pipeline
In the browser’s rendering engine (think Blink, Gecko, or WebKit), style computation is a multi-step process:
Parsing CSS , The engine parses your CSS, creating a style tree where each node has declarations like
margin-inline-start.Resolving Computed Styles , The engine resolves computed values for each property. For logical properties, it uses the element’s computed
writing-modeanddirectionto map logical properties to physical ones.Applying Physical Styles , The engine applies these physical styles to layout boxes, which then participate in the box model and flow layout calculations.
This means that from the layout engine’s perspective, it never really sees margin-inline-start; it only sees margin-left or margin-top, etc., depending on context.
Why This Matters for Debugging Layout Issues
- Unexpected Margins on RTL or Vertical Text
If your app flips to RTL but some margins don’t move as expected, check if you’re mixing logical and physical properties. Physical properties like margin-left don’t adapt, so your layout breaks.
- Overriding Logical Properties with Physical Ones
Sometimes, authors override logical properties with physical ones elsewhere in CSS. Because physical properties have the same specificity and cascade rules, the last one wins. This can cause logical properties to be silently ignored.
- DevTools Show Physical Properties
Inspecting elements in browser DevTools often shows the physical properties after translation, not the logical ones you wrote. This can confuse you into thinking your CSS isn’t applied.
Practical Tips When Using Logical Properties
Always use logical properties consistently in your CSS for layout margins, paddings, borders, and positioning.
Be mindful of writing mode. If your app supports vertical writing modes, test your layouts carefully. Logical properties behave differently there.
Check DevTools carefully. Don’t expect to see
margin-inline-startin computed styles. Look for the mapped physical properties.Use computed styles and layout debugging tools. Some browsers let you visualize box model edges and directions, which can help understand how logical properties translate.
Avoid mixing physical and logical properties for the same edge. This reduces cascade confusion.
A Real Debugging Example
I had a sidebar that used:
.sidebar {
padding-inline-start: 20px;
border-inline-end: 1px solid #ccc;
}
It looked perfect in LTR, but in RTL, the padding stayed on the left, and the border appeared on the left instead of the right. Turns out, somewhere else in the stylesheet, there was a physical property:
.sidebar {
padding-left: 10px;
}
Because padding-left came after in the cascade, it silently overrode the logical padding on the physical left edge.
Removing the physical property and relying solely on logical properties fixed the problem.
Wrap-up
CSS logical properties are a powerful way to write adaptable, locale-friendly styles. But they’re not magic. Browsers internally translate them to physical properties based on the element’s writing mode and direction, and understanding that helps you debug those sticky layout issues in multilingual or vertical writing layouts.
Next time your margin-inline-start feels stubborn, remember: it’s actually a margin-left or margin-right in disguise, chosen based on your document’s flow.
Happy styling!
Helpful learning resources
- MDN Web Docs
- web.dev performance guidance
- OpenAI developer resources Originally published at Under The Hood. Get the next deep dive in your inbox: subscribe to Under The Hood.
Top comments (0)