Articles /

layout

Logical properties: writing-mode-aware CSS

Stop thinking left/right/top/bottom. Start thinking inline/block. Your layouts will thank you when they need to support RTL or vertical text.

Physical vs logical

Physical properties like margin-left and padding-top are hardcoded to the screen. Logical properties map to the content's flow direction instead. In a left-to-right language, margin-inline-start equals margin-left. In a right-to-left language, it becomes margin-right — automatically.

/* Physical — breaks in RTL */
.card { margin-left: 1rem; padding-top: 2rem; }

/* Logical — adapts to writing mode */
.card { margin-inline-start: 1rem; padding-block-start: 2rem; }

The shorthand properties

Logical shorthands accept one or two values. With two values, the first sets the start edge and the second sets the end edge:

/* margin-inline: start end */
.element {
  margin-inline: 1rem 2rem;   /* inline-start: 1rem, inline-end: 2rem */
  padding-block: 1.5rem;      /* block-start and block-end: 1.5rem */
  border-inline: 2px solid oklch(0.7 0.15 250);
}

/* Single value = both sides */
.centered {
  margin-inline: auto;  /* replaces margin: 0 auto for centering */
}
Use margin-inline: auto instead of margin: 0 auto — it's cleaner and only affects the inline axis.

Inset: the logical positioning shorthand

The inset property replaces top, right, bottom, left. Its logical counterparts are inset-block and inset-inline:

/* Full-bleed overlay — physical */
.overlay { top: 0; right: 0; bottom: 0; left: 0; }

/* Same thing — logical shorthand */
.overlay { inset: 0; }

/* Pinned to the inline-end edge */
.close-btn {
  position: absolute;
  inset-block-start: 0.5rem;
  inset-inline-end: 0.5rem;
}

Border and border-radius

Logical border properties let you style edges relative to flow. Logical border-radius targets specific corners using start/end naming:

.tab {
  border-block-end: 3px solid oklch(0.65 0.2 280);
  border-start-start-radius: 0.5rem; /* block-start + inline-start */
  border-start-end-radius: 0.5rem;   /* block-start + inline-end */
  border-end-start-radius: 0;
  border-end-end-radius: 0;
}

The naming pattern is border-{block}-{inline}-radius. It reads naturally once you internalize the block/inline axes.

Sizing with logical properties

Width and height have logical equivalents too: inline-size and block-size. These are particularly useful for vertical writing modes like Japanese:

.container {
  max-inline-size: 65ch;     /* replaces max-width */
  min-block-size: 100dvb;    /* replaces min-height */
}

/* Resize property also has a logical form */
.panel {
  resize: inline;  /* replaces resize: horizontal */
  overflow: auto;
}

Migration strategy

You don't need to convert everything at once. Start with new code and high-impact areas:

  • Use margin-inline and padding-block in all new CSS immediately.
  • Replace text-align: left with text-align: start.
  • Swap float: left for float: inline-start.
  • Convert max-width to max-inline-size in layout components.
Logical properties are Baseline Widely Available. There is no browser support reason to avoid them in production.