CSS Portal

CSS Logical Properties

If this site has been useful, we’d love your support! Consider buying us a coffee to keep things going strong!
css logical properties

Picture this: you’ve built a beautiful card component. Padding looks perfect in English. Then your product manager says “we need Arabic support” and suddenly everything is mirrored – your left-aligned icon is now on the wrong side, your margin-left pushes content the wrong way, and you’re drowning in [dir="rtl"] overrides that double your stylesheet size.

Or imagine a different scenario: you’re adding vertical text to a Japanese language feature. Your width and height suddenly mean the wrong thing, and your carefully tuned padding no longer aligns with the text flow. You add more hacks. The codebase grows. The confidence shrinks.

CSS Logical Properties were designed specifically to kill these problems. Rather than anchoring spacing and sizing to fixed physical directions – top, bottom, left, right – they anchor them to the flow of the document. The browser resolves which physical direction that maps to at paint time, based on writing-mode and direction. Your CSS stays lean; every language just works.

Core Idea
Logical properties describe positions relative to how content flows, not where it appears on screen. In English (LTR), inline-start resolves to left. In Arabic (RTL), it resolves to right. In Japanese vertical text, it resolves to top. The same CSS declaration handles all three with zero overrides.

This isn’t experimental. Logical properties have been in the CSS specification since 2017 and have full cross-browser support in all modern browsers. The question isn’t whether to use them – it’s building the mental model so they feel as natural as margin-top.

The Two Axes

The entire system of logical properties rests on two axes. Everything – margin, padding, border, sizing, positioning – gets expressed in terms of these two axes rather than physical screen directions.

Block Axis

The block axis runs perpendicular to the direction text flows in a line. In English, text flows left to right across a line, and new lines stack downward – so the block axis runs top to bottom. block-start means “the start of the block direction,” which in English is the top. block-end is the bottom.

A useful way to think about it: block = the direction the page grows as you add more content. Paragraphs stack along the block axis. New items in a vertical list move along the block axis. Scroll (in a standard webpage) happens along the block axis.

Inline Axis

The inline axis runs parallel to the direction text flows within a line. In English (LTR), this is left to right. inline-start is the left edge where a line begins, inline-end is the right edge where it ends. In Arabic (RTL), these flip – inline-start is now on the right.

Think of it as: inline = the direction a sentence flows. Characters in a word sit along the inline axis. Words in a sentence sit along the inline axis. The inline axis is where reading direction lives.

These axes are not fixed to physical directions. They rotate and flip depending on the writing-mode and direction CSS properties. That’s the whole power of the system. The axes travel with the content flow, so your logical properties travel with them automatically – you write the CSS once, and the browser handles the geometry.

DEMO 01
Property Explorer – click any property to highlight its edge
Select a property →
block-start
block-end
inline-start
inline-end

↑ block
← inline →
↓ block

margin-block-startmargin-top
margin-block-endmargin-bottom
margin-inline-startmargin-left
margin-inline-endmargin-right
padding-blockpadding-top + -bottom
padding-inlinepadding-left + -right

Shorthands as a bonus

One underappreciated benefit of logical properties is how much more expressive the shorthand forms are. padding-block: 1rem 2rem sets block-start to 1rem and block-end to 2rem in a single declaration. The physical equivalent required two separate lines: padding-top: 1rem; padding-bottom: 2rem;. These shorthands aren’t just shorter – they group related values together and signal intent more clearly. margin-inline: auto communicates “center this horizontally in the text flow direction” better than the two-property version ever did.

Physical vs. Logical: Full Reference

Here’s the complete day-to-day mapping. Notice the consistent naming formula: [property]-[axis]-[side]. Pick a property family (margin, padding, border, inset), then an axis (block or inline), then optionally a side (-start or -end). Omit the side to get the shorthand for both sides of that axis. Once you internalize that pattern, you can derive any logical property name without memorizing a list. For a broader reference on all CSS properties – including the physical counterparts listed here – see our CSS properties reference.

Spacing – Margin & Padding

Physical Logical Equivalent Shorthand
margin-top margin-block-start margin-block: [start] [end]
margin-bottom margin-block-end
margin-left margin-inline-start margin-inline: [start] [end]
margin-right margin-inline-end
padding-top padding-block-start padding-block
padding-bottom padding-block-end
padding-left padding-inline-start padding-inline
padding-right padding-inline-end

Borders

Border logical properties follow the same axis naming. Notably, border-block and border-inline let you style both edges of an axis simultaneously – something that had no physical equivalent before. Setting a consistent horizontal rule or a side-border on both left and right used to take two declarations; now it takes one.

