Skip to main content

Логічні властивості CSS

Логічні властивості CSS (CSS logical properties) прив'язують відступи, розміри та позиціонування до напрямку тексту, а не до фіксованих країв екрана.

Теорія

TL;DR

  • Уяви GPS, що автоматично перевертає "поверни ліворуч" на "поверни праворуч" для RTL-карти. Логічні властивості працюють так само.
  • margin-left завжди залишається зліва по екрану в RTL; margin-inline-start переходить вправо.
  • Одне правило CSS покриває LTR, RTL і вертикальний текст без [dir="rtl"]-перевизначень.
  • Використовуй логічні властивості якщо підтримуєш RTL або вертикальне письмо; фізичні підходять для простих LTR-інтерфейсів.
  • Підтримка браузерів: Chrome, Firefox, Safari (2020+), Edge 79+. IE не підтримується.

Швидкий приклад

css
/* Фізичне - потрібне дублювання для RTL */ .sidebar { border-left: 2px solid #ccc; } [dir="rtl"] .sidebar { border-left: none; border-right: 2px solid #ccc; /* окреме перевизначення */ } /* Логічне - одне правило для обох напрямків */ .sidebar { border-inline-start: 2px solid #ccc; /* в RTL автоматично стає правим бордером */ }

Логічна версія не знає про "ліво" і "право". Вона знає "початок інлайн-напрямку", що є лівом у LTR і правом у RTL.

Ключова різниця

Фізичні властивості (margin-left, top, border-right) прив'язані до фіксованих країв viewport. Вони не рухаються незалежно від мови. Логічні властивості (margin-inline-start, inset-block-start) обчислюються відносно поточного режиму письма: інлайн-вісь слідує напрямку тексту, блочна вісь слідує напрямку стекування рядків. Тому margin-inline-start стає margin-left у LTR і margin-right у RTL, та сама властивість, різна інструкція для браузера.

Коли застосовувати

  • Підтримка RTL (арабська, іврит, перська): логічні властивості скрізь.
  • Вертикальний текст (CJK, сайти в стилі манги): логічні + writing-mode: vertical-rl.
  • Глобальний продукт або дизайн-система: логічні за замовчуванням, фізичні тільки для SVG і декоративних елементів.
  • LTR-прототип що живе тиждень: фізичні, менше понять для розуміння.
  • Компоненти теми (MUI, Chakra, Bootstrap RTL): логічні для відступів що не залежать від напрямку.

Таблиця відповідностей

ФізичнаЛогічнаLTRRTLvertical-rl
margin-leftmargin-inline-startleftrighttop
margin-rightmargin-inline-endrightleftbottom
margin-topmargin-block-starttoptopright
padding-bottompadding-block-endbottombottomleft
widthinline-sizewidthwidthheight
heightblock-sizeheightheightwidth
float: leftfloat: inline-startleftrighttop
Колитільки LTR, legacyRTL/глобальні застосункиCJK вертикальні UI

Як браузери обчислюють логічні властивості

Браузер першочергово читає direction і writing-mode під час обчислення стилів, а потім розкладає логічні властивості відповідно до специфікації CSS Writing Modes Level 3. margin-inline-start стає margin-left у LTR і margin-right у RTL. Blink і WebKit кешують розкладені фізичні значення в дереві компонування, тому повторного розбору на зміну dir немає, якщо вже використовуються логічні властивості. Але сама зміна dir запускає повний перерахунок layout. Групуй DOM-зміни і використовуй transform для анімацій якщо перемикаєш напрямок в runtime.

Ще один момент, що часто здивовує: у border-radius немає класичних логічних еквівалентів. Нові властивості називаються border-start-start-radius, border-start-end-radius, border-end-start-radius, border-end-end-radius. Підтримка з'явилась в Chrome, Firefox та Safari приблизно в 2021 році.

Типові помилки

Змішування фізичних і логічних властивостей на одному елементі:

css
/* Неправильно - обидва застосовуються, відступ додається */ .box { margin-left: 10px; margin-inline-start: 20px; /* 30px в LTR, а не 20px */ } /* Правильно - обери одну систему */ .box { margin-inline-start: 20px; }

Логічне скорочення не перевизначає фізичне. Обидва обчислюються незалежно і додаються. Це часто здивовує розробників що мігрують кодову базу на логічні властивості.

Очікування що text-align: start центрує контент:

css
/* В RTL, start = правий бік. Не центр. */ p { text-align: start; } /* Вирівнювання вправо в RTL */ /* Для справжнього центру використовуй center - у нього немає логічного еквівалента */ p { text-align: center; }

Використання фізичного resize у вертикальному режимі письма:

css
/* Не дає корисного результату в writing-mode: vertical-rl */ textarea { resize: horizontal; } /* Правильно */ textarea { resize: inline; } /* Зміна розміру вздовж інлайн-осі */

Припущення що position: sticky однаково поводиться у вертикальному режимі:

В writing-mode: vertical-rl, position: sticky; inset-block-start: 0 прилипає до правого краю, бо block-start дорівнює right. Фізичне top: 0 ігнорує режим письма і прилипає до верху viewport. Я натрапив на це на CJK-дашборді де кожен sticky-заголовок прив'язувався до неправильного краю у вертикальному макеті. Перевіряй у RTL-симуляторі Chrome DevTools перед деплоєм.

Де застосовується в реальних проектах

  • Material-UI v6 використовує marginInline в системі тем для RTL-сумісних відступів в sx-пропсах.
  • Tailwind CSS v3.4+ відображає ms-4 на margin-inline-start і підтримує RTL через dir-плагін.
  • Bootstrap 5.3 використовує pe-3 (padding-inline-end) в RTL-білдах через data-bs-dir="rtl".
  • Ionic Framework використовує логічні float для підтримки іврит у гібридних iOS/Android застосунках.
  • Правило вибору: логічні якщо dir змінюється в runtime; фізичні для статичних LTR SVG або canvas.

Додай @supports (margin-inline-start: 0) для фізичного фолбеку якщо потрібна підтримка старих браузерів.

Питання з інтерв'ю

Q: Що відбувається з inline-size проти width в writing-mode: vertical-rl?
A: inline-size стає висотою, бо інлайн-вісь іде зверху вниз. width залишається шириною по екрану. Використовуй inline-size для манги або японських текстових макетів де осі поміняні місцями.

Q: Як логічні властивості взаємодіють з align-items у Flexbox?
A: align-items: start вирівнює по block-start краю, що є верхом у горизонтальному режимі і правом в vertical-rl. Осі Flexbox теж слідують режиму письма.

Q: Назви властивість без логічного еквівалента.
A: outline не має логічної форми. У border-radius тепер є логічні еквіваленти (border-start-start-radius тощо), але вони з'явились значно пізніше за основні логічні властивості і досі менш відомі.

Q: Зміна dir запускає reflow?
A: Так, повний перерахунок layout. Якщо перемикаєш LTR/RTL динамічно, групуй DOM-зміни і використовуй transform для анімацій щоб триматись біля 60fps.

Q: Складне питання: у shadow DOM з writing-mode: vertical-rl, як поводиться position: sticky; inset-block-start: 0 порівняно з фізичним top: 0?
A: Sticky-контейнер прилипає до правого краю, бо block-start дорівнює right в vertical-rl. Фізичне top: 0 ігнорує режим і прилипає до верху. Це не взаємозамінні варіанти, вони дають абсолютно різний результат.

Приклади

Порівняння: фізичне проти логічного в RTL

html
<!DOCTYPE html> <html dir="rtl"> <head> <style> .card-physical { margin-left: 20px; /* Залишається зліва по екрану в RTL */ border-left: 4px solid blue; /* Неправильний бік для RTL */ } .card-logical { margin-inline-start: 20px; /* В RTL переходить вправо */ border-inline-start: 4px solid blue; /* Бордер вправо в RTL */ } </style> </head> <body> <div class="card-physical">Фізична картка</div> <div class="card-logical">Логічна картка</div> </body> </html>

В RTL: фізична картка отримує лівий відступ і лівий бордер, неправильний бік для RTL-макета. Логічна картка автоматично переносить обидва вправо. Зміни dir="rtl" на dir="ltr" і обидві виглядають однаково. В цьому вся суть.

RTL-сумісний React-компонент

jsx
function Card({ title, children, dir = 'ltr' }) { return ( <div dir={dir} style={{ marginInlineStart: '2rem', // RTL: стає margin-right paddingBlock: '1rem', // Однаково в усіх режимах inlineSize: '300px', // RTL: все одно 300px ширини borderInlineStart: '5px solid blue' // RTL: бордер справа }}> <h3>{title}</h3> {children} </div> ); } // Використання <Card dir="rtl" title="مرحبا">Контент тут</Card> // Результат: синій бордер справа, 2rem відступ справа, 300px ширини

Material-UI v6 використовує саме такий патерн у своїй системі тем. marginInlineStart в sx-пропсі адаптується до dir на найближчому батьківському елементі без жодної додаткової RTL-конфігурації.

Вертикальний режим письма з логічними розмірами

css
.manga-panel { writing-mode: vertical-rl; /* інлайн-вісь = зверху вниз, блочна = справа наліво */ inline-size: 200px; /* стає висотою (інлайн іде вертикально) */ block-size: 100%; /* стає шириною */ margin-block-end: 20px; /* стає margin-left в vertical-rl */ }
html
<div class="manga-panel">縦書きテキスト</div>

Часта помилка: float: inline-start в writing-mode: vertical-rl відображається на float: top, якого legacy float не підтримує. Використовуй flexbox або grid для потоку елементів у вертикальному письмі.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.

Дочитали статтю?