Category: reference
CSS Logical Properties — Writing Mode Aware Layout
margin-inline, padding-block, inset-inline-start — เขียน CSS ที่รองรับ RTL และ vertical text โดยไม่ต้องเขียน rule ซ้ำ
สารบัญ
ทำไมต้องใช้ Logical Properties
CSS เดิมใช้ physical directions: left, right, top, bottom
ซึ่งไม่ทำงานถูกต้องกับ RTL languages (Arabic, Hebrew) หรือ vertical writing modes (Japanese)
/* ❌ Physical — พัง RTL */
.card { margin-left: 1rem; padding-left: 1.5rem; }
/* ✓ Logical — ทำงานถูกต้องทุก writing mode */
.card { margin-inline-start: 1rem; padding-inline-start: 1.5rem; }
Mapping พื้นฐาน
| Physical (เดิม) | Logical (ใหม่) |
|---|---|
margin-top | margin-block-start |
margin-bottom | margin-block-end |
margin-left | margin-inline-start |
margin-right | margin-inline-end |
margin-left + margin-right | margin-inline |
margin-top + margin-bottom | margin-block |
left | inset-inline-start |
right | inset-inline-end |
top | inset-block-start |
width | inline-size |
height | block-size |
min-width | min-inline-size |
max-height | max-block-size |
Inline vs Block Axis
| LTR / RTL text | Vertical text | |
|---|---|---|
| inline axis | แนวนอน (←→) | แนวตั้ง (↕) |
| block axis | แนวตั้ง (↕) | แนวนอน (←→) |
- inline-start = ซ้ายใน LTR, ขวาใน RTL, บนใน vertical
- inline-end = ขวาใน LTR, ซ้ายใน RTL, ล่างใน vertical
- block-start = บนใน horizontal, ซ้ายใน vertical LTR
Shorthand Syntax
/* Shorthand ใหม่ */
margin-inline: 1rem; /* margin-left + margin-right */
margin-block: 0.5rem 1rem; /* margin-top 0.5rem, margin-bottom 1rem */
padding-inline: 1.5rem;
padding-block: 1rem 1.5rem;
/* inset shorthand (แทน top/right/bottom/left) */
inset: 0; /* ทุกด้าน */
inset-block: 0; /* top + bottom */
inset-inline: 0 1rem; /* left 0, right 1rem */
Size Properties
/* ❌ Physical */
.button {
width: 100%;
min-height: 44px;
}
/* ✓ Logical */
.button {
inline-size: 100%;
min-block-size: 44px;
}
Border Radius
/* Physical corners */
border-top-left-radius: 8px;
border-top-right-radius: 8px;
/* Logical corners */
border-start-start-radius: 8px; /* top-left in LTR */
border-start-end-radius: 8px; /* top-right in LTR */
border-end-start-radius: 8px; /* bottom-left in LTR */
border-end-end-radius: 8px; /* bottom-right in LTR */
Float และ Text Align
/* ❌ Physical */
.pull-quote { float: left; text-align: left; }
/* ✓ Logical */
.pull-quote { float: inline-start; text-align: start; }
ตัวอย่างจริง: Card Component
/* ❌ Physical — ต้องเขียนซ้ำสำหรับ RTL */
.card {
padding: 1.5rem;
border-left: 4px solid #2563eb;
border-radius: 8px 0 0 8px;
}
/* RTL override */
[dir='rtl'] .card {
border-left: none;
border-right: 4px solid #2563eb;
border-radius: 0 8px 8px 0;
}
/* ✓ Logical — ทำงานถูกต้องทั้ง LTR และ RTL โดยไม่ต้อง override */
.card {
padding: 1.5rem;
border-inline-start: 4px solid #2563eb;
border-start-start-radius: 0;
border-end-start-radius: 0;
border-start-end-radius: 8px;
border-end-end-radius: 8px;
}
ตัวอย่างจริง: Positioned Element
/* ❌ Physical */
.tooltip {
position: absolute;
top: 100%;
left: 0;
}
/* ✓ Logical */
.tooltip {
position: absolute;
inset-block-start: 100%;
inset-inline-start: 0;
}
เมื่อไหรใช้ Logical vs Physical
ใช้ Logical เมื่อ:
- Layout ที่ต้องรองรับ RTL หรือหลายภาษา
- Spacing ที่เกี่ยวกับ flow direction (margin ข้างๆ text)
- Component library หรือ design system
ยังใช้ Physical ได้เมื่อ:
- Visual decoration ที่ไม่เกี่ยวกับ text flow
- เช่น:
border-top: 1px solid(เส้นด้านบนเสมอ ไม่ว่า writing mode ไหน) - Shadow, gradient direction ที่ specific
Browser Support
รองรับ Chrome 87+, Firefox 66+, Safari 14.1+ ทั้งหมดรองรับแล้วใน 2024+
Shorthand เช่น margin-inline รองรับ Chrome 87+, Firefox 66+, Safari 14.1+
/* Fallback pattern ถ้าต้องรองรับ browser เก่ามาก */
.element {
margin-left: 1rem; /* fallback */
margin-inline-start: 1rem; /* override สำหรับ browser ใหม่ */
}
Quick Reference
/* Spacing */
margin-inline: auto; /* center ใน flow */
padding-inline: 1rem; /* left+right padding */
padding-block: 0.5rem 1rem; /* top+bottom padding */
/* Positioning */
inset-inline-start: 0; /* left ใน LTR */
inset-block-start: 50%; /* top */
/* Sizing */
inline-size: 100%; /* width */
block-size: 200px; /* height */
min-inline-size: min-content;
/* Border */
border-inline-start: 2px solid; /* left border ใน LTR */
border-block-end: 1px solid; /* bottom border */
/* Text */
text-align: start; /* left ใน LTR */
text-align: end; /* right ใน LTR */