Physical Logical Equivalent Shorthand
border-top border-block-start border-block (both edges)
border-bottom border-block-end
border-left border-inline-start border-inline (both edges)
border-right border-inline-end
border-top-left-radius border-start-start-radius
border-top-right-radius border-start-end-radius
border-bottom-left-radius border-end-start-radius
border-bottom-right-radius border-end-end-radius
Border-radius naming
The double-axis naming of logical border-radius (border-start-start-radius) trips people up at first. Read it as “the corner where block-start meets inline-start.” In LTR horizontal writing, that’s the top-left corner. In RTL, it’s the top-right. It’s consistent once you see the pattern, but it’s worth committing to memory separately from the rest.

Sizing

This is where logical properties make the deepest conceptual sense. width is fundamentally the measurement along the text-flow direction – in horizontal writing that happens to be left-to-right, so width = horizontal. But in vertical writing modes like Japanese, what we’d colloquially call “width” is actually the block-axis measurement. inline-size cuts through this ambiguity: it always means “the size along the direction text flows in a line,” regardless of physical orientation.

Physical Logical Equivalent
width inline-size
height block-size
min-width min-inline-size
max-width max-inline-size
min-height min-block-size
max-height max-block-size

Positioning – Inset

The inset family covers top, right, bottom, left for positioned elements. The bare inset shorthand (without an axis qualifier) is itself a new addition – it sets all four physical sides at once, like a shorthand for top + right + bottom + left. It’s not purely logical, but it’s a useful shorthand that arrived alongside the logical property work.

Physical Logical Equivalent Shorthand
top inset-block-start inset-block
bottom inset-block-end
left inset-inline-start inset-inline
right inset-inline-end
top + right + bottom + left inset (all 4 sides)

The RTL Problem, Solved

Right-to-left support has historically been one of the most painful parts of internationalising a web application. The traditional approach involves writing all your CSS for LTR first, then appending a large [dir="rtl"] block that mirrors every physical property. This approach has serious maintenance problems: the RTL block doubles your spacing-related CSS, it falls out of sync with changes to the base styles, and developers who don’t work in RTL languages often forget to update it – or never test it properly.

The worst part is that this problem is entirely structural. You’re writing two sets of rules for what is conceptually one piece of information: “this element should have space on the reading-start side.” Logical properties let you express that concept once.

What the old approach looked like

/* Base LTR styles */
.nav-icon {
  float: left;
  margin-right: 0.75rem;
  padding-left: 1rem;
  border-left: 2px solid var(--brand);
}

/* RTL override block - written separately, easy to forget to update */
[dir="rtl"] .nav-icon {
  float: right;
  margin-right: 0;
  margin-left: 0.75rem;
  padding-left: 0;
  padding-right: 1rem;
  border-left: none;
  border-right: 2px solid var(--brand);
}

The logical properties approach

/* One rule set. Handles LTR and RTL. No override needed. */
.nav-icon {
  float: inline-start;         /* float also accepts logical values */
  margin-inline-end: 0.75rem;  /* space after the icon in reading direction */
  padding-inline-start: 1rem;  /* breathing room on the reading-start side */
  border-inline-start: 2px solid var(--brand);
}
DEMO 02
Direction Toggle – physical vs. logical in action
Text direction:


❌ Physical properties

margin-left · border-left · padding-left

📦 Nav item. Has a left border accent and left-side padding. Switch to RTL to see it misalign.

✅ Logical properties

margin-inline-start · border-inline-start · padding-inline-start

📦 Same visual. Border and padding follow inline-start – they flip correctly in RTL automatically.

text-align and float also have logical values

It’s not just spacing properties. text-align accepts start and end as values. Using text-align: start instead of text-align: left means text aligns to the correct reading edge in both LTR and RTL without any override – and it reads more semantically accurately too. float: inline-start and float: inline-end work the same way. Even resize: block and resize: inline are available for <textarea> elements, constraining resizing to a specific axis.

/* text-align with logical values */
p      { text-align: start; }  /* left in LTR, right in RTL */
.label { text-align: end; }    /* right in LTR, left in RTL */
.hero  { text-align: center; } /* center is already direction-agnostic */

/* float with logical values */
.pull-quote { float: inline-end; } /* right in LTR, left in RTL */

Writing Modes & Vertical Text

RTL is the more common internationalisation challenge for Western developers, but logical properties shine just as brightly in vertical writing systems. Japanese, Chinese, and Korean content is frequently laid out with writing-mode: vertical-rl, where text flows from top to bottom and columns progress right to left – used in traditional literature, newspapers, and many modern Japanese UI designs. Mongolian traditionally uses writing-mode: vertical-lr, where columns progress left to right instead.

In a vertical writing mode, the axes literally rotate. The block axis now runs horizontally – because that’s the direction new columns stack. The inline axis runs vertically – because that’s the direction text flows within a column. If you’ve used physical properties throughout your CSS, you’d need to completely rethink your spacing for any vertical-mode component. With logical properties, the rotation is handled automatically by the browser – your padding-inline gives space in the vertical direction when the writing mode is vertical, exactly as it should.

