Articles /
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 */
}
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-inlineandpadding-blockin all new CSS immediately. - Replace
text-align: leftwithtext-align: start. - Swap
float: leftforfloat: inline-start. - Convert
max-widthtomax-inline-sizein layout components.