Skip to content

Logical Properties and Internationalization

beginner10 min read

Left and Right Are Not Universal

Here's something most developers never think about: English reads left-to-right, top-to-bottom. Arabic reads right-to-left. Japanese can read top-to-bottom, right-to-left. If you hardcode margin-left: 20px for an indent, Arabic users see the indent on the wrong side. Logical properties replace physical directions (left, right, top, bottom) with flow-relative ones (inline-start, inline-end, block-start, block-end) that automatically adapt to any writing direction.

Mental Model

Think of logical properties as directions relative to reading flow, not the screen. "Start" is where reading begins — left in English, right in Arabic. "End" is where reading finishes. "Block" is the direction paragraphs stack — top-to-bottom in most languages, right-to-left in vertical Japanese. If your CSS uses logical properties, flipping the language flips the layout automatically — no separate RTL stylesheet needed.

Physical vs Logical Properties

PhysicalLogicalDescription
margin-leftmargin-inline-startStart of reading direction
margin-rightmargin-inline-endEnd of reading direction
margin-topmargin-block-startStart of block flow
margin-bottommargin-block-endEnd of block flow
padding-leftpadding-inline-startStart inline padding
padding-rightpadding-inline-endEnd inline padding
widthinline-sizeSize in reading direction
heightblock-sizeSize in block direction
topinset-block-startBlock start offset
leftinset-inline-startInline start offset
border-leftborder-inline-startBorder at inline start
text-align: lefttext-align: startAlign to start of reading

Shorthand Properties

.card {
  /* Horizontal padding (inline axis) */
  padding-inline: 1.5rem; /* Sets both inline-start and inline-end */

  /* Vertical padding (block axis) */
  padding-block: 1rem; /* Sets both block-start and block-end */

  /* Individual values */
  margin-inline: 2rem 1rem; /* inline-start: 2rem, inline-end: 1rem */

  /* Size */
  inline-size: 300px; /* Width in LTR, adapts in vertical modes */
  block-size: auto;

  /* Border */
  border-inline-start: 3px solid blue; /* Left border in LTR, right in RTL */

  /* Position */
  inset-inline-start: 0; /* left: 0 in LTR, right: 0 in RTL */
}

Building RTL-Ready Layouts

/* Physical (breaks in RTL) */
.sidebar {
  float: left;
  margin-right: 2rem;
  border-left: 3px solid blue;
  text-align: left;
}

/* Logical (works in any direction) */
.sidebar {
  float: inline-start;
  margin-inline-end: 2rem;
  border-inline-start: 3px solid blue;
  text-align: start;
}

Setting the Direction

<!-- Document level -->
<html lang="ar" dir="rtl">

<!-- Section level -->
<blockquote dir="rtl">Arabic quote here</blockquote>
/* Or via CSS (HTML attribute is preferred for semantics) */
:root[dir="rtl"] {
  direction: rtl;
}

/* Detect direction in CSS */
:dir(rtl) .icon { transform: scaleX(-1); } /* Flip directional icons */
Common Trap

Not everything should flip in RTL. Phone numbers, code snippets, mathematical formulas, and progress bars usually maintain LTR direction. Icons that represent directional concepts (back arrow, forward arrow) should flip, but icons that are symmetric (home, search, settings) should not. Use the :dir(rtl) pseudo-class to selectively flip only what needs flipping.

Writing Modes

Most of us won't need this daily, but understanding it makes logical properties click.

For vertical text and advanced internationalization:

/* Default: horizontal, top-to-bottom */
.default { writing-mode: horizontal-tb; }

/* Vertical: right-to-left columns (traditional CJK) */
.vertical-rl { writing-mode: vertical-rl; }

/* Vertical: left-to-right columns */
.vertical-lr { writing-mode: vertical-lr; }

And this is where it gets mind-bending: when writing mode changes, the meaning of inline and block axes swap:

.vertical-text {
  writing-mode: vertical-rl;
  /* Now: inline axis = vertical, block axis = horizontal */
  /* inline-size = what was height */
  /* block-size = what was width */
  /* margin-inline-start = what was margin-top */
}

This is exactly why logical properties exist — they follow the text flow regardless of writing mode.

The practical impact on flexbox and grid

Flexbox and grid already use logical directions. flex-direction: row follows the inline axis — in RTL, a row flex container starts items from the right. justify-content: flex-start means inline-start. Grid's grid-column-start follows the inline direction. So if you're using flex/grid, your layout already adapts to writing direction without explicit logical properties. But margins, padding, borders, and widths still need the logical property equivalents.

Quiz
In a vertical-rl writing mode, what does inline-size correspond to?
Execution Trace
LTR document
dir='ltr', margin-inline-start: 2rem
Renders as margin-left: 2rem
RTL document
dir='rtl', same CSS
Renders as margin-right: 2rem — automatically flipped
Border
border-inline-start: 3px solid blue
Left border in LTR, right border in RTL
Text align
text-align: start
Left-aligned in LTR, right-aligned in RTL
Position
inset-inline-start: 0
left: 0 in LTR, right: 0 in RTL

Production Scenario: Navigation with RTL Support

Let's see how this works in a real component.

.nav {
  display: flex;
  gap: 1rem;
  padding-inline: 2rem;
}

.nav-logo {
  margin-inline-end: auto; /* Pushes other items to the end */
}

.nav-item {
  padding-inline: 0.75rem;
}

/* Dropdown arrow flips in RTL */
.dropdown-arrow {
  margin-inline-start: 0.25rem;
}

:dir(rtl) .dropdown-arrow {
  transform: scaleX(-1);
}

/* Breadcrumb separator */
.breadcrumb-separator {
  margin-inline: 0.5rem;
  /* In LTR: > */
  /* In RTL: need to flip or use a neutral separator */
}

:dir(rtl) .breadcrumb-separator {
  transform: scaleX(-1);
}
What developers doWhat they should do
Using margin-left/margin-right for layout spacing
Physical directions break when the document direction changes to RTL or when writing mode is vertical
Use margin-inline-start/end or the margin-inline shorthand
Flipping all icons in RTL layouts
Not everything has direction. A house icon doesn't need to face right-to-left.
Only flip directional icons (arrows, progress). Keep symmetric icons (home, search) unchanged.
Using CSS direction property instead of the HTML dir attribute
The dir attribute affects the bidirectional algorithm for text, form inputs, and accessibility. CSS direction only affects rendering.
Use the HTML dir attribute for document direction — it's semantic and affects non-CSS behavior
Forgetting that width/height are physical — using them for responsive layouts
In vertical writing modes, width becomes the block axis. inline-size always follows the text flow.
Use inline-size and block-size for layouts that should adapt to writing direction
Quiz
In an RTL document, what does margin-inline-start: 2rem render as?
Quiz
A flex container with flex-direction: row in an RTL document — which direction do items flow?
Key Rules
  1. 1Use logical properties (margin-inline, padding-block, inline-size) instead of physical (margin-left, padding-top, width)
  2. 2Flexbox and grid already follow logical direction — items flow with the document's inline axis
  3. 3Use the HTML dir attribute for direction, not the CSS direction property
  4. 4Only flip directional icons in RTL — symmetric icons stay unchanged
  5. 5Shorthands like margin-inline and padding-block set both start and end values