РозробкаJunior

HTML та CSS

HTML і CSS — це дві мови, з яких складається будь-який вебінтерфейс, і шар, який найчастіше вважають простим. HTML — це не розмітка заради вигляду: кожен елемент є обіцянкою, за якою діють браузер і допоміжні технології. CSS — не список стилів, а алгоритм розв’язання конфліктів із визначеним порядком, і знання цього порядку перетворює вгадування на міркування.

Специфікує
WHATWG · W3C
Ворота каскаду
Четверо, по черзі
Інструменти розкладки
Flow · Flex · Grid

HTML — це набір обіцянок

<button> — це не коробка, схожа на кнопку. Вона отримує фокус із клавіатури, реагує на Enter і пробіл, оголошує себе кнопкою для зчитувача екрана, бере участь у надсиланні форми й доступна автоматизації браузера та шару доступності операційної системи. <div> з обробником кліку не має нічого з цього, а відтворити все це правильно — це рядків сорок, у яких ви припуститеся непомітних помилок.

За цим стоїть дерево доступності. Розбираючи ваш HTML, браузер поряд із DOM будує другу структуру, у якій кожен вузол має роль, ім’я, стан і набір підтримуваних дій. Зчитувачі екрана, голосове керування, режими читання в браузері та пошукові краулери читають саме це дерево, а не ваш CSS. Семантичні елементи наповнюють його правильно й безкоштовно; несемантичні лишають порожнім і потребують ручного заповнення через атрибути ARIA.

Дві речі дають більшу частину практичної користі. Заголовки мають описувати структуру документа, а не кегль тексту: багато людей переміщуються сторінкою, стрибаючи між заголовками, і сторінка, чий єдиний <h1> — це логотип, не дає їм нічого. І кожен елемент форми потребує пов’язаного <label>; плейсхолдер лейблом не є, бо зникає саме тоді, коли потрібен, і часто взагалі не озвучується.

Каскад — це алгоритм

Коли два оголошення задають одну властивість одного елемента, браузер не вгадує. Він проводить чотири порівняння у фіксованому порядку й зупиняється на першому, яке їх розрізняє. Майже на кожне питання «чому мій стиль не застосовується» відповідає розуміння того, на якому саме порівнянні ви програєте.

Коли кілька оголошень задають одну властивість одного елемента, браузер розв’язує конфлікт у фіксованому порядку: спершу джерело й важливість, потім шари каскаду, потім специфічність і лише тоді порядок у коді. Кожні ворота відсіюють кандидатів, і застосовується той, хто лишився останнім. Специфічність — треті ворота, а не перші, тому її підвищення зазвичай є лікуванням не тієї стадії.
ВоротаЩо порівнюєтьсяДе програють
1. Джерело й важливістьСтилі автора, користувача й браузера, де !important перевертає порядок між ними.!important у чужому стилі, який ви не писали.
2. Шари каскадуДо якого @layer належить правило; шари порівнюються в порядку оголошення.Дуже специфічний селектор у ранньому шарі програє простому в пізнішому.
3. СпецифічністьСпершу id, потім класи, атрибути й псевдокласи, потім елементи — порівнюються як три колонки, а не сумуються.Припущення, що одинадцять класів переможуть один id. Ні: колонку id перевіряють першою.
4. Порядок у кодіВиграє останнє відповідне оголошення в порядку коду.Складальник ставить ваші файли в інакшому порядку, ніж ви очікували.

Шари каскаду варто брати передусім з однієї причини: вони відділяють «наскільки сильно це має вигравати» від «наскільки точно це вибирає». Покладіть сторонній стиль у ранній шар, а власні перевизначення — у пізніший, і потреба нарощувати селектори зникне зовсім: один клас у пізнішому шарі переможе id у ранішому, бо другі ворота вирішуються раніше за треті.

Розкладка: flow, flex, grid

До будь-якої системи розкладки існує нормальний потік — поведінка документа взагалі без CSS. Блокові елементи складаються вниз сторінкою й займають доступну ширину; рядкові стоять уздовж рядка й переносяться. Чимало коду розкладки існує, щоб відтворити те, що нормальний потік уже робив, а найдешевша розкладка — та, якої ви не написали.

Flexbox — одна вісь

  • Розміри визначає вміст; контейнер розподіляє простір
  • Рядок або колонка, з переносом, якщо дозволите
  • Пасує панелям, рядкам кнопок, начинці карток
  • Вирівнювання вздовж і впоперек однієї осі

Grid — дві осі

  • Структуру визначає контейнер; вміст її заповнює
  • Рядки й колонки задані наперед, за бажання — іменами
  • Пасує структурі сторінки й будь-якій справді двовимірній розкладці
  • Елементи можна розміщувати й свідомо накладати

Правило вибору коротке: якщо ви шикуєте речі вздовж однієї лінії і розміри має визначати вміст — беріть flex; якщо ви задаєте структуру, у яку падає вміст, — беріть grid. Вони вільно поєднуються: сторінка на grid із flex усередині кожної клітинки — звичайний випадок, а суперечка про те, що «краще», дорівнює суперечці, чи молоток перемагає пилку.

Що прибрав сучасний CSS

Значна частина усталеної мудрості в цій темі — це поради до проблем, яких уже немає. Якщо ви вчили CSS за матеріалами приблизно до 2022 року, кілька з цього буде новим, і кожен пункт видаляє милицю, а не додає прийом.

  • Користувацькі властивості (--gap) — це справжні значення, які браузер обчислює під час роботи, тож вони каскадуються, реагують на медіазапити й читаються та задаються з JavaScript — на відміну від змінних препроцесора, яких на момент читання файлу браузером уже немає.
  • clamp() замінює більшість типографських шкал на брейкпоінтах: одне оголошення задає мінімум, плавну середину й максимум.
  • Контейнерні запити дозволяють компоненту реагувати на ширину власного контейнера, а не вікна, — а саме цього багаторазовому компоненту й бракувало весь час.
  • :has() вибирає батька за тим, що в ньому лежить, — той «батьківський селектор», який два десятиліття вважали неможливим.
  • Логічні властивості (margin-inline, padding-block) описують напрям відносно режиму письма, тож розкладка працює в мові справа наліво без дзеркального набору стилів.
  • gap працює і в flexbox, і в grid, і це прибирає останню причину вішати відступи на дітей, а потім знімати їх у першої чи останньої.

Що насправді коштує користувачеві

CSS блокує рендер за задумом: браузер не малюватиме, доки не отримає стилі для поточного медіа, бо намалювати спершу й перестилювати потім означало б показати всім нестилізований вміст. Саме тому розмір і кількість стилів у голові документа — це проблема першої відмальовки, а не пропускної здатності.

Два видимі збої варто назвати, бо обидва дешево попередити. Зсув розкладки стається, коли вміст приходить без зарезервованого місця: зображення без розмірів, шрифт, що підмінюється на інший за метрикою, рекламний блок, що виникає над тим, що людина читає. Зарезервуйте місце — і цього не буде. А «биття» розкладки стається, коли JavaScript у циклі читає геометричну властивість, пише стиль і читає знову, змушуючи браузер синхронно перераховувати розкладку на кожній ітерації; групуйте спершу читання, потім записи.

Як це виявляється в реальній поставці

Стилі стають непідтримуваними майже ніколи не через розмір. Причина в тому, що ніхто не може передбачити, що зламає видалення правила, — а це стається, коли селектори тягнуться через межі компонентів: правило у файлі шапки стилізує щось у підвалі, бо обидва підпали під .card h3. Хоч би яку методологію ви взяли, щоб цьому запобігти — конвенцію імен, CSS-модулі, скоуповані стилі у фреймворку чи шари плюс дисципліну, — властивість, яку ви купуєте, та сама: локальність, щоб зміна лишалася там, де ви її зробили.

Де це вироджується

  • Div з обробником кліку замість кнопки — невидимий для клавіатури й для будь-якої допоміжної технології.
  • outline: none на фокусі без заміни робить навігацію клавіатурою неможливою для відстеження.
  • Заголовки, обрані за розміром, руйнують структуру документа, за якою люди орієнтуються.
  • Гонка !important, де кожна сторона може відповісти лише ще одним.
  • Селектори, що тягнуться через межі компонентів, — жодне правило не можна безпечно видалити.
  • Магічні числа — margin-top: 37px — кодують один розмір екрана й ламаються на наступному.
  • Зображення без розмірів — текст стрибає під пальцем читача, поки сторінка вантажиться.

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

Застосовуйте, коли

  • Завжди — кожен фреймворк із цього списку зрештою зводиться до цих двох мов.
  • Для контентних сторінок беріть чистий HTML і CSS: фреймворк додасть витрат і жодної нової спроможності.
  • Беріть рідні елементи раніше за ARIA, а ARIA — лише щоб описати те, що ви справді реалізували.
  • Беріть шари каскаду, коли інтегруєте сторонні стилі, які не можете редагувати.

Уникайте, коли

  • Робити руками віджети, які вже є рідними: діалог, розкривний блок, поле дати.
  • Додавати методологію CSS у проєкт, достатньо малий, щоб локальність ще не була проблемою.
  • Відтворювати систему розкладки в JavaScript, бо слухач resize здався простішим за grid.
  • Оптимізувати швидкість селекторів — це не було справжнім вузьким місцем понад десять років.

Було корисно?

Поділіться з тим, хто працює над тією ж задачею.