Clean Markup

CSS Logical Properties for Multi-Directional Layouts

CSS Logical Properties for Multi-Directional Layouts

When building user interfaces that support both Left-to-Right (ltr) languages like English and Right-to-Left (rtl) languages like Arabic or Hebrew, physical CSS properties (margin-left, padding-right, border-left, left) quickly become a maintenance bottleneck. Every physical horizontal offset hardcodes an assumption that text starts on the left and flows to the right, forcing teams to maintain separate [dir="rtl"] override stylesheets that reset margin-left: 0 and apply margin-right instead.

The CSS Logical Properties and Values Level 1 specification solves this by replacing physical coordinates (top, right, bottom, left) with flow-relative axes tied to the document's dir and writing-mode:

Example

/* Legacy physical CSS requiring manual [dir="rtl"] overrides */
.callout-legacy {
  margin-bottom: 1.5rem;
  padding-left: 1rem;
  border-left: 4px solid #2563eb;
}

[dir="rtl"] .callout-legacy {
  padding-left: 0;
  padding-right: 1rem;
  border-left: 0;
  border-right: 4px solid #2563eb;
}

/* Flow-relative CSS Logical Properties: flips automatically in RTL */
.callout-logical {
  margin-block-end: 1.5rem;
  padding-inline-start: 1rem;
  border-inline-start: 4px solid #2563eb;
}

Input : UI components rendered across <html dir="ltr"> and <html dir="rtl"> locales
Output : Single-source stylesheets whose spacing, borders, and alignment mirror automatically with text direction.

Implementation

Below is a practical translation table and component stylesheet showing how physical properties map to their flow-relative logical equivalents across modern evergreen browsers (Chrome, Edge, Firefox, and Safari).

<!-- Switch dir="ltr" to dir="rtl" and the entire layout mirrors automatically -->
<section class="notification-banner" dir="rtl" lang="ar">
  <div class="notification-banner__icon" aria-hidden="true">!</div>
  <div class="notification-banner__content">
    <h2 class="notification-banner__title">تحديث إعدادات الحساب</h2>
    <p class="notification-banner__text">
      تم تفعيل المصادقة الثنائية لحمايةجلستك الحالية.
    </p>
  </div>
  <a class="notification-banner__action" href="#settings">الإعدادات</a>
</section>
.notification-banner {
  display: flex;
  align-items: center;
  /* max-width -> max-inline-size */
  max-inline-size: 42rem;
  /* margin-top / margin-bottom -> margin-block */
  margin-block: 1.5rem;
  /* margin-left / margin-right -> margin-inline */
  margin-inline: auto;
  /* padding-top/bottom and padding-left/right */
  padding-block: 1rem;
  padding-inline: 1.25rem;
  /* Accent bar always sits at the start of the reading axis */
  border-inline-start: 4px solid #0ea5e9;
  border-radius: 6px;
  background-color: #f8fafc;
  text-align: start;
}

.notification-banner__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* width / height -> inline-size / block-size */
  inline-size: 2rem;
  block-size: 2rem;
  /* Space between the icon and text regardless of LTR or RTL */
  margin-inline-end: 1rem;
  border-radius: 9999px;
  background-color: #e0f2fe;
  color: #0369a1;
  font-weight: 700;
}

.notification-banner__content {
  flex: 1;
}

.notification-banner__title {
  margin-block: 0 0.25rem;
  font-size: 1rem;
}

.notification-banner__text {
  margin-block: 0;
  color: #475569;
  font-size: 0.875rem;
}

.notification-banner__action {
  /* Push action link to the far end of the inline axis */
  margin-inline-start: 1rem;
  padding-block: 0.375rem;
  padding-inline: 0.75rem;
  border-radius: 4px;
  background-color: #0284c7;
  color: #ffffff;
  text-decoration: none;
  font-size: 0.875rem;
}

Main Point: Default to inline-start, inline-end, block-start, and block-end properties (margin-inline-start, padding-inline, border-inline-start, text-align: start) so your components adapt to both LTR and RTL languages without duplicating selector overrides.

Credits

Photo by Ed Stone

← Home