Какие способы подключения стилей к документу в компоненте существуют
Что проверяют
Понимаете ли вы, как выбранный способ влияет на изоляцию стилей, размер бандла и серверный рендеринг, и умеете ли обосновать выбор. Следом обычно спрашивают, как вы избегаете конфликтов имён классов и что возьмёте в новый проект.
Как отвечать
- глобальный CSS:
import './App.css'или<link>в документе. Просто и хорошо кэшируется, но изоляции нет, нужна дисциплина вроде БЭМ и@layerдля управления каскадом; - CSS Modules: файл
Button.module.css, классы превращаются в уникальные имена и импортируются как объектstyles. Изоляция на этапе сборки, рантайма нет; - препроцессоры: Sass или Less дают миксины и функции, но переменные и вложенность теперь есть в самом CSS, так что выбор уже не очевиден;
- utility-классы: Tailwind CSS, стили прямо в разметке, в сборку попадают только использованные классы;
- CSS-in-JS в рантайме: styled-components, Emotion. Удобно завязывать стили на пропсы, но они вычисляются в браузере, а с React Server Components такие библиотеки работают только в клиентских компонентах.;
- CSS-in-JS без рантайма: vanilla-extract, Linaria, Panda CSS. На выходе обычный CSS;
- инлайн
style: для значений, вычисляемых в рантайме (ширина прогресса). Не умеет псевдоклассы и медиазапросы; - механизмы фреймворков: во Vue
<style scoped>добавляет атрибутыdata-v-*,<style module>даёт CSS Modules. В Angular по умолчаниюViewEncapsulation.Emulated, естьShadowDomиNone. В React 19<link rel="stylesheet">с атрибутомprecedenceможно рендерить прямо в компоненте, React сам поднимет его в<head>.
Где спотыкаются
Называют инлайн-стили медленными и запрещают их целиком. Для динамических значений это нормальный инструмент, плохи статичные стили в style: они не переиспользуются и не умеют :hover.
Выбирают CSS-in-JS в рантайме для приложения с серверным рендерингом и не называют цену: вставка стилей во время рендера, лишний JavaScript в бандле, сложности со стримингом.
Считают, что scoped во Vue полностью изолирует компонент. Стили родителя всё равно попадают на корневой элемент дочернего компонента, а чтобы достать глубже, нужен :deep().