DEMO 03
Writing Modes – how the axes shift

Click a writing mode to see how the block/inline axes map →

horizontal-tb · LTR
Hello! Standard English layout.
horizontal-tb · RTL
مرحبا! Arabic: inline-start = right.
vertical-rl
縦書き: Japanese vertical text flows top to bottom.

vertical-lr
ᠮᠣᠩᠭᠣᠯ: Mongolian, columns progress left to right.

In horizontal-tb LTR: block-start = top · block-end = bottom · inline-start = left · inline-end = right

A concrete vertical text example

Say you’re building a Japanese article layout with a sidebar label that uses writing-mode: vertical-rl. With physical properties, you’d set padding-left and padding-right for breathing room. But in vertical writing, “left” and “right” are the block axis – they control the depth of columns, not the spacing of text within a line. Your padding is suddenly applied in the wrong dimension. With logical properties, padding-inline always gives space in the text-flow direction, regardless of what physical direction that currently maps to.

.sidebar-label {
  writing-mode: vertical-rl;

  /* ❌ Physical - applies space in the block direction (horizontal), not inline */
  padding-left: 1rem;
  padding-right: 1rem;

  /* ✅ Logical - always gives space in the text-flow direction */
  padding-inline: 1rem;  /* = top + bottom in vertical-rl */
  padding-block: 0.5rem; /* = left + right in vertical-rl */
}

Live Playground

The best way to build intuition for logical properties is to manipulate them and watch the box model update in real time. Use the sliders below to adjust padding, border, and margin on different logical axes. Notice how the generated CSS uses shorthands where values are equal – the same way you’d write it in production.

DEMO 04
Logical Box Model Builder
padding-block-start

16px
padding-block-end

16px
padding-inline-start

24px
padding-inline-end

24px
border-inline-start

3px
margin-inline-start

0px

Component text

Practical Example: A Real Card Component

Theory is useful, but let’s build something real. Here’s a notification card component – the kind you’d find in a design system – written entirely with logical properties. It renders correctly in LTR, RTL, and vertical writing modes with zero additional CSS.

.notification-card {
  /* Sizing: inline-size instead of width */
  inline-size: 100%;
  max-inline-size: 420px;

  /* Padding: block for vertical rhythm, inline for horizontal breathing room */
  padding-block: 1.25rem;
  padding-inline: 1.5rem;

  /* Accent border on the reading-start edge */
  border-inline-start: 4px solid var(--brand);

  /* Round only the end-side corners (the side without the accent border) */
  border-start-end-radius: 8px;
  border-end-end-radius: 8px;

  position: relative;
}

.notification-card__icon {
  /* Space between icon and text, on the end side of the icon */
  margin-inline-end: 0.75rem;
}

.notification-card__badge {
  position: absolute;
  /* Top-right corner in LTR, top-left in RTL - no override needed */
  inset-block-start: 0.75rem;
  inset-inline-end: 0.75rem;
}

.notification-card__timestamp {
  display: block;
  margin-block-start: 0.5rem; /* space above, below the body text */
  text-align: end;             /* flush with reading-end edge */
}

The centering pattern to retire immediately

The single most impactful quick win in any codebase is replacing the centering pattern. How many times have you written margin-left: auto; margin-right: auto? Two lines, both required, physically anchored. Replace both with margin-inline: auto. It’s shorter, works in any writing mode, and clearly signals intent: “distribute available inline space equally on both sides.”

/* Old way - two properties, physically named */
.centered {
  margin-left: auto;
  margin-right: auto;
}

/* New way - one property, direction-agnostic */
.centered {
  margin-inline: auto;
}

The border-radius corner naming

Logical border-radius names use a double-axis convention that takes a moment to learn. border-start-start-radius names the corner where block-start meets inline-start – in English, that’s the top-left. border-start-end-radius is where block-start meets inline-end – the top-right in LTR. It’s verbose, but it’s completely consistent with the rest of the system, and it means a “tab” UI component (rounded on two adjacent corners) automatically mirrors itself in RTL.

Migrating an Existing Codebase

You don’t need to rewrite your entire stylesheet in one sitting. The best strategy is incremental: adopt logical properties as you touch existing code, write all new code with logical properties by default, and use tooling to enforce the convention going forward. Here’s how to do each step without disrupting production.

Step 1 – Start with symmetric patterns

The safest starting point is any property that’s currently set symmetrically – same value on both left and right, or both top and bottom. These migrations are trivially correct and visually identical in LTR. If you’d rather not do it by hand, our CSS logical property converter can translate physical properties to their logical equivalents automatically:

