DEV Community

Cover image for Your `margin-left` doesn't exist in Arabic. CSS logical properties fix that.
Parsa Jiravand
Parsa Jiravand

Posted on

Your `margin-left` doesn't exist in Arabic. CSS logical properties fix that.

Here is a layout assumption you have probably made without thinking about it.

A sidebar sits to the left of the content with margin-right: 1.5rem pushing the content away. A button has padding-left: 1rem so the label doesn't crowd its edge. A sticky header uses left: 0 to pin to the viewport. A nav indicator uses border-left: 3px solid.

All of that is correct in English, French, and German. In Arabic, Hebrew, or Persian — where text flows right-to-left — every one of those values is wrong. The sidebar should sit to the right. The button's breathing room belongs on the right edge. The sticky element pins to the right. The nav indicator appears on the right.

The standard patch is a [dir="rtl"] block that mirrors every physical property for right-to-left documents. You maintain two copies of every layout rule. They drift apart. They get missed.

CSS logical properties solve this at the property level.

The two axes

Physical CSS maps to the viewport: top, right, bottom, left. Logical CSS maps to the writing mode:

  • Inline axis — the direction text flows. Left-to-right in English; right-to-left in Arabic.
  • Block axis — the direction blocks stack. Top-to-bottom in most scripts.

Logical properties use inline and block in place of left/right/top/bottom. The browser resolves them to the correct physical direction based on the element's computed writing-mode and direction.

The main properties

Margins and padding:

/* Physical */
margin-left: 1rem;
padding-top: 0.5rem;

/* Logical */
margin-inline-start: 1rem;   /* left in LTR, right in RTL */
padding-block-start: 0.5rem; /* top in horizontal writing */
Enter fullscreen mode Exit fullscreen mode

Shorthand versions collapse both sides at once:

margin-inline: 1rem;      /* inline-start AND inline-end */
padding-block: 0.5rem;    /* block-start AND block-end */
margin-block: 1.5rem 0;   /* block-start block-end */
Enter fullscreen mode Exit fullscreen mode

Positioning:

/* Physical */
position: sticky;
left: 0;
top: 1rem;

/* Logical */
position: sticky;
inset-inline-start: 0;   /* left in LTR, right in RTL */
inset-block-start: 1rem; /* top in horizontal writing */
Enter fullscreen mode Exit fullscreen mode

The four-value inset shorthand covers all sides: inset: 0 is equivalent to top: 0; right: 0; bottom: 0; left: 0.

Borders:

/* Physical — a left-side accent border */
border-left: 3px solid var(--accent);

/* Logical */
border-inline-start: 3px solid var(--accent);
Enter fullscreen mode Exit fullscreen mode

Size:

/* Physical */
width: 100%;
height: 2rem;

/* Logical */
inline-size: 100%;  /* width in horizontal writing */
block-size: 2rem;   /* height in horizontal writing */
Enter fullscreen mode Exit fullscreen mode

Text alignment:

/* Always aligns to the physical left edge */
text-align: left;

/* Aligns to the start of the inline axis */
text-align: start;
Enter fullscreen mode Exit fullscreen mode

text-align: start is the most frequently missed change. In an English UI the two properties are identical — but when dir="rtl" is set on the <html> element, start aligns to the right automatically, while left stays physically left regardless of reading direction.

The before-and-after

A sidebar layout that supports both LTR and RTL, no override block needed:

/* Before — requires a full RTL mirror */
.sidebar {
  float: left;
  margin-right: 1.5rem;
  padding-left: 1rem;
  border-right: 1px solid var(--border);
}

[dir="rtl"] .sidebar {
  float: right;
  margin-right: 0;
  margin-left: 1.5rem;
  padding-left: 0;
  padding-right: 1rem;
  border-right: none;
  border-left: 1px solid var(--border);
}

/* After — one rule, both directions */
.sidebar {
  float: inline-start;
  margin-inline-end: 1.5rem;
  padding-inline-start: 1rem;
  border-inline-end: 1px solid var(--border);
}
Enter fullscreen mode Exit fullscreen mode

The logical version is shorter, has no duplicate block, and flips automatically when dir="rtl" is set on <html>. The browser does the math; you don't maintain the mirror.

When to start using logical properties

If your app supports or may ever support RTL languages, audit your layout CSS. Common candidates are easy to spot: margins and paddings that describe spacing relative to "the start of the content," text-align: left, left: 0 on sticky or fixed elements, and border-left/border-right accent styles.

If your app is English-only today, the case is still real. Apps grow. Retrofitting an existing codebase with logical properties is tedious — finding every margin-left, understanding whether it is layout-directional or genuinely physical, rewriting each one. Building with logical properties from the start costs nothing. margin-inline-start is the same number of characters as margin-left: with a value; the intent is actually clearer.

The one caveat: use physical properties when the direction truly is physical and should not flip. A drop shadow that always trails to the bottom-right regardless of reading direction should use box-shadow with physical offsets. A scroll-indicator pinned to the physical right edge of the viewport should use right: 0. Logical properties model writing direction, not every use of a spatial axis.

Browser support

Logical properties are Baseline 2023: Chrome 89, Firefox 66, Safari 15. Every browser released in the last three years supports the full property set. No polyfill, no flag, no build-time transform.

The takeaway

margin-left means "the left edge." margin-inline-start means "the edge where text begins." In English they produce identical output. In Arabic they diverge — and the logical version is correct for both without any extra code. The [dir="rtl"] mirror block was never a solution; it was the cost of using physical properties in a world that doesn't read in one direction. Logical properties eliminate that cost. The next time you reach for margin-left, ask whether you mean the physical left or the inline start. Usually you mean the start.


Thanks for reading! Let's stay connected:

Top comments (0)