Мы с вами уже научились создавать компоненты, управлять их состоянием, работать с формами и маршрутизацией. Наши приложения функциональны, но пока они выглядят не очень презентабельно. Пришло время добавить им стиля.
В этом уроке мы разберем три основных подхода к стилизации React-приложений, классические CSS-модули, современные CSS-in-JS библиотеки на примере Styled Components, а также бегло взглянем на готовые библиотеки компонентов. Я подробно расскажу о плюсах и минусах каждого метода, покажу много практических примеров и, самое главное, помогу вам понять, какой подход выбрать для вашего следующего проекта.
CSS-модули
CSS-модули это не какой-то специальный библиотека или инструмент, а скорее концепция, система организации кода. Если вы работали с обычным CSS и сталкивались с проблемой «загрязнения» глобального пространства имен (когда стили из одного файла неожиданно применяются к элементам в другом), то CSS-модули это ваше спасение.
Идея проста. Каждый файл стилей (например, Button.module.css) считается независимым модулем. Имена классов, которые вы в нем объявляете, при сборке проекта автоматически преобразуются в уникальные. Это означает, что класс .btn в вашем компоненте Button и класс .btn в компоненте Header будут скомпилированы в разные, уникальные имена, например, Button_btn__a1b2c и Header_btn__x3y4z. Таким образом, стили изолированы в рамках своего компонента и вы можете не бояться конфликтов.
Давайте посмотрим, как это работает на практике. Представьте, что у нас есть простой компонент кнопки.
Пример кода: Обычный CSS (проблема)
Button.css:
.btn { padding: 10px 20px; background-color: blue; color: white; border: none; border-radius: 4px; }
Button.js:
import './Button.css'; function Button() { return <button className="btn">Нажми меня</button>; }
Пока все хорошо. Но если в другом файле, например, Header.css, мы тоже объявим класс .btn с другими стилями, они начнут конфликтовать. С CSS-модулями этой проблемы нет.
Пример кода: Использование CSS-модулей
Переименуем наш файл стилей, добавив суффикс .module.css: Button.module.css. Содержимое может остаться тем же.
Button.module.css:
.btn { padding: 10px 20px; background-color: blue; color: white; border: none; border-radius: 4px; cursor: pointer; } .btn:hover { background-color: darkblue; }
Теперь импортируем стили в наш компонент иначе:
Button.js:
import styles from './Button.module.css'; function Button() { return ( <button className={styles.btn}> Нажми меня </button> ); }
styles это обычный JavaScript-объект, который импортируется из CSS-файла. Ключи в этом объекте, это имена классов, которые вы написали в CSS-файле (btn), а значения это те самые сгенерированные уникальные имена. В этом и заключается вся суть. Вы продолжаете писать привычный CSS, но получаете гарантированную изоляцию стилей.
Плюсы CSS-модулей:
-
Изоляция стилей. Полное отсутствие конфликтов имен классов.
-
Простота освоения. Если вы знаете CSS, вам не нужно учить новый синтаксис.
-
Стабильность и производительность. Это «скомпилированный» подход. На клиент не приходят лишние библиотеки, все стили это статические CSS-файлы.
-
Совместимость. Отлично работает с SASS/SCSS (просто используйте
[name].module.scss).
Минусы CSS-модулей:
-
Динамические стили. Работа с пропсами для изменения стилей становится менее интуитивной и требует передачи нескольких классов или inline-стилей.
-
Глобальные стилы. Для сброса стилей или шрифтов все равно нужен отдельный глобальный CSS-файл.
CSS-модули это отличный, надежный и производительный выбор для большинства проектов, особенно для команд, привыкших к классической вёрстке.
Styled Components: CSS-in-JS и динамические стили
Это подход, при котором мы пишем стили не в отдельных .css файлах, а прямо внутри JavaScript-кода, используя специальные библиотеки. Самая популярная из них, это Styled Components. Её суть заключается в том, что компонент должен включать в себя всё: и логику и разметку и стили.
Styled Components позволяет создавать React-компоненты, которые имеют свои стили, «вшитые» прямо в них. Вы описываете стили, используя шаблонные литералы (template literals), те самые строки в обратных кавычках. Внутри этих строк вы пишете обычный CSS. В результате вы получаете готовый React-компонент, который можно использовать как любой другой.
Что делает Styled Components по-настоящему мощными? Они идеально подходят для создания динамических стилей, которые зависят от пропсов. Давайте сразу создадим кнопку, которая может менять свой цвет в зависимости от переданного пропса variant.
Сначала установим библиотеку npm install styled-components
Пример кода: Базовое использование Styled Components
Button.js:
import styled from 'styled-components'; // Создаем компонент StyledButton, который будет рендерить тег <button> с нашими стилями. const StyledButton = styled.button` padding: 10px 20px; border: none; border-radius: 4px; cursor: pointer; font-size: 16px; // Динамические стили на основе пропса `variant` background-color: ${props => { if (props.variant === 'primary') return 'blue'; if (props.variant === 'danger') return 'red'; return 'gray'; }}; color: white; // Псевдоклассы тоже работают! &:hover { opacity: 0.8; } `; // Используем наш стилизованный компонент как обычный function Button({ variant, children }) { return ( <StyledButton variant={variant}> {children} </StyledButton> ); } export default Button;
Теперь мы можем использовать нашу кнопку в другом компоненте:
App.js:
import Button from './Button'; function App() { return ( <div> <Button variant="primary">Основная кнопка</Button> <Button variant="danger">Опасная кнопка</Button> <Button>Кнопка по умолчанию</Button> </div> ); }
Как видите, стили напрямую зависят от пропсов, которые мы передаем. Это очень читаемо и удобно. Вся мощь JavaScript теперь доступна вам прямо внутри CSS!
Плюсы Styled Components:
-
Полная инкапсуляция. Стили не просто изолированы, они являются частью компонента.
-
Динамические стили. Легко менять стили в зависимости от пропсов и состояния.
-
Удаление неиспользуемого кода. Если компонент не используется, его стили тоже не попадут в финальную сборку.
-
Отличная темадизация. Библиотека предоставляет удобный API (
ThemeProvider) для создания тем оформления.
Минусы Styled Components:
-
Runtime накладные расходы. Стили вычисляются на клиенте, что может незначительно влиять на производительность очень больших приложений.
-
Усложнение DevTools. В инструментах разработчика браузера вы увидите много сгенерированных классов, что может быть менее наглядно, чем семантичные имена классов из CSS-модулей.
-
Зависимость от библиотеки. Вы добавляете еще одну зависимость в проект.
Styled Components это фантастический выбор для проектов, где важна динамическая тема, где компоненты должны гибко адаптироваться и где разработчикам нравится философия «всё в одном месте».
Библиотеки компонентов
Иногда вам не нужно писать свои собственные стилизованные кнопки, карточки и модальные окна. Иногда скорость разработки и единообразие дизайна гораздо важнее. Именно для этого и существуют библиотеки компонентов, такие как Material-UI (MUI), Ant Design, Chakra UI и многие другие.
Эти библиотеки предоставляют вам готовые, часто очень красивые и функциональные компоненты, которые вы можете просто импортировать и использовать. Они уже протестированы, доступны и следуют определенным гайдлайнам дизайна (например, Material Design от Google в случае с MUI).
Давайте рассмотрим, как бы выглядела наша кнопка с использованием библиотеки Material-UI.
Сначала устанавливаем: npm install @mui/material @emotion/react @emotion/styled
Пример кода: Использование Material-UI
Button.js:
import Button from '@mui/material/Button'; function MyAppButton({ variant, children }) { return ( <Button variant={variant} color="primary"> {children} </Button> ); } export default MyAppButton;
App.js:
import MyAppButton from './Button'; import Stack from '@mui/material/Stack'; // Компонент для компоновки function App() { return ( <Stack direction="row" spacing={2}> <MyAppButton variant="contained">Основная кнопка</MyAppButton> <MyAppButton variant="outlined">Контурная кнопка</MyAppButton> <MyAppButton variant="text">Текстовая кнопка</MyAppButton> </Stack> ); }
И всё! Вы получили три красиво стилизованные кнопки с интерактивными состояниями (hover, focus, etc.), не написав ни строчки CSS. Библиотеки компонентов экономят колоссальное количество времени.
Плюсы библиотек компонентов:
-
Скорость разработки. Не нужно изобретать велосипед.
-
Единообразие дизайна. Все компоненты следуют одной дизайн-системе.
-
Доступность (a11y). Компоненты часто уже имеют встроенную доступность (правильные ARIA-атрибуты, управление с клавиатуры).
-
Богатая функциональность. Сложные компоненты вроде таблиц, календарей, модальных окон уже реализованы.
Минусы библиотек компонентов:
-
Размер бандла. Вы добавляете в проект очень много чужого кода, что увеличивает итоговый размер приложения.
-
Ограниченность кастомизации. Выйти за рамки предусмотренного дизайна может быть сложно. Иногда приходится бороться с библиотекой, чтобы переопределить её стили.
-
Зависимость от внешней зависимости. Обновления библиотеки могут ломать ваш код.
Библиотеки компонентов это идеальный выбор для внутренних инструментов (admin panels), прототипирования и проектов, где вы готовы пожертвовать уникальностью дизайна ради скорости.
Как выбрать подход для своего проекта?
Итак, у нас есть три мощных инструмента. Какой же выбрать? Давайте систематизируем знания и я дам вам несколько рекомендаций.
Я всегда задаю себе и своей команде несколько ключевых вопросов перед началом проекта:
-
Насколько уникальным должен быть дизайн?
-
Очень уникальный (бренд-центричный.: CSS-модули или Styled Components. Они дают полную свободу.
-
Можно использовать готовую дизайн-систем.: Библиотека компонентов (Material-UI, Ant Design).
-
-
Какой размер команды и её опыт?
-
Небольшая команда, сильный CSS-эксперт: CSS-модули.
-
Команда, которая любит JavaScript и хочет инкапсуляции: Styled Components.
-
Команда, где нет сильного фронтенд-дизайнера, но нужно быстро сделать качественный интерфейс: Библиотека компонентов.
-
-
Каковы требования к производительности и размеру бандла?
-
Критически важны: CSS-модули (минимальные накладные расходы).
-
Приемлем небольшой runtime: Styled Components.
-
Размер бандла не является главным приоритетом: Библиотека компонентов.
-
-
Нужна ли темизация (светлая/тёмная тема)?
-
Да и гибкая: Styled Components с
ThemeProvider, то это лучший выбор. -
Да, но в рамках библиотеки: MUI и другие имеют встроенную поддержку тем.
-
Мой личный сводный совет:
-
Для большинства средних и крупных проектов с уникальным дизайном я предпочитаю CSS-модули (с SCSS). Это надежно, производительно и не мешает масштабированию.
-
Для проектов, где динамика стилей (сложные анимации, темы, стили, сильно зависящие от пропсов) выходит на первый план, я выбираю Styled Components.
-
Когда нужно «сделать вчера» или разрабатывается internal tool, я без раздумий беру библиотеку компонентов (чаще всего Chakra UI или MUI).
Например, можно использовать библиотеку компонентов для основной части приложения, а для уникальных, промо-блоков написать свои компоненты с помощью Styled Components.
Практические задачи для закрепления
Чтобы материал точно усвоился, я подготовил для вас несколько практических задач. Постарайтесь выполнить их самостоятельно.
Задача 1: Создайте компонент карточки с использованием CSS-модулей
Создайте компонент Card, который отображает изображение, заголовок и текст. Используйте CSS-модули для стилизации. Убедитесь, что стили карточки не влияют на другие элементы страницы.
Решение (Card.module.css):
.card { border: 1px solid #ddd; border-radius: 8px; overflow: hidden; max-width: 300px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); font-family: sans-serif; } .cardImage { width: 100%; height: 160px; object-fit: cover; } .cardContent { padding: 16px; } .cardTitle { margin-top: 0; margin-bottom: 8px; font-size: 1.2rem; } .cardText { color: #666; line-height: 1.5; }
Решение (Card.js):
import styles from './Card.module.css'; function Card({ imageUrl, title, text }) { return ( <div className={styles.card}> <img src={imageUrl} alt={title} className={styles.cardImage} /> <div className={styles.cardContent}> <h3 className={styles.cardTitle}>{title}</h3> <p className={styles.cardText}>{text}</p> </div> </div> ); } export default Card;
Задача 2: Создайте «адаптивную» кнопку с использованием Styled Components
Создайте компонент кнопки AdaptiveButton, который меняет свой размер в зависимости от пропса size (small, medium, large). Также добавьте пропс disabled, который делает кнопку полупрозрачной и отключает курсор.
Решение (AdaptiveButton.js):
import styled from 'styled-components'; const getPadding = (size) => { switch (size) { case 'small': return '8px 12px'; case 'large': return '16px 24px'; default: return '12px 18px'; // medium } }; const StyledButton = styled.button` padding: ${props => getPadding(props.size)}; background-color: blue; color: white; border: none; border-radius: 4px; cursor: pointer; font-size: ${props => props.size === 'small' ? '0.8rem' : '1rem'}; /* Динамические стили для disabled */ opacity: ${props => props.disabled ? 0.5 : 1}; cursor: ${props => props.disabled ? 'not-allowed' : 'pointer'}; &:hover { background-color: ${props => props.disabled ? 'blue' : 'darkblue'}; } `; function AdaptiveButton({ size = 'medium', disabled = false, children }) { return ( <StyledButton size={size} disabled={disabled}> {children} </StyledButton> ); } export default AdaptiveButton;
Задача 3: Создайте простую панель навигации с помощью библиотеки компонентов
Выберите любую понравившуюся библиотеку (например, Material-UI) и создайте компонент Navbar. Он должен содержать логотип (просто текст) и несколько ссылок (например, «Главная», «О нас», «Контакты»).
Решение (с использованием MUI):
import * as React from 'react'; import AppBar from '@mui/material/AppBar'; import Toolbar from '@mui/material/Toolbar'; import Typography from '@mui/material/Typography'; import Button from '@mui/material/Button'; import Box from '@mui/material/Box'; function Navbar() { return ( <Box sx={{ flexGrow: 1 }}> <AppBar position="static"> <Toolbar> <Typography variant="h6" component="div" sx={{ flexGrow: 1 }}> Мой Сайт </Typography> <Button color="inherit">Главная</Button> <Button color="inherit">О нас</Button> <Button color="inherit">Контакты</Button> </Toolbar> </AppBar> </Box> ); } export default Navbar;
На сегодня всё! Мы разобрали три столпа стилизации в React-приложениях. Вы теперь знаете сильные и слабые стороны каждого подхода и сможете сделать осознанный выбор для своего проекта.
Не забывайте, что все уроки моего курса структурированы и идут от простого к сложному, чтобы вы могли плавно и уверенно стать востребованным React-разработчиком.
Поддержка автора осуществляется с помощью специальной формы ниже, предоставленной сервисом «ЮMoney». Все платёжные операции выполняются на защищённой странице сервиса, что обеспечивает их корректность и полную безопасность.