Common migrationsPhysical → Logical
margin-left: auto;
margin-right: auto;
margin-inline: auto;

padding-top: 1rem;
padding-bottom: 1rem;
padding-block: 1rem;

padding-left: 1.5rem;
padding-right: 1.5rem;
padding-inline: 1.5rem;

width: 100%;
max-width: 800px;
inline-size: 100%;
max-inline-size: 800px;

text-align: left;
text-align: start;

Step 2 – Think about directional intent

Not every physical property should become a logical one. Before converting, ask: “Should this direction flip in an RTL or vertical layout?” A decorative swoosh that is always pinned to the left side of the viewport as a visual brand element? That should stay as left: 0. A “back to top” button that is always in the bottom-right regardless of language? Keep right: 1rem; bottom: 1rem. The rule is simple: physical properties for physical design decisions, logical properties for flow-relative ones.

Don’t blindly convert everything
A notification tray that is always on the right side of the screen in your product design should use right: 0, not inset-inline-end: 0. Using the logical version would move it to the left side in RTL – which would violate the intended layout. Use logical properties where direction follows content, not where direction is a fixed product decision.

Step 3 – Update your design tokens

If you’re using CSS custom properties or a design token system, this is a good moment to audit your token names. Tokens named --spacing-left-sm encode physical direction into the token name itself. Renaming to --spacing-inline-start-sm – or more practically, restructuring so the “which side” decision happens in the component rather than the token – aligns your token architecture with logical thinking from the start.

Browser Support

Logical properties are not experimental or behind flags. They’ve been shipping in stable browsers since 2017–2020 depending on the property group, and as of 2025 they have near-universal support across all evergreen browsers. The table below reflects stable release support.

Property Group Chrome Firefox Safari Edge
margin / padding logical ✓ 69+ ✓ 41+ ✓ 12.1+ ✓ 79+
border logical ✓ 87+ ✓ 41+ ✓ 15+ ✓ 87+
border-radius logical ✓ 89+ ✓ 66+ ✓ 15+ ✓ 89+
inset logical ✓ 87+ ✓ 63+ ✓ 14.1+ ✓ 87+
inline-size / block-size ✓ 57+ ✓ 41+ ✓ 12.1+ ✓ 79+
text-align: start / end ✓ All ✓ All ✓ All ✓ All
float: inline-start / end ✓ 118+ ✓ 55+ ✓ 15+ ✓ 118+

Internet Explorer has no support and reached end-of-life in June 2022. If you’re still required to support IE, logical properties need physical fallbacks – but if you’re free of that constraint, you can use logical properties without any fallback in modern browsers. For teams that need to support Safari 12–14 specifically (the gap years for some property groups), physical property fallbacks written above the logical declaration will cascade correctly:

/* Safe pattern for wider support where needed */
.element {
  margin-left: 1.5rem;           /* fallback for older browsers */
  margin-inline-start: 1.5rem;  /* overrides in supporting browsers */
}

When Should You Use Them?

For any CSS written today, logical properties should be the default. The support is there, the DX is better (shorthands reduce line count, names signal intent more clearly), and the resilience to internationalisation changes is built in from the start. The honest question isn’t whether to use them – it’s how to make them feel as natural as the physical properties you’ve been writing for years.

Default to logical properties for…

  • All spacing that should flip in RTL layouts (margin, padding, border)
  • Sizing that should adapt to writing-mode changes (use inline-size, block-size)
  • Any new component in a design system
  • Positioning UI elements relative to text flow (icons, badges, timestamps, carets)
  • Centering elements horizontally – margin-inline: auto is strictly better
  • Text alignment where reading direction should determine the edge

Keep physical properties for…

  • Elements intentionally anchored to a fixed screen edge (viewport overlays, fixed sidebars always on the right)
  • Physical canvas, SVG, or WebGL coordinates where logical properties don’t apply
  • Explicit design decisions that should not mirror (brand-specific decorative layouts)
Quick Decision Rule
Ask: “Should this spacing or position flip if the user switches to Arabic or Japanese vertical text?” If yes, or if you’re unsure – use a logical property. Physical properties are for deliberate, direction-fixed design decisions. When in doubt, go logical.

TL;DR

CSS Logical Properties replace physical directions (top, left, right, bottom) with flow-relative equivalents (block-start, inline-start, etc.) that automatically adapt to any writing direction or mode. They eliminate RTL override blocks, make vertical-text layouts correct by default, and produce shorter, more semantically accurate CSS in the process. Browser support is universal across all modern browsers. Migration is safe and incremental. Tooling – Tailwind, ESLint plugins, CSS-in-JS – all support them without friction.

The next time you reach for padding-left, pause and ask if padding-inline-start better describes your intent. Nine times out of ten, it does.

If this site has been useful, we’d love your support! Consider buying us a coffee to keep things going strong!