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: English, Spanish, French, etc.
- Right-to-left (RTL) languages: Arabic, Hebrew, Persian, etc.
- Top-to-bottom languages: Traditional Chinese, Japanese, Korean, etc.
Logical properties solve this by using flow-relative terms instead of physical directions:
- Inline: The direction text flows (left-to-right in English, right-to-left in Arabic)
- Block: The direction blocks stack (top-to-bottom in most languages)
- Start: The beginning of a flow
- End: The end of a flow
Key Insight: With logical properties, you define layout relative to text flow, not physical screen directions. This means your layout automatically adapts to different writing modes and directions.
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
/* 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;
}
/* 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
/* Block axis shorthands (top/bottom) */
.element {
margin-block: 10px; /* margin-block-start and margin-block-end */
padding-block: 15px; /* padding-block-start and padding-block-end */
border-block: 1px solid; /* border-block-start and border-block-end */
}
/* Inline axis shorthands (left/right in LTR) */
.element {
margin-inline: 20px; /* margin-inline-start and margin-inline-end */
padding-inline: 25px; /* padding-inline-start and padding-inline-end */
border-inline: 2px solid; /* border-inline-start and border-inline-end */
}
/* Individual border properties */
.element {
border-block-start-width: 1px;
border-block-start-style: solid;
border-block-start-color: black;
/* Shorthand */
border-block-start: 1px solid black;
}
Logical Values for Float and Clear
/* Physical values */
.float-left {
float: left;
}
.clear-right {
clear: right;
}
/* Logical values */
.float-start {
float: inline-start; /* left in LTR, right in RTL */
}
.clear-end {
clear: inline-end; /* right in LTR, left in RTL */
}
Text Alignment and Direction
Text Alignment
/* Physical alignment */
.align-left {
text-align: left;
}
.align-right {
text-align: right;
}
/* Logical alignment */
.align-start {
text-align: start; /* left in LTR, right in RTL */
}
.align-end {
text-align: end; /* right in LTR, left in RTL */
}
Direction and Writing Mode
/* Set text direction */
.rtl-text {
direction: rtl; /* Right to left */
}
.ltr-text {
direction: ltr; /* Left to right (default) */
}
/* 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 */
}
Note: When you change the writing mode, the meaning of inline and block also changes. In vertical writing modes, inline runs vertically and block runs horizontally.
Practical Examples
Bidirectional Navigation Menu
/* 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 */
.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 */
Card Component with Icon
/* 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 */
.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
Pro Tip: When building internationalized interfaces, test early and often with real content in different languages. What works well for Latin scripts might not work as well for Arabic, Hebrew, or Asian languages.
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
Final Thought: Logical properties represent a significant improvement in how we handle layout in CSS. As global audiences become increasingly important, building layouts that work seamlessly across different writing systems is no longer optional but essential.