Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Що таке методологія BEM (блок елемент модифікатор)». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**BEM (Block Element Modifier)** - конвенція іменування (naming convention) CSS-класів, де класи слідують шаблону `block__element--modifier`. ```css .card { } /* Block - самостійний компонент */ .card__title { } /* Element - існує тільки всередині .card */ .card--featured { } /* Модифікатор блоку - варіація */ .card__title--large { } /* Модифікатор елемента */ ``` **Головне:** `.card__title--large` ніколи не зіткнеться з `.nav__title--large`. Назва сама є простором імен.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**BEM (Block Element Modifier)** - конвенція іменування CSS-класів, де кожен клас слідує шаблону `block__element--modifier`, щоб запобігти конфліктам стилів у великих проєктах. ## Теорія ### TL;DR - Block = самостійна UI-одиниця (`button`). Element = частина, що існує тільки всередині блоку (`button__icon`). Modifier = варіація або стан (`button--primary`). - Як LEGO: block це основна деталь, element кріпиться тільки до неї, modifier змінює її вигляд. - Головне: `.menu__item--active` стосується тільки меню і ніколи не зіткнеться з `.button--active`. - Використовуй BEM у команді від 5+ розробників або при CSS понад 10 тисяч рядків. Для маленьких прототипів і CSS-in-JS не потрібно. ### Швидкий приклад ```html <button class="button button--primary"> <span class="button__icon">★</span> Натисни </button> ``` ```css .button { padding: 10px; border: 1px solid; } /* Block */ .button__icon { display: inline-block; margin-right: 5px; } /* Element */ .button--primary { background: blue; color: white; } /* Модифікатор блоку */ .button__icon--large { font-size: 20px; } /* Модифікатор елемента */ ``` Назва класу сама описує структуру. `button__icon--large` - велика іконка всередині кнопки. Не більше. ### Ключова різниця Клас `.active` - глобальний. Злий три гілки коду і отримаєш три різні правила `.active`, що борються між собою. Це найпоширеніший CSS-конфлікт у командних проєктах. BEM дає простір імен для всього: `.card--active`, `.menu__item--active`, `.button--active` - три незалежних селектори, які не перетинаються. ### Коли використовувати - Команда від 5+ людей або CSS понад 10k рядків: BEM-іменування запобігає конфліктам при злитті гілок. - **Бібліотеки компонентів для повторного використання**: елементи прив'язані до блоку, немає семантичного дрейфу з часом. - Vanilla CSS без білд-тулів: BEM дає ізоляцію без PostCSS або Webpack. - CSS-in-JS (Styled Components, Emotion): пропускай BEM, бібліотека сама хешує класи. - **Tailwind CSS**: пропускай BEM, утилітарні класи замінюють будь-які конвенції іменування. - Маленький соло-проєкт до 5 файлів: прості класи писати швидше, оверхед BEM не виправданий. ### Порівняння | Аспект | BEM | Flat CSS (`.btn.active`) | CSS Modules | |---|---|---|---| | Іменування | `block__element--mod` | `.class`, `.state` | `Button_module__root` | | Масштабованість | Висока (простір імен) | Низька (глобальні колізії) | Висока (хешування при збірці) | | Розмір команди | 5+ розробників | Соло або мала команда | Будь-який | | Дебаг | DevTools показує ієрархію | Шукай глобальні стилі | Безпечно, але назви нечитабельні | | Найкраще для | Vanilla або командний CSS | Прототипи | React/Vue компоненти | ### Як браузер обробляє BEM Жодної магії. Браузер читає BEM-класи як звичайні CSS-селектори. `.button__element` має специфічність (0,1,0), тобто рівно стільки ж, скільки й будь-який одиночний клас. Ось і все. Структура закодована в назві, а не в каскаді чи shadow DOM. CSS пишуть плоско, ніяких `.button .button__icon {}`. ### Типові помилки **Вкладені селектори в CSS:** ```css /* Неправильно - ламається без PostCSS, суперечить BEM */ .button { .icon { color: red; } } /* Правильно - завжди плоскі селектори */ .button__icon { color: red; } ``` **Занадто довгий ланцюжок модифікаторів:** ```css /* Неправильно - важко читати і перевизначити */ .button--primary--large--rounded { } /* Правильно - окремі класи, комбінуй в HTML */ .button--primary.button--large { } ``` **Вкладені елементи:** ```css /* Неправильно - BEM іде тільки на один рівень для елементів */ .header__nav__link { } /* Правильно - link це елемент nav */ .nav__link { } ``` **Очікування, що модифікатор блоку вплине на модифікатор елемента:** ```css .card { transition: opacity 0.3s; } .card--loading { opacity: 0.5; } /* Впливає на блок */ .card__spinner--fast { animation: spin 1s infinite; display: block; } /* Реальність: спінер з --fast крутиться незалежно від .card--loading. * Модифікатори блоку і елемента - незалежні селектори. * Щоб сховати спінер під час завантаження, пиши явно: * .card--loading .card__spinner { display: none; } */ ``` ### Де зустрічається - **Yandex** (де народився BEM) використовує його в кодовій базі понад 1 мільйон рядків: `search__input--focused`. - **BBC News** застосовує для модульних шаблонів: `article__headline--breaking`. - **Shopify themes** дотримуються BEM-іменування: `product-form__input--error`. - **Google AMP** використовує послідовно: `amp-form__submit-button--disabled`. ### Питання на співбесіді **Q:** Поясни block, element і modifier на прикладі e-commerce. **A:** Block - `cart`. Element - `cart__item` (рядок у кошику). Modifier - `cart__item--out-of-stock` (перекреслена ціна, сірий текст). Кошик може бути де завгодно на сторінці. Item має сенс тільки всередині кошика. **Q:** Як специфічність BEM порівняно зі звичайними класами? **A:** `.block__element` має специфічність (0,1,0), як і `.element`. BEM сам по собі не підвищує вагу селектора. Захист дає унікальна назва, а не специфічність. `!important` не потрібен. **Q:** Чи варто використовувати BEM у React-проєкті з CSS Modules? **A:** Зазвичай ні. CSS Modules хешують назви класів при збірці, тому `.button` в одному файлі ніколи не зіткнеться з `.button` в іншому. BEM додасть багатослівності без вирішення проблеми, яку Modules вже вирішують. **Q:** (Senior) Якщо блок має модифікатор і елемент всередині теж має модифікатор, один впливає на інший? **A:** Ні. `.card--loading` змінює блок. `.card__spinner--fast` змінює елемент. Це незалежні селектори, браузер застосовує обидва. Якщо хочеш зупинити спінер під час завантаження, пиши явне правило: `.card--loading .card__spinner { display: none; }`. ## Приклади ### Базовий компонент кнопки ```html <button class="button button--primary"> <span class="button__icon">★</span> Підтвердити </button> <button class="button button--secondary"> Скасувати </button> ``` ```css .button { padding: 10px 20px; border: 1px solid transparent; cursor: pointer; } .button__icon { display: inline-block; margin-right: 6px; } .button--primary { background: #0057ff; color: #fff; } .button--secondary { background: #e0e0e0; color: #333; } ``` Дві кнопки, один блок, два модифікатори. Жоден стиль не виходить за межі `.button`. ### Картка товару в інтернет-магазині ```html <article class="product-card product-card--featured"> <img class="product-card__image" src="shirt.jpg" alt="Футболка"> <h3 class="product-card__title">Бавовняна футболка</h3> <div class="product-card__price product-card__price--sale">$19.99</div> <button class="product-card__button product-card__button--add">Додати до кошика</button> </article> ``` ```css .product-card { display: flex; flex-direction: column; max-width: 300px; } .product-card__image { width: 100%; height: 200px; object-fit: cover; } .product-card__title { font-size: 1.2em; margin: 10px 0; } .product-card__price { font-weight: bold; color: green; } .product-card__price--sale { color: red; text-decoration: line-through; } .product-card__button { padding: 10px; background: #007bff; color: #fff; border: none; } .product-card__button--add:hover { background: #0056b3; } ``` `--featured` на блоці дає змогу додати рамку або бейдж через один клас без зміни стилів елементів. `--sale` на `__price` робить ціну червоною з перекресленням. Жодне правило не потребує специфічності вищої за один клас.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.