Позвольте мне обрисовать вам картину: сейчас 3 часа ночи, ваш компонент React теряет стили, как зомби из «Ходячих мертвецов», и вы по уши в обёртках styled-component. Вдруг вас осеняет — возможно, CSS-in-JS не был той панацеей, которую обещали в статье на Medium с подозрительно идеальным примером кода. Добро пожаловать в мой мир, друг. Давайте разберёмся, когда CSS заслуживает своего места за столом взрослых.

Индустрия JavaScript объявляет очередную жертву

Я никогда не забуду тот день, когда я унаследовал кодовую базу, где для изменения цвета при наведении курсора на компонент кнопки потребовалось 17 вложенных ThemeProvider. Наша реализация CSS-in-JS стала программным эквивалентом матрешки, окунутой в эпоксидную смолу. Показатели производительности выглядели как проверка на полиграфе от неверного супруга.

// Место преступления:
<ThemeProvider theme={outerSpace}>
  <ColorProvider palette={brandColors}>
    <MobileFirstContext.Provider value={true}>
      <Button
        sx={{
          '&:hover': {
            color: 'inheritedFromSomewhereMaybe',
            transform: 'rotateX(360deg)'
          }
        }}
      />
    </MobileFirstContext.Provider>
  </ColorProvider>
</ThemeProvider>

Вот как умирают благие намерения. Мы хотели иметь стили с ограниченной областью действия компонентов, но получили спагетти зависимостей. Пересчёты стилей в браузере заставили наше приложение работать медленнее, чем государственные сайты во время налогового сезона.

Когда простой CSS надевает плащ

Давайте пройдёмся по шумихе с помощью некоторых холодных и жёстких тестов из моего последнего проекта:

ПоказательCSS-модулиСтилизованные компонентыОбычный CSS
FCP (мс)12002400800
Размер пакета (КБ)15021090
Гидратация SSR1,2 с2,8 с0,4 с
Увольнение разработчиков03 в неделю1 в месяц

(Данные собраны из аудитов Lighthouse) Как только мы переключили основную разметку на CSS Grid с использованием собственных переменных, наш продуктовый менеджер заплакал от радости. Оказывается, браузеры отлично справляются с CSS, если мы позволяем им делать свою работу.

Возрождение каскада

Помните, когда мы все высмеивали CSS за его букву «К»? Оказывается, каскад похож на того странного дядюшку, который знает навыки выживания — он раздражает, пока не наступит конец света. Вот моя программа реабилитации каскадов из трёх шагов:

  1. Пространство имён со слоями
    @layer base, components, utilities;
    @layer components {
      .card { /* изолированные стили */ }
    }
    
  2. Ограничьте ущерб
    .user-profile {
      container-type: inline-size;
      /* Ваши стили не могут выйти за пределы этого Алькатраса */
    }
    
  3. Переменные > Поставщики тем
    :root {
      --accent-color: oklch(68.72% 0.147 358.04);
    }
    .callout {
      background: var(--accent-color);
    }
    

Нужна динамическая тематика? Вот интересный подход: пользовательские свойства CSS + classList.toggle() могут справиться с 90% случаев использования без загрузки среды выполнения CSS-in-JS размером 15 КБ.

Искусство стратегического отступления

Когда следует отказаться от CSS-in-JS? Давайте визуализируем:

flowchart TD A[Запуск нового проекта] --> B{Сложные динамические стили?} B --> |Да| C[CSS-in-JS: Эмоциональная поддержка аллигатора] B --> |Нет| D[CSS-модули: Надёжный напарник по лаборатории] C --> E{Критично для производительности?} E --> |Да| F[Отмена! Используйте скомпилированный CSS] E --> |Нет| G[Продолжайте гидратацию SSR] D --> H[Прибыль!]

Оказались в красной зоне? Вот как выбраться из чистилища CSS-in-JS:

  1. Создайте аварийный выход
    npx codemod --parser css-modules --extensions js,jsx ./src
    
  2. Удалите стили времени выполнения
    /* styles.module.css */
    .enterpriseForm {
      --input-border: 2px solid;
      border: var(--input-border) hotpink;
    }
    
  3. Используйте PostCSS как талисман
    // postcss.config.js
    module.exports = {
      plugins: {
        'postcss-jit-props': {},
        'postcss-nesting': {},
        'cssnano': {}
      }
    }
    

Правдивая история: мы сократили количество ошибок, связанных со стилями, на 40%, перейдя от проверки состояния формы к чистым псевдоклассам CSS. Оказывается, :invalid работает лучше, чем отслеживание 15 полей формы с помощью React useEffect.

Парадокс обслуживания

Сторонники CSS-in-JS любят кричать «совмещение!», но видели ли вы оформленный компонент через 6 месяцев после добавления функций? Это всё равно что найти в своей кодовой базе гостевую книгу GeoCities 1998 года:

const StyledButton = styled(Button).attrs(({ theme }) => ({
  // 😱 ПОЧЕМУ ЗДЕСЬ ЭМОДЗИ В ВИДЕ РЫБКИ?
  hoverColor: theme.mode === 'dark' ? '#00ff9d' : '👩🍳'
}))`
  background: ${p => p.hoverColor};
  animation: ${pulse} 2s infinite;
  ${({ variant }) => variant === 'cta' && css`
    box-shadow: 0 0 10px #ff00ff;
  `}
`;

Сравните это с CSS-модулями, где вашим худшим грехом может быть слишком умное имя класса:

/* login.module.css */
.t-rex-theme-conqueror {
  /* По крайней мере, это деградирует изящно */
  background: linear-gradient(to right, #fff 0%, #dino-mix 100%);
}

Неприятная правда

После работы над 7+ производственными приложениями на 3 континентах (да, даже в Антарктиде теперь есть разработчики React), вот моё спорное мнение:

CSS-in-JS — это блокчейн разработки интерфейса — революционный для определённых вариантов использования, но катастрофический при неизбирательном применении. Давайте оставим CSS-in-JS для того, в чём он хорош: дизайн-системы со сложными динамическими требованиями, переключение тем в реальном времени и прототипирование. Для вашего маркетингового сайта, панели администратора или платформы с большим количеством контента — CSS не враг, а ваш друг, выпивший слишком много кофе, который доводит дело до конца. В следующий раз, когда кто-то потребует CSS-in-JS, потому что «это делает Facebook», напомните ему, что Марк Цукерберг тоже считал бежевый цвет хорошим для веб-сайта. Некоторые решения заслуживают тщательного изучения.

/* Потому что иногда нужно просто бросить микрофон */
.old-school-rules {
  content: "🔥";
}