Lesson 13·Unit 4 · Scripts and layout·Layout mirroring & CSS logical properties·Lv 201·~8 min
RTL layouts: what flips and what doesn't
The bidi lesson covered text: the Unicode bidirectional algorithm reorders characters on its own. Nothing reorders your layout. Margins, offsets, and icons mirror only if you wrote them in CSS logical properties; this page shows the same app frame built both ways.
By the end
- ·Explain why dir="rtl" flips your text and leaves a physically-styled layout exactly where it was.
- ·Convert physical CSS (margin-left, left, text-align: left) to the logical properties that follow direction.
- ·Decide which icons mirror and which stay put, and give the reason behind each call.
The problem
Every margin-left, left: 12px, and text-align: left in your stylesheet bakes a left-to-right reading order into the layout. Set dir="rtl" for an Arabic or Hebrew build and the text right-aligns (the browser handles characters), but the back button stays glued to the left, chevrons point into their rows, and the progress bar fills from the wrong end. The result is a half-mirrored UI, and it never shows up in an English-only review because physical and logical CSS render identically in LTR.
How it works
The two halves of RTL
The bidi lesson covered the first half: the Unicode bidirectional algorithm reads character properties and reorders text runs on its own. An Arabic sentence lays out right-to-left before you write a line of CSS. The natural next assumption is that the rest of the page follows. It does not. The algorithm's job ends at text. Your margins, offsets, icon positions, and progress bars know nothing about reading direction, because margin-left means the compass-left side of the box in every locale.
The switch for the second half is dir="rtl" on the html element. On its own it does real work: blocks right-align, table columns run right to left, flex and grid reverse their inline axis. But it can only reach CSS that speaks in flow terms. That is what logical properties are. margin-inline-start names the side where a line of text begins, so it lands on the left under LTR and on the right under RTL. A physical property names a fixed side and stays where you put it. Write your layout logically and it mirrors on that one attribute. Write it physically and you need a second, overriding stylesheet. That is why build tools like RTLCSS exist to machine-rewrite left into right for teams that cannot migrate.
CSS shipped compass sides first and flow sides decades later because early CSS assumed one writing direction, and a retrofit cost a full mirrored vocabulary. Logical properties give every physical property a flow-relative twin (left → inset-inline-start, border-top-left-radius → border-start-start-radius) so one stylesheet can serve both directions. In LTR the twins behave identically. That is why the bug hides: physical CSS looks correct in every English review and breaks only when the first Arabic or Hebrew build sets the attribute.
<html dir="rtl" lang="ar">
.row {
padding-inline-start: 44px; /* was padding-left */
text-align: start; /* was left */
}
.row .chevron {
inset-inline-end: 8px; /* was right */
}How it works
Icons are a separate audit
Logical properties move boxes. They never redraw a glyph. A back arrow repositioned to the right edge still points left, so directional icons need their own rule (the standard one is [dir="rtl"] .icon { transform: scaleX(-1) }). The harder question is which icons get it. Material Design's guidance draws the line at meaning: mirror what depicts navigation or the passage of time (back and forward arrows, list chevrons, progress bars), and do not mirror what depicts a physical object or circular time (keyboards, headsets, and clocks, which turn clockwise everywhere).
Two verdicts are easy to get wrong. The search magnifier looks directional but is not: its handle sits bottom-right because it depicts a right hand holding the glass, and right-handedness holds in RTL countries too. Media playback stays LTR entirely: play, fast-forward, and the scrubber follow the direction of the media rather than the direction of time. A video scrubber and a download progress bar showing the same 60% therefore mirror differently. One verdict is even per-script: icons containing a question mark mirror for Arabic and Farsi (Arabic script has its own mirrored question mark, ؟) but not for Hebrew, which keeps the Latin one.
See it yourself
Try these, in order
Each step triggers a specific failure you should recognize on sight.
- 1Leave the Language toggle on English and compare the two frames. They render pixel-identical. Physical and logical CSS agree completely under LTR. That is why this bug class survives every English-only review.
- 2Click Arabic and read the Physical CSS column. The text right-aligned on its own: that half is the bidi algorithm. But the back control is still on the left, chevrons point into the rows, and numbered markers sit on each break. The list under the frame, “Where the physical column breaks”, names all four.
- 3Click marker 3, on the progress bar. The fill anchors at left: 0, a physical property, so the bar still fills from the left. An RTL progress bar shows 0% on the right and fills right to left.
- 4Now read the Logical CSS column, still in Arabic. Same markup, fully mirrored: header, rows, bar, and button all flipped because inline-start now resolves to the right. The only RTL-specific rule in that column is the one that flips directional icon glyphs: CSS moves boxes, not glyphs.
- 5In the “What flips and what doesn't” table, compare the Progress bars row with the Media playback & scrubber row. Both are a bar filling left to right, but one flips and one does not. A progress bar depicts time, and a scrubber depicts the media. The verdict comes from what the element means rather than what it looks like.
- 6Read the last row of “The property map”. text-align: start is a one-word change from left, and it is the difference between a column that mirrors and one that does not.
Language
Both frames get dir="ltr" and lang="en". The columns differ only in which CSS properties they use.
Physical CSS
left / right · padding-left / padding-right · margin-left: auto · text-align: left
Logical CSS
inset-inline-start / end · padding-inline-start / end · margin-inline-start: auto · text-align: start
What flips and what doesn't
The rule of thumb: mirror anything that depicts reading direction (arrows, chevrons, linear progress). Clocks, media playback, and physical objects like the search magnifier stay in place.
| Element | Verdict | Why |
|---|---|---|
| Back / forward arrows | Flips | Back and forward navigation buttons reverse. Forward points left in RTL. · Material bidirectionality |
| Chevrons in list rows | Flips | chevron_left and chevron_right are on Material's list of icons to mirror. A row chevron points at the row's inline end. · Material icons guide |
| Progress bars | Flips | An RTL progress bar shows 0% on the right and 100% on the left, and fills right to left. · Material bidirectionality |
| Text alignment | Flips | dir="rtl" right-aligns blocks on its own. text-align: start / end keeps your overrides direction-aware. · W3C i18n |
| Search magnifier | Doesn't flip | The handle sits bottom-right because it depicts a right hand holding the glass, and right-handedness holds in RTL countries too. · Material bidirectionality |
| Media playback & scrubber | Doesn't flip | Playback buttons and the media progress indicator follow the direction of the media, not the direction of time. · Material bidirectionality |
| Clocks, refresh, history | Doesn't flip | RTL does not mirror the circular direction of time. Clocks still turn clockwise. · Material bidirectionality |
| Camera & other non-directional icons | Doesn't flip | Icons that do not communicate direction stay unmirrored. · Material bidirectionality |
| Question mark (help icon) | Depends on script | Mirrored for Arabic and Farsi (؟ is a distinct character), but not for Hebrew, which keeps the Latin question mark. · Material icons guide |
Verdicts follow Material Design's bidirectionality guidance, its icons-in-RTL guide, and the W3C i18n guidance on document direction.
The property map
Every physical property has a logical equivalent. In LTR they behave identically. Under dir="rtl" the logical one resolves to the opposite side. Names per MDN and CSS Logical Properties and Values Level 1.
| Physical (LTR-only) | Logical (direction-aware) |
|---|---|
| margin-left | margin-inline-start |
| padding-right | padding-inline-end |
| left | inset-inline-start |
| border-top-left-radius | border-start-start-radius |
| text-align: left | text-align: start |
If you remember one thing
The bidi algorithm mirrors your text for free. Nothing mirrors your layout. Write CSS in logical properties (inline-start / inline-end) so dir="rtl" on the html element flips the whole UI. Then audit icons separately, because CSS moves boxes, not glyphs.
What to do about it
- Write layout in logical properties by default:
margin-inline-start,padding-inline-end,inset-inline-start,text-align: start. In LTR they cost nothing; underdir="rtl"they mirror the layout without a second stylesheet. - Set
dir="rtl"andlangon thehtmlelement, not per component; direction is a document-level decision that tables, forms, and alignment all inherit. - Audit icons separately: CSS moves boxes, not glyphs. Mirror back/forward arrows and list chevrons; leave playback controls, clocks, and the search magnifier alone (Material Design's bidirectionality guidance has the full list).
- Add a lint rule that flags physical properties in new CSS, and run an RTL pass before translation lands; the breakage is visible with placeholder text.
Use this with
Stakeholders
Moments
- ·RTL launch readiness review
- ·Component library audit
- ·Design handoff for an Arabic or Hebrew market
See it in a market: Egypt: Arabic-script market data →
Field note
“Set dir="rtl" and ship” is the classic first Arabic build. The text right-aligns, but every margin-left, left offset, and left-pointing chevron stays put: the half-mirrored UI this demo's physical column reproduces. Ahmad Shadeed's RTL Styling 101, written from examples on production Arabic UIs including LinkedIn's and Twitter's, exists because the failure is that common. It walks the physical-to-logical fixes property by property.
Quick check
3 questions · pass at 2+
Question 1/3
A badge is pinned with left: 12px. Which change makes it sit at the row's start in both LTR and RTL?
Question 2/3
Your player screen shows a download progress bar and a video scrubber. Under dir="rtl", which one mirrors?
Question 3/3
Which statement about the help icon's question mark is right?