CSS Logical Properties
Introduction to Logical Properties
CSS Logical Properties provide a way to control layout through logical, rather than physical, direction and dimension mappings. This makes creating internationalized layouts much easier, especially for languages that use different writing modes.
Why Logical Properties Matter
Traditional CSS properties like margin-left
or border-right
are based on physical directions. This creates challenges when supporting languages with different writing directions:
Left-to-right (LTR)
Languages that read from left to right.
Examples:
- English
- Spanish
- French
- German
- Italian
- Portuguese
Right-to-left (RTL)
Languages that read from right to left.
Examples:
- Arabic
- Hebrew
- Persian (Farsi)
- Urdu
- Kurdish
- Yiddish
Top-to-bottom
Languages that can be written vertically.
Examples:
- Traditional Chinese
- Japanese
- Korean
- Mongolian
The Problem with Physical Properties
When building multilingual websites, physical properties create several challenges:
Without Logical Properties
/* LTR Styles */
.sidebar {
float: left;
margin-right: 20px;
border-right: 1px solid gray;
text-align: left;
}
/* RTL Styles - Duplicate code needed */
[dir="rtl"] .sidebar {
float: right;
margin-left: 20px;
margin-right: 0;
border-left: 1px solid gray;
border-right: none;
text-align: right;
}
- Duplicate code maintenance
- Easy to miss properties when updating
- Complex selectors with direction attributes
- Prone to inconsistencies
With Logical Properties
/* Works for both LTR and RTL */
.sidebar {
float: inline-start;
margin-inline-end: 20px;
border-inline-end: 1px solid gray;
text-align: start;
}
/* No duplicate code needed! */
- Single codebase for all languages
- Automatically adapts to writing direction
- Simpler maintenance
- More robust internationalization
Logical Property Concepts
Logical properties use these key concepts to replace physical directions:
Logical Concept | Description | LTR Equivalent | RTL Equivalent | Vertical Writing Mode |
---|---|---|---|---|
Inline | The direction text flows within a line | Horizontal (left-to-right) | Horizontal (right-to-left) | Vertical |
Block | The direction blocks stack | Vertical (top-to-bottom) | Vertical (top-to-bottom) | Horizontal |
Start | The beginning of a flow | Left | Right | Top (or side, depending on writing mode) |
End | The end of a flow | Right | Left | Bottom (or side, depending on writing mode) |
Historical Context
CSS Logical Properties evolved from the need to better support international layouts:
- Early CSS (1990s): Focused primarily on LTR languages with physical properties only
- CSS 2.1 (2011): Added
direction
andunicode-bidi
properties, but still required duplicate styles - CSS Writing Modes Level 3 (2015): Introduced logical properties as a working draft
- CSS Logical Properties Level 1 (2018-present): Formalized the specification, now widely implemented
Physical vs. Logical Properties
Mapping Physical to Logical Properties
Physical Property | Logical Property | LTR Equivalent | RTL Equivalent |
---|---|---|---|
margin-top |
margin-block-start |
margin-top |
margin-top |
margin-bottom |
margin-block-end |
margin-bottom |
margin-bottom |
margin-left |
margin-inline-start |
margin-left |
margin-right |
margin-right |
margin-inline-end |
margin-right |
margin-left |
padding-top |
padding-block-start |
padding-top |
padding-top |
padding-bottom |
padding-block-end |
padding-bottom |
padding-bottom |
padding-left |
padding-inline-start |
padding-left |
padding-right |
padding-right |
padding-inline-end |
padding-right |
padding-left |
border-top |
border-block-start |
border-top |
border-top |
border-bottom |
border-block-end |
border-bottom |
border-bottom |
border-left |
border-inline-start |
border-left |
border-right |
border-right |
border-inline-end |
border-right |
border-left |
Dimension Properties
Physical Property | Logical Property | LTR Equivalent |
---|---|---|
width |
inline-size |
width |
height |
block-size |
height |
min-width |
min-inline-size |
min-width |
min-height |
min-block-size |
min-height |
max-width |
max-inline-size |
max-width |
max-height |
max-block-size |
max-height |
Using Logical Properties
Basic Usage
Physical Properties
/* Traditional physical properties */
.box-physical {
margin-top: 10px;
margin-right: 20px;
margin-bottom: 10px;
margin-left: 20px;
padding-top: 15px;
padding-right: 25px;
padding-bottom: 15px;
padding-left: 25px;
border-top: 1px solid black;
border-right: 2px solid black;
border-bottom: 1px solid black;
border-left: 2px solid black;
}
Logical Properties
/* Equivalent logical properties */
.box-logical {
margin-block-start: 10px;
margin-inline-end: 20px;
margin-block-end: 10px;
margin-inline-start: 20px;
padding-block-start: 15px;
padding-inline-end: 25px;
padding-block-end: 15px;
padding-inline-start: 25px;
border-block-start: 1px solid black;
border-inline-end: 2px solid black;
border-block-end: 1px solid black;
border-inline-start: 2px solid black;
}
Shorthand Properties
CSS Logical Properties offer convenient shorthands similar to their physical counterparts:
Block Axis Shorthands
Controls the block direction (usually top/bottom in horizontal writing modes):
/* Block axis shorthands */
.element {
/* Sets both block-start and block-end */
margin-block: 10px;
padding-block: 15px;
border-block: 1px solid;
/* Individual sides with values */
margin-block: 10px 20px; /* start end */
padding-block: 15px 25px; /* start end */
}
Inline Axis Shorthands
Controls the inline direction (left/right in LTR, right/left in RTL):
/* Inline axis shorthands */
.element {
/* Sets both inline-start and inline-end */
margin-inline: 20px;
padding-inline: 25px;
border-inline: 2px solid;
/* Individual sides with values */
margin-inline: 20px 30px; /* start end */
padding-inline: 25px 35px; /* start end */
}
Individual Border Properties
You can control individual aspects of borders using logical properties:
/* Individual border properties */
.element {
/* Long-form individual properties */
border-block-start-width: 1px;
border-block-start-style: solid;
border-block-start-color: black;
/* Shorthand for a single edge */
border-block-start: 1px solid black;
/* Different borders for different edges */
border-block-start: 2px solid blue;
border-inline-end: 1px dashed red;
border-block-end: 2px dotted green;
border-inline-start: 1px solid orange;
}
Logical Values for Float and Clear
Float and clear properties also have logical counterparts:
Physical Values
/* Physical values */
.float-left {
float: left;
}
.clear-right {
clear: right;
}
Logical Values
/* Logical values */
.float-start {
float: inline-start; /* left in LTR, right in RTL */
}
.clear-end {
clear: inline-end; /* right in LTR, left in RTL */
}
Logical Properties for Layout
Logical properties are particularly useful for layout components:
Navigation Bar Example
/* Logical navigation bar */
.navbar {
display: flex;
padding-block: 1rem;
padding-inline: 2rem;
background-color: #f8f9fa;
}
.navbar-brand {
margin-inline-end: 2rem;
font-weight: bold;
}
.navbar-nav {
display: flex;
gap: 1rem;
}
/* Works in both LTR and RTL without changes */
Card Component Example
/* Logical card component */
.card {
border-radius: 8px;
border: 1px solid #dee2e6;
overflow: hidden;
}
.card-header {
padding-block: 1rem;
padding-inline: 1.5rem;
border-block-end: 1px solid #dee2e6;
background-color: #f8f9fa;
}
.card-body {
padding-block: 1.5rem;
padding-inline: 1.5rem;
}
.card-footer {
padding-block: 1rem;
padding-inline: 1.5rem;
border-block-start: 1px solid #dee2e6;
background-color: #f8f9fa;
}
Real-World Use Case: Multilingual Form
Here's a practical example of a form that works in both LTR and RTL languages:
/* Multilingual form using logical properties */
.form-group {
margin-block-end: 1.5rem;
}
.form-label {
display: block;
margin-block-end: 0.5rem;
font-weight: 500;
}
.form-control {
display: block;
width: 100%;
padding-block: 0.5rem;
padding-inline: 0.75rem;
border: 1px solid #ced4da;
border-radius: 0.25rem;
}
.form-text {
display: block;
margin-block-start: 0.25rem;
font-size: 0.875rem;
color: #6c757d;
}
.form-check {
display: flex;
align-items: center;
}
.form-check-input {
margin-inline-end: 0.5rem;
}
.btn-submit {
padding-block: 0.5rem;
padding-inline: 1rem;
background-color: #0d6efd;
color: white;
border: none;
border-radius: 0.25rem;
cursor: pointer;
}
LTR Form Preview
RTL Form Preview
Text Alignment and Direction
Text Alignment
CSS provides logical values for text alignment that automatically adapt to the text direction:
Physical Alignment
/* Physical alignment */
.align-left {
text-align: left;
}
.align-right {
text-align: right;
}
.align-center {
text-align: center;
}
.align-justify {
text-align: justify;
}
Logical Alignment
/* Logical alignment */
.align-start {
text-align: start; /* left in LTR, right in RTL */
}
.align-end {
text-align: end; /* right in LTR, left in RTL */
}
/* These remain the same */
.align-center {
text-align: center;
}
.align-justify {
text-align: justify;
}
LTR Example
This text is aligned to the start (left in LTR).
This text is aligned to the end (right in LTR).
This text is centered.
This is justified text. It will stretch to fill the width of the container, creating even left and right edges. This is commonly used for long paragraphs of text in print media and some websites.
RTL Example
هذا النص محاذى إلى البداية (اليمين في RTL).
هذا النص محاذى إلى النهاية (اليسار في RTL).
هذا النص في الوسط.
هذا نص مبرر. سيمتد لملء عرض الحاوية ، مما يؤدي إلى حواف يمنى ويسرى متساوية. يستخدم هذا بشكل شائع للفقرات الطويلة من النص في وسائل الإعلام المطبوعة وبعض مواقع الويب.
Direction and Writing Mode
CSS provides properties to control text direction and writing mode:
Direction Property
/* Set text direction */
.rtl-text {
direction: rtl; /* Right to left */
}
.ltr-text {
direction: ltr; /* Left to right (default) */
}
/* Often used with unicode-bidi */
.rtl-text-bidi {
direction: rtl;
unicode-bidi: bidi-override;
}
Writing Mode Property
/* Set writing mode */
.horizontal-tb {
writing-mode: horizontal-tb; /* Default: horizontal, top to bottom */
}
.vertical-rl {
writing-mode: vertical-rl; /* Vertical, right to left */
}
.vertical-lr {
writing-mode: vertical-lr; /* Vertical, left to right */
}
/* With text orientation */
.vertical-upright {
writing-mode: vertical-rl;
text-orientation: upright; /* Characters upright */
}
Writing Mode Examples
horizontal-tb (Default)
This is the default writing mode used in most languages. Text flows horizontally from left to right (or right to left in RTL languages) and blocks stack from top to bottom.
vertical-rl
This writing mode is used in traditional East Asian typography. Text flows vertically from top to bottom, and blocks stack from right to left. Common in traditional Chinese, Japanese, and Korean texts.
vertical-lr
Similar to vertical-rl, but blocks stack from left to right. This is less common in traditional typography but can be used for creative layouts or for languages like Mongolian.
Text Orientation in Vertical Writing Modes
When using vertical writing modes, you can control how characters are oriented:
text-orientation: mixed
Mixed (default): Characters from horizontal-only scripts are rotated sideways. 漢字 remain upright.
{
writing-mode: vertical-rl;
text-orientation: mixed;
}
text-orientation: upright
Upright: All characters are displayed upright, including those from horizontal-only scripts.
{
writing-mode: vertical-rl;
text-orientation: upright;
}
text-orientation: sideways
Sideways: All characters are rotated sideways, including those from vertical scripts like 漢字.
{
writing-mode: vertical-rl;
text-orientation: sideways;
}
Real-World Use Case: Multilingual Navigation
Here's how logical properties can be used to create a navigation menu that works in both LTR and RTL contexts:
/* Multilingual navigation with logical properties */
.nav {
display: flex;
padding-block: 1rem;
padding-inline: 1.5rem;
background-color: #f8f9fa;
border-block-end: 1px solid #dee2e6;
}
.nav-brand {
font-weight: bold;
margin-inline-end: 2rem;
}
.nav-items {
display: flex;
gap: 1.5rem;
}
.nav-item {
position: relative;
}
/* Dropdown menu */
.dropdown-menu {
position: absolute;
top: 100%;
inset-inline-start: 0; /* Logical version of left/right */
min-width: 10rem;
padding-block: 0.5rem;
padding-inline: 0;
margin-block-start: 0.125rem;
background-color: white;
border: 1px solid rgba(0, 0, 0, 0.15);
border-radius: 0.25rem;
}
.dropdown-item {
display: block;
padding-block: 0.25rem;
padding-inline: 1rem;
text-align: start;
}
LTR Navigation Preview
RTL Navigation Preview
Combining Direction and Logical Properties
The real power comes when combining the dir
attribute or direction
property with logical CSS properties:
/* HTML */
<div class="container">
<div class="card" dir="ltr">...</div>
<div class="card" dir="rtl">...</div>
</div>
/* CSS - Same styles work for both directions */
.card {
padding-block: 1rem;
padding-inline: 1.5rem;
border-start-start-radius: 0.5rem;
border-start-end-radius: 0.5rem;
border-end-start-radius: 0.5rem;
border-end-end-radius: 0.5rem;
box-shadow: 0.25rem 0 0.5rem rgba(0, 0, 0, 0.1);
}
Interactive Logical Properties Demo
This interactive demo allows you to experiment with CSS logical properties in different writing modes and directions. Toggle between settings to see how the same CSS adapts to different contexts.
Box Model Demo
This box demonstrates how logical properties affect the box model (margin, padding, border).
padding-block: 1rem padding-inline: 1.5rem margin-block: 1rem margin-inline: 1.5rem border-block: 2px solid border-inline: 4px solid border-start-start-radius: 12px border-end-end-radius: 12px
This text is aligned to the start.
This text is aligned to the end.
This text is always aligned left.
This text is always aligned right.
This paragraph demonstrates how elements float using logical properties. The blue boxes use float: inline-start
and float: inline-end
, which adapt to the text direction.
Practical Examples
Bidirectional Navigation Menu
LTR Navigation (English)
RTL Navigation (Arabic)
/* HTML */
<nav class="main-nav">
<ul>
<li><a href="#">Home</a></li>
<li><a href="#">About</a></li>
<li><a href="#">Services</a></li>
<li><a href="#">Contact</a></li>
</ul>
</nav>
/* CSS with logical properties */
.main-nav ul {
display: flex;
list-style: none;
padding-inline-start: 0; /* Removes default padding */
margin-block: 0; /* Removes top and bottom margins */
}
.main-nav li:not(:last-child) {
margin-inline-end: 20px; /* Space between items */
}
.main-nav a {
padding-block: 10px;
padding-inline: 15px;
border-inline-start: 3px solid transparent;
}
.main-nav a:hover {
border-inline-start-color: blue;
}
/* This menu will work correctly in both LTR and RTL contexts */
dir="rtl"
on the HTML element), all spacing, borders, and alignment automatically adjust to match the reading direction.
Card Component with Icon
LTR Card (English)
Feature Title
This is a description of the amazing feature that our product offers.
RTL Card (Arabic)
عنوان الميزة
هذا وصف للميزة الرائعة التي يقدمها منتجنا.
/* HTML */
<div class="card">
<div class="card-icon">
<i class="icon"></i>
</div>
<div class="card-content">
<h3>Card Title</h3>
<p>Card description text goes here.</p>
</div>
</div>
/* CSS with logical properties */
.card {
display: flex;
padding: 15px;
border-radius: 8px;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
}
.card-icon {
margin-inline-end: 15px; /* Space between icon and content */
}
.card-content {
padding-inline-start: 10px;
border-inline-start: 2px solid #eee;
}
/* In LTR: Icon on left, content on right */
/* In RTL: Icon on right, content on left */
Form Layout
/* HTML */
<form class="contact-form">
<div class="form-group">
<label for="name">Name:</label>
<input type="text" id="name">
</div>
<div class="form-group">
<label for="email">Email:</label>
<input type="email" id="email">
</div>
<div class="form-actions">
<button type="submit">Submit</button>
<button type="reset">Reset</button>
</div>
</form>
/* CSS */
.form-group {
margin-block-end: 15px;
display: flex;
flex-wrap: wrap;
}
.form-group label {
flex: 0 0 100px;
text-align: end;
padding-inline-end: 10px;
}
.form-group input {
flex: 1;
min-inline-size: 200px;
}
.form-actions {
margin-inline-start: 100px; /* Align with inputs */
padding-block-start: 10px;
}
.form-actions button:first-child {
margin-inline-end: 10px;
}
Logical Properties in Grid and Flexbox
Grid Layout with Logical Properties
.grid-container {
display: grid;
grid-template-columns: repeat(3, 1fr); /* Still using columns */
gap: 20px;
}
/* Using logical properties for item placement */
.header {
grid-column: 1 / -1; /* Spans all columns */
padding-block: 20px;
border-block-end: 1px solid #ddd;
}
.sidebar {
grid-row: 2 / 4;
padding-inline: 15px;
border-inline-end: 1px solid #ddd;
}
.content {
grid-column: 2 / -1;
padding: 20px;
}
.footer {
grid-column: 1 / -1;
padding-block: 20px;
border-block-start: 1px solid #ddd;
}
Flexbox with Logical Properties
.flex-container {
display: flex;
flex-direction: row; /* Default */
justify-content: space-between;
padding-block: 20px;
padding-inline: 15px;
}
.flex-item {
margin-inline-end: 10px;
padding-inline: 15px;
border-inline-start: 2px solid #ddd;
}
.flex-item:last-child {
margin-inline-end: 0;
}
/* For RTL support, no changes needed to the flex layout */
/* Just add dir="rtl" to the HTML element or set direction: rtl; in CSS */
Browser Support and Fallbacks
Current Browser Support
Logical properties have good support in modern browsers, but you may need fallbacks for older browsers:
- Chrome: Full support since version 89
- Firefox: Full support since version 66
- Safari: Full support since version 15
- Edge: Full support since version 89
Providing Fallbacks
/* Method 1: Cascade - Physical properties first, then logical */
.element {
/* Fallback for older browsers */
margin-left: 20px;
margin-right: 20px;
/* Modern browsers will use these */
margin-inline-start: 20px;
margin-inline-end: 20px;
}
/* Method 2: Feature detection with @supports */
.element {
/* Fallback for all browsers */
margin-left: 20px;
margin-right: 20px;
}
@supports (margin-inline-start: 20px) {
.element {
margin-left: 0; /* Reset physical property */
margin-right: 0;
margin-inline-start: 20px;
margin-inline-end: 20px;
}
}
Using PostCSS for Automatic Fallbacks
The postcss-logical plugin can automatically generate physical fallbacks for logical properties:
/* Your CSS with logical properties */
.element {
margin-inline: 20px;
padding-block: 10px;
border-inline-start: 1px solid black;
}
/* After PostCSS processing */
.element {
margin-left: 20px;
margin-right: 20px;
padding-top: 10px;
padding-bottom: 10px;
border-left: 1px solid black;
margin-inline: 20px;
padding-block: 10px;
border-inline-start: 1px solid black;
}
/* In RTL contexts, the physical fallbacks may be incorrect,
but the logical properties will work correctly */
Best Practices
When to Use Logical Properties
- Multilingual websites that support both LTR and RTL languages
- International applications where content direction may change
- Components that need to adapt to different writing modes
- Design systems that aim for maximum flexibility and reusability
Migration Strategy
- Start with new components: Apply logical properties to new code first
- Identify direction-sensitive components: Focus on components that need to work in multiple writing directions
- Use automated tools: Consider using PostCSS or similar tools to help with the transition
- Test thoroughly: Verify layouts in both LTR and RTL contexts
Common Pitfalls
- Mixing logical and physical properties: Be consistent to avoid confusion
- Forgetting about images and icons: These may need to be flipped or adjusted for RTL
- Assuming all languages read top-to-bottom: Some languages use vertical writing modes
- Hardcoding values in JavaScript: Ensure JS also respects the document direction
Resources and Further Reading
Documentation
- MDN: CSS Logical Properties and Values
- W3C: CSS Logical Properties and Values Level 1
- Can I Use: CSS Logical Properties
Tools
- PostCSS Logical Properties
- RTLCSS - Framework for converting LTR CSS to RTL
- PostCSS RTLCSS - PostCSS plugin for RTL transformation
Articles and Tutorials
- web.dev: Logical Properties
- CSS-Tricks: CSS Logical Properties
- Smashing Magazine: Understanding Logical Properties And Values