Styled Components — стилизация React-приложений
Содержание
Сегодня мы рассмотрим удобную библиотеку для React – Styled Components. Она предназначена для реализации стилей в JavaScript файлах на основании входных данных React-компонентов — пропсов (props).
Особенности Styled Components
React — это отличный способ писать большие и быстрые JavaScript-приложения. При разработке динамических приложений c этим инструментом часто приходится стилизовать контент. По ряду причин использование стандартных средств CSS для этого не совсем удобно. Библиотека Styled Components дает возможность выполнить стилизацию React-приложения, упростив и ускорив написание кода. Styled Components позволяет работать со стилями прямо в JavaScript — это компонент, который в стиль подсовывает функцию от каких-то аргументов. В Styled Components вы обращаетесь к функции и она, по сути, может делать что угодно, возвращая любое строковое значение для стиля этого компонента.
Преимущества и недостатки Styled Components в React-приложениях
Ранее, до появления Styled Components, если нужно было сделать динамические стили, их нужно было выносить в inline или писать много className. Но с этой библиотекой вы больше не стилизуете элементы HTML или компоненты на основании их класса или HTML-элемента. Отпадает необходимость в тернарных операторах, нет надобности прибегать к className
. Вместо этого используются пропсы внутри компонент, с указанием стилей, а классы генерируются автоматически (к слову, проблема коллизии имен отсутствует как таковая). Обращение к стилям CSS происходит прямо в JavaScript, благодаря чему им легко управлять, он понятен, нет необходимости учить какой-то дополнительный синтаксис.
Стили легко отслеживать. Предположим, вы написали какой-то компонент, а затем его убрали, а стили остались – от них нужно избавиться, чтобы они лишний раз не грузились на клиент. Такая проблема со Styled Components решается автоматически — удалили компонент, удалились стили. Также к преимуществам Styled Components можно отнести наличие серверного рендеринга и модульных тестов.
Очевидный недостаток Styled Components – привязка к React. Кроме того, зарезервированные названия (height, width, background-color и пр.) мы не должны использовать как входные данные React-компонентов. Еще один минус данной библиотеки – стили не сохраняются в кеше, стиль появляется только тогда, когда исполняется JavaScript. Это несколько влияет на производительность.
Установка Styled Components
Для начала разберемся с установкой Styled Components. Ее можно выполнить одной командой в командной строке:
# менеджер пакетов npm
npm install --save styled-components
Альтернативный вариант с yarn:
# через yarn
yarn add styled-components
Стилизация компонентов происходит следующим образом. Вместо того, чтобы описывать стили HTML на основе класса:
<button className="btn">Knopka</button>
И
button.btn { background-color: #1dcde0;
color: white;
font-size: 22px;
margin: 11px;
padding: 5px 20px;
border: 4px solid black;
border-radius: 8px;}
Указываются компоненты, которые содержат собственные инкапсулированные наборы стилей, вот так:
const Knopka = styled.button`
background-color: #1dcde0;
color: white;
font-size: 22px;
margin: 11px;
padding: 5px 20px;
border: 4px solid black;
border-radius: 8px;`;
С помощью утилиты create-react-app создадим новое приложение, удалим все лишнее, оставив приложение полностью пустым. После установки пакета переходим в компоненту App и импортируем этот модуль styled-component. Создадим стилизованный компонент – обертку приложения, грубо говоря, корневой блок div.
Внутри шаблонных литералов пишем стили, которые собираемся использовать: ширина на 100 процентов, минимальная высота – на всю высоту окна браузера, padding в два rem (размер относительно шрифта) и черный цвет фона приложения.
Чтобы увидеть стили, теперь обернем наше приложение в обертку:
const App = () => {
return (
<AppWrapper>
Some text
</AppWrapper>
);
};
Управление глобальными стилями
Поскольку по умолчанию в браузере всегда есть внешние-внутренние отступы (из-за чего появилась полоса прокрутки), их следует убрать глобальными стилями. Для этого в коде index.js из модуля styled-components импортируем функцию GlobalStyle и, по аналогии с предыдущим примером, создаем компонент, вызываем эту функцию, указывая шаблонных литералах стили. Используя универсальный селектор для каждого элемента на странице по умолчанию уберем внешние и внутренние отступы, параметр box-sizing (определяет как вычисляется общая ширина и высота элемента) поставим как border-box. Теперь этот компонент можно поместить в любой участок кода и эти стили будут функционировать. Обычно, их помещают в корень приложения, либо в компоненту app. Обернем все в react-фрагмент и добавим наше приложение App-компонент и глобальные стили:
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import styled, {createGlobalStyle} from "styled-components";
const Global = createGlobalStyle`
* {
margin:0;
padding:0;
box-sizing:border-box;
}`
ReactDOM.render(
<>
<Global/>
<App />
</>,
document.getElementById( 'root')
);
Отступы пропали, значит, глобальные стили работают. В стилях подключим шрифт.
font-family: consolas;
Работа с пропсами
Чтобы упорядочить компоненты, создадим отдельную директорию, назовем ее components. Создадим там первый компонент – Title.js. Быстро делаем React-компонент (можно сниппетом, набрав rsc) и сделаем стилизованный заголовок, прописав в шаблонных литералах стили.
import React from 'react';
import styled from "styled-components";
const StyledTitle = styled.h1`
color: white;
`
const Title = () => {
return <StyledTitle>
</StyledTitle>
};
export default Title;
Вернемся в App.js и добавим его на страницу. Вместо Some text добавляем
<Title>Highload.tech </Title>
Если обновить страницу в браузере мы увидим черный цвет.
Чтобы React понял, что текст нужно добавить внутрь стилизованного заголовка, используем пропс, который называется {children}
. Добавляем этот пропс и помещаем его в середину.
import React from 'react';
import styled from "styled-components";
const StyledTitle = styled.h1`
color: white;
`
const Title = ({children}) => {
return <StyledTitle>
{children}
</StyledTitle>
};
export default Title;
Предположим, в ходе работы приложения, нам необходимо динамически менять цвет заголовка. С помощью следующего синтаксиса в зависимости от пропса, который принимает компонент, можно менять те или иные свойства:
color: ${props => props.color};
Вернемся в компоненту App и добавим нашему заголовку пропс color, добавив, скажем, синий цвет:
<Title color={"blue"}>Highload.tech </Title>
Если сейчас мы откроем браузер, то ничего не увидим, поскольку передали пропс не в StyledTitle, а просто в Title. Поэтому в Title.js этот пропс нужно принять и передать в StyledTitle:
const Title = ({children, color}) => {
return <StyledTitle color={color}>
Открываем браузер и видим, что цвет изменился – таким образом можно передавая разные пропсы менять цвет заголовка.
Однако, такая запись является достаточно неудобной. Ведь, если у нас будет с десяток различных пропсов, вручную их перечислять, конечно, неудобно. Есть более лаконичный синтаксис, позволяющий в StyledTitle развернуть все пропсы:
import React from 'react';
import styled from "styled-components";
const StyledTitle = styled.h1`
color: ${props => props.color};
`
const Title = (props) => {
return <StyledTitle {...props}/>
};
export default Title;
Все, что мы будем передавать в Title, автоматически будет передаваться и в StyledTitle.
Создадим еще один компонент, назовем его Flex.js. Это будет тоже своего рода обертка, которая будет принимать направление Flex-контейнера, align-items и justify-content, чтобы выравнивать относительно контейнера все внутренние элементы.
import React from 'react';
import styled from 'styled-components'
const StyledFlex = styled.div`
display: flex;
flex-direction: ${props => props.direction || 'row'};
align-items: ${props => props.align || 'stretch'};
justify-content: ${props => props.justify || 'stretch'};
margin: ${({margin}) => margin || '0'};
`
const Flex = (props) => {
return <StyledFlex {...props}/>
};
export default Flex;
Каждое из перечисленных свойств будет принимать значение, в зависимости от того, какой пропс мы прокинули. Так, если мы передали props.direction
, то он будет присвоен свойству flex-direction. В обратном случае будет присвоено значение ‘row’.
Возвращаемся в App.js – теперь можем пользоваться компонентом Flex и поместить внутрь него наш Title, центруя его посередине.
import Title from "./components/Title";
import Flex from "./components/Flex";
const AppWrapper = styled.div`
width: 100% ;
min-height: 100vh;
padding: 2rem;
background: black;
`
const App = () => {
return (
<AppWrapper>
<Flex justify = "center">
<Title color={"blue"}>Highload.tech </Title>
</Flex>
</AppWrapper>
);
};
export default App;
Чтобы разобраться в данной теме, сделаем что-то вроде симулятора окна командной строки. Перейдем к верстке окна терминала – создаем компонент Console.js. Поле textarea растянем на всю ширину, высоту – 80% от высоты окна браузера, прокинем в компонент пропсы и возвратим из этого компонента нашу стилизованную консоль.
import React from 'react';
import styled from "styled-components";
const StyledConsole = styled.textarea`
width:100%;
height:80vh;
`
const Console = (props) => {
return <StyledConsole {...props}/>
};
export default Console;
В компоненте Flex.js добавим эту консоль
const App = () => {
return (
<AppWrapper>
<Flex justify = "center">
<Title color={"blue"}>Highload.tech </Title>
</Flex>
<Console/>
</AppWrapper>
Настроим внешний вид консоли
color: ${({color}) => color || "red"
Псевдоклассы
На примере фокуса рассмотрим как работать с псевдоклассами. Используем знак &, который заменяет селектор текущего элемента и указываем, чтобы рамка поля при выделении не рисовалась:
&:focus{
outline: none;
}
Добавим кнопку и на примере этого элемента рассмотрим как можно делать разные стили в зависимости от пропса. Создаем и разворачиваем новый компонент Button.js:
import React from 'react';
import styled from "styled-components";
const StyledButton = styled.button`
border:none;
padding:10px 15px;
font-size:26px;
cursor: pointer;
& focus {
outline:none;
}
`
const Button = (props) => {
return <StyledButton{...props}/>
};
export default Button;
Возвращаемся в App.js и добавляем под консоль эту кнопку:
.. <AppWrapper>
<Flex justify = "center">
<Title color={"blue"}>Highload.tech </Title>
</Flex>
<Console/>
<Button>Publish</Button>
</AppWrapper>
Переместим кнопку вправо. Консоль и кнопку обернем во <Flex> и добавим пропс для того, чтобы сместить кнопку вправо:
<AppWrapper>
<Flex justify = "center">
<Title color={"blue"}>Highload.tech </Title>
</Flex >
<Flex direction="column">
<Console/>
<Button align="flex-end">Publish</Button>
</Flex>
</AppWrapper>
В Button.js добавляем свойство align-self, которое позволяет выровнять какой-то элемент внутри флекс-контейнера. Значение будем получать из пропсов, а если такового нет, по умолчанию установим stretch.
align-self: ${props => props.align || 'stretch'}
Группировка стилей на основании пропсов
Теперь займемся стилями. Чтобы сгруппировать несколько свойств, в зависимости от пропсов, используется следующая конструкция. Она состоит из логического “И” (&&) и указанного в шаблонных литералах стилей, которые применяются, если мы передали в компонент этот пропс. Помещаем код в Button.js
import React from 'react';
import styled from "styled-components";
const StyledButton = styled.button`
border:none;
padding:10px 15px;
font-size:26px;
cursor: pointer;
& focus {
outline:none;
}
align-self: ${props => props.align || 'stretch'};
${props => props.primary && `
color: ${props => props.color ||'white'};
background: ${props => props.background||'white'};
`}
`
const Button = (props) => {
return <StyledButton{...props}/>
};
export default Button;
Перейдем в компоненту App и передадим пропс primary.
Button primary background={‘green’} color={'red'} align="flex-end">Publish</Button>
Меняем color={'green'}
и видим, что цвет кнопки стал красным на зеленом фоне.
Теперь сделаем стиль кнопки с обводкой
${props => props.outlined && css`
color: ${props => props.color || 'white'};
border: 1px solid ${props => props.color || "white"};
background: transparent;
`}
Возвращаемся в App.js и передаем пропсам outlined
<Button outlined align="flex-end">Publish</Button>
Создадим кнопку, которая будет иметь все те же стили, что и Styled button, но больше в размерах. Создадим кнопку, что будет иметь все те же стили, что и наша Styled button. Вызываем Styled, параметром передаем компонент, от которого хотим унаследоваться, увеличиваем размер шрифта.
const LargeButton = styled(StyledButton)`
font-size: 32px;
Теперь кнопка стала больше, но она сохранила все стили, которые есть у StyledButton. Грубо говоря – LargeButton наследуется от StyledButton. Таким образом, стили можно расширять на основе уже существующих компонентов.
Анимация
Принцип анимации тот же самый, что и в CSS. Чтобы добавить анимацию, необходимо использовать функцию keyframes. Для подключения используем псевдокласс hover.
import React from 'react';
import styled, {css, keyframes} from 'styled-components'
const rotateAnimation = keyframes`
0% {
transform: rotateZ(0deg);
}
100% {
transform: rotateZ(360deg);
}
`const StyledButton = styled.button.attrs(props => ({
outlined: true,
}))`
border: none;
padding: 10px 15px;
font-size: 18px;
cursor: pointer;
&:focus {
outline: none;
}
&: hover {
animation: ${rotateAnimation} 1s infinite linear;
}
align-self: ${props => props.align || 'stretch'};
${props => props.primary && css`
color: ${props => props.color || 'white'};
background: ${props => props.background || 'white'};
`}
${props => props.outlined && css`
color: ${props => props.color || 'white'};
border: 1px solid ${props => props.color || "white"};
background: transparent;
`}
`const LargeButton = styled(StyledButton)`
font-size: 32px;
`const Button = (props) => {
return <StyledButton {...props}/>
};
export default Button;
Заключение
Мы разобрались с библиотекой Styled Components и рассмотрели основные приемы работы с ней. Для более детального изучения данной темы рекомендуем вам посмотреть видео, где автор используя Styled Components проведет мастер класс по созданию SPA-приложения с выбором темы REST API запросами, поиском, фильтрацией SPA-проект с темизацией на React и styled-components.
Сообщить об опечатке
Текст, который будет отправлен нашим редакторам: