All lessons

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.

RTLCSS logical propertiesdir=rtl

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 (leftinset-inline-start, border-top-left-radiusborder-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         */
}
One attribute flips the document, and logical properties let the flip reach your layout.

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.

  1. 1
    Leave 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.
  2. 2
    Click 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.
  3. 3
    Click 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.
  4. 4
    Now 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.
  5. 5
    In 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.
  6. 6
    Read 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

Settings
Profile
Notifications
Language
Progress
60%
Continue

Logical CSS

inset-inline-start / end · padding-inline-start / end · margin-inline-start: auto · text-align: start

Settings
Profile
Notifications
Language
Progress
60%
Continue

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.

ElementVerdictWhy
Back / forward arrowsFlipsBack and forward navigation buttons reverse. Forward points left in RTL. · Material bidirectionality
Chevrons in list rowsFlipschevron_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 barsFlipsAn RTL progress bar shows 0% on the right and 100% on the left, and fills right to left. · Material bidirectionality
Text alignmentFlipsdir="rtl" right-aligns blocks on its own. text-align: start / end keeps your overrides direction-aware. · W3C i18n
Search magnifierDoesn't flipThe 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 & scrubberDoesn't flipPlayback buttons and the media progress indicator follow the direction of the media, not the direction of time. · Material bidirectionality
Clocks, refresh, historyDoesn't flipRTL does not mirror the circular direction of time. Clocks still turn clockwise. · Material bidirectionality
Camera & other non-directional iconsDoesn't flipIcons that do not communicate direction stay unmirrored. · Material bidirectionality
Question mark (help icon)Depends on scriptMirrored 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-leftmargin-inline-start
padding-rightpadding-inline-end
leftinset-inline-start
border-top-left-radiusborder-start-start-radius
text-align: lefttext-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; under dir="rtl" they mirror the layout without a second stylesheet.
  • Set dir="rtl" and lang on the html element, 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

EngineeringDesignQA

Moments

  • ·RTL launch readiness review
  • ·Component library audit
  • ·Design handoff for an Arabic or Hebrew market

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.

RTL Styling 101: Ahmad Shadeed

Quick check

3 questions · pass at 2+

  1. 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?

  2. Question 2/3

    Your player screen shows a download progress bar and a video scrubber. Under dir="rtl", which one mirrors?

  3. Question 3/3

    Which statement about the help icon's question mark is right?

Words you'll hear

Where to read more

Related lessons