Введение: конец войны методологий
АААААААААААА!!! 15 МИНУТ МОЕЙ ЖИЗНИ ТОЛЬКО ЧТО УШЛИ НА ПРИДУМЫВАНИЕ ИМЕНИ ГРЁБАНОМУ DIV-КОНТЕЙНЕРУ!
Знакомо, да? Не я один, кто неистово бился головой о клавиатуру, пытаясь придумать, как назвать очередную обертку для обертки внутри обертки?
Я УСТАЛ. Мы все устали. Устали от:
-
Бесконечного
.header__nav-container__menu-wrapper__item-list__element😵💫 -
Спора на код-ревью о том, должен ли это быть
block__elementили просто новыйblock🤬 -
«Не используй margin на блоке! Это нарушает принципы БЭМ!» — и последующего создания еще одного контейнера 🤦♂️
-
Конфликтов имён классов в разных компонентах ⚔️
-
А потом приходит Tailwind и превращает твой HTML в нечитаемую простыню из 20 классов на элемент 📜
«Я просто хотел сверстать карточку товара, а закончил философским вопросом о природе существования блоков и элементов.»
В какой-то момент я понял, что трачу больше времени на придумывание названий классов, чем на написание самого CSS. И подозреваю, что не я один такой.
Но что, если я скажу, что можно прекратить эти мучения?
В этой статье я расскажу, как я наконец-то перестал биться в конвульсиях при создании очередного div’а и нашел баланс между структурированностью БЭМа и удобством утилитарного подхода Tailwind. Больше никаких религиозных войн и догматизма — только прагматизм и эффективность.
Проблемы чистого БЭМа в реальном мире
БЭМ — отличная методология, которая решает множество проблем большого проекта. Ага, и создает тысячу новых. Но давайте будем честными, у неё есть свои недостатки:
<!-- Ад нейминга --> <div class="content-block"> <div class="content-block__wrapper"> <div class="content-block__wrapper-inner"> <div class="content-block__wrapper-inner-container"> <!-- Наконец-то контент! Осталось только пробраться через эти девять кругов ада нейминга --> </div> </div> </div> </div>
-
Мучительный нейминг для вспомогательных элементов и контейнеров (Серьезно, кто придумал, что все должно иметь осмысленное имя? Моя кошка и та не страдает, когда я называю её «кис-кис-кис»)
-
Проблема с отступами — в чистом БЭМе блок не должен иметь margin, поэтому приходится создавать дополнительные обертки (Потому что, видите ли, margin — это как НЛО: все знают, что они существуют, но никто не признается в их использовании)
-
Раздутая разметка из-за множества уровней вложенности (Ничто так не поднимает самооценку, как ощущение, что ты архитектор, спроектировавший Бурдж-Халифу из div’ов)
-
Сложность переиспользования для позиционирования — приходится создавать множество модификаторов (block_position-top_margin-left_slightly-to-the-right-no-not-that-right-a-bit-more… идеально!)
С другой стороны, чистый Tailwind часто приводит к «салянке» классов, потере семантики и усложнению чтения HTML. (Потому что ничто не говорит «я знаю, что делаю» лучше, чем 42 класса на одном элементе)
Гибридный подход: когда что использовать
1. Используй БЭМ с SCSS и @apply, когда:
-
Имеешь дело с семантически очевидными компонентами:
.product-card,.user-profile,.catalog(Ключевое слово: «очевидными». Если ты полчаса думаешь, как назвать div, это уже не очевидно, Капитан Очевидность!) -
Работаешь с компонентами с богатой внутренней структурой (Как в большой семье — каждый элемент должен знать своё место и родословную до пятого колена)
-
Создаешь переиспользуемые компоненты с разными вариациями (Потому что DRY расшифровывается как «Don’t Repeat Yourself», а не «Damn, Repeat Yelp!»)
// SCSS с использованием @apply для утилит Tailwind .product-card { @apply bg-white rounded-lg shadow-sm overflow-hidden; // 👆 Смотри-ка! Одна строка вместо 10 строк CSS! Какая экономия, прямо как в рекламе стирального порошка! &__image { @apply w-full object-cover aspect-video; } &__body { @apply p-4; } &__title { @apply text-lg font-medium text-gray-900; } &__price { @apply text-primary-600 font-bold mt-2; // Ой, margin-top! Не показывайте это БЭМ-пуристам 🙈 &_discounted { @apply line-through text-gray-400 font-normal; } } // Модификатор для самого блока &_featured { @apply shadow-md border-2 border-primary-500; // А здесь можно было бы создать еще один блок "featured-card", // пять оберток и два миксина. Но мы не ищем легких путей, верно? } }
Что дает:
-
Четкую структуру компонента (Как государство, но без налогов)
-
Легкое переиспользование (Когда-нибудь ваш компонент вырастет и станет библиотекой, и вы будете им гордиться!)
-
Хорошую читаемость благодаря SCSS (Потому что нормальные люди не хотят читать CSS, где селекторы длиннее, чем названия лекарств)
-
Повторно используемые стили утилит благодаря @apply (Tailwind как пицца — берешь только те кусочки, которые нравятся)
2. Используй чистый Tailwind, когда:
-
Работаешь с вспомогательными контейнерами и обертками (Те самые, которым мы всегда даем имена типа wrapper, container, box, и — в момент отчаяния — thingy)
-
Создаешь однократные элементы без особой семантики (Потому что не всё заслуживает имени, некоторым достаточно просто быть flex-1 p-4)
-
Имеешь сложности с придумыванием осмысленного имени (Когда все хорошие имена уже заняты, а плохие не пропустит код-ревью)
<!-- Вместо мучений с .layout__content-wrapper__inner-container --> <div class="max-w-screen-xl mx-auto px-4 py-8"> <div class="grid grid-cols-1 md:grid-cols-3 gap-6"> <!-- Содержимое, которое не нужно искать в CSS-файлах за тридевять земель --> </div> </div>
Что дает:
-
Меньше головной боли с названиями (Потому что «придумывание имен» должно относиться к детям и домашним питомцам, а не к div’ам)
-
Быстрая разработка (Ты вернешься домой к ужину, а не будешь до полуночи подбирать имя для очередного элемента)
-
Отсутствие дополнительных CSS-файлов для вспомогательных элементов (Меньше файлов = меньше мест, где можно потеряться)
Решение проблемы с margin и позиционированием
Вот где гибридный подход по-настоящему сияет. ✨ Вместо создания модификаторов для каждого варианта отступа и позиционирования (я тебя умоляю, кому нужны .product-card_margin-bottom-16 .product-card_margin-bottom-32 .product-card_margin-left-0-on-mobile?!), используем Tailwind поверх БЭМ-классов:
<!-- Внутренняя структура через БЭМ, позиционирование через Tailwind --> <article class="product-card mb-4 md:mb-0 md:mr-6 flex-1"> <img class="product-card__image" src="product.jpg" alt="Product" /> <div class="product-card__body"> <h3 class="product-card__title">Отличный продукт</h3> <div class="flex items-center justify-between mt-3"> <!-- Да, я использовал флексы внутри БЭМ-блока! Арестуйте меня! --> <p class="product-card__price">1999 ₽</p> <button class="product-card__button">Купить</button> </div> </div> </article>
Обратите внимание:
-
product-cardи его внутренние элементы следуют БЭМ (Потому что мы воспитанные люди) -
Внешние отступы (
mb-4,md:mb-0,md:mr-6) и некоторое позиционирование (flex-1) задаются через Tailwind (Потому что жизнь слишком коротка, чтобы создавать модификаторы для каждого пикселя отступа) -
Для уникальной внутренней структуры, которую сложно выразить в БЭМ, также используем Tailwind (
flex items-center justify-between mt-3) (Потому что иногда flex — это просто flex, а не product-card__price-button-row_layout-horizontal)
Переиспользуемые секции: база через БЭМ, вариации через Tailwind
Особенно полезен гибридный подход при работе с секциями сайта, которые переиспользуются в разных контекстах (Ох уж эти секции, которые выглядят одинаково, но дизайнер говорит «здесь отступ должен быть чуть побольше, а здесь — градиент поярче»):
<!-- Базовая структура через БЭМ, специфичные стили через Tailwind --> <section class="hero-section bg-gradient-to-r from-blue-500 to-indigo-600 py-16 md:py-24" > <div class="container mx-auto px-4"> <h1 class="hero-section__title text-center md:text-left" >Заголовок страницы</h1 > <p class="hero-section__subtitle mb-8 max-w-2xl" >Подробное описание сервиса</p > <div class="hero-section__buttons flex flex-col sm:flex-row gap-4"> <!-- Да, мы используем gap вместо margin между кнопками! И нет, нам не стыдно! Это 2023-й, а не каменный век! --> <button class="hero-section__button_primary">Начать</button> <button class="hero-section__button_secondary">Подробнее</button> </div> </div> </section>
.hero-section { &__title { @apply text-3xl md:text-5xl font-bold text-white; // Мама, смотри! Я адаптивную типографику без медиа-запросов сделал! } &__subtitle { @apply text-lg text-white/80; } &__button { &_primary { @apply bg-white text-blue-600 font-medium py-3 px-6 rounded-lg; } &_secondary { @apply bg-transparent border-2 border-white text-white py-3 px-6 rounded-lg; // 15 строк CSS в одну! Дизайнер даже не заметит подмены! } } }
Такой подход позволяет переиспользовать секции, настраивая их внешний вид и позиционирование через Tailwind прямо в месте использования. (А не через 50 модификаторов, имена которых заставляют задуматься о смене профессии)
Работа с компонентами Vue/React/Angular
В мире компонентов гибридный подход тоже прекрасно работает (если ваш тимлид не фанатик какой-то одной методологии):
<!-- ProductCard.vue --> <template> <article class="product-card" > <img class="product-card__image" :src="product.image" :alt="product.name" /> <div class="product-card__body"> <h3 class="product-card__title">{{ product.name }}</h3> <p class="product-card__price" :class="{ 'product-card__price_discounted': product.hasDiscount }" > {{ product.price }} </p> </div> </article> </template>
И используем его так:
<template> <div class="grid grid-cols-1 md:grid-cols-3 gap-6"> <ProductCard v-for="product in products" :key="product.id" :product="product" class="mb-4 md:mb-0" <!-- Смотрите, никаких custom-component-margin-for-this-specific-case модификаторов! --> /> </div> </template>
Когда НЕ стоит использовать гибридный подход
-
Микро-проекты — для совсем небольших проектов часто достаточно просто Tailwind (Чтобы потом через 6 месяцев проклинать себя, когда «маленький проект» вырастет в монстра, но кто ж об этом думает в начале?)
-
Строгие требования к методологии — если в команде есть строгие гайдлайны по БЭМ или Tailwind (Или если ваш тимлид носит футболку «БЭМ или смерть»)
-
Проекты с устаревшим CSS — может быть сложно интегрировать в унаследованную кодовую базу (Особенно если там есть !important в каждой второй строке и inline-стили «потому что так быстрее»)
Заключение
Гибридный подход БЭМ + Tailwind это не ересь (хотя пуристы с обеих сторон могут сжечь вас на костре), а прагматичное решение реальных проблем:
-
Перестаем мучиться с неймингом вспомогательных элементов (Нет больше «как назвать этот div, который просто центрирует контент?»)
-
Решаем проблему с отступами и позиционированием (Потому что отступы — это отношения между элементами, а не их внутреннее дело!)
-
Сохраняем семантическую структуру для сложных компонентов (Чтобы разобраться даже спустя год)
-
Ускоряем разработку благодаря утилитам (И успеваем закончить до дедлайна, что уже чудо)
Личный опыт: спасение из CSS-ада
Знаете, я ведь не просто так все это пишу. Я лично использовал этот подход на реальном коммерческом проекте, когда уже был готов наплевать на все методологии и начать писать стили прямо в атрибутах (да, было настолько х**во).
Когда мой проект вырос до 30+ компонентов, я начал замечать, что:
-
На придумывание имён для вложенных контейнеров уходило больше времени, чем на саму верстку
-
Каждый новый элемент вызывал приступ экзистенциального кризиса: «это новый бл**ь блок или элемент существующего блока?»
-
Меня начинало потряхивать от необходимости создавать очередной модификатор типа
block__element_margin-bottom-md
И тут меня осенило. Если я использую БЭМ для чётких семантических блоков, а Tailwind — для всего остального, жизнь становится прекрасной! Разработка ускорилась примерно в два раза. Я перестал тратить время на бессмысленные споры с самим собой о том, как назвать очередной ёб**ый контейнер, который просто центрирует содержимое.
После перехода на гибридный подход:
-
Верстать стало удовольствием, а не пыткой
-
Компоненты действительно стали переиспользуемыми без тонны модификаторов
-
Код-ревью перестали превращаться в лекции по правильному именованию в БЭМ
-
Дизайнер перестал закатывать глаза, когда я говорил, что внести «небольшие изменения в отступы» займёт полдня
И самое главное — вы сэкономите кучу нервов. Серьезно, это как чёртово освобождение. Просто попробуйте эту ох**нную комбинацию, и вы поймёте, о чём я.
Не нужно быть религиозным фанатиком одной методологии — вместо этого используйте лучший инструмент для конкретной задачи. Иногда это БЭМ, иногда Tailwind, а часто — их разумное сочетание. Я за**ался тратить время на споры о методологиях, когда можно просто делать крутой продукт!
ссылка на оригинал статьи https://habr.com/ru/articles/924826/
Добавить комментарий