Styled Components — стилізація React-додатків
Зміст
Сьогодні ми розглянемо зручну бібліотеку для React – Styled Components. Вона призначена для реалізації стилів у файлах JavaScript на основі вхідних даних React-компонентів — пропсів (props).
Особливості Styled Components
React – це чудовий спосіб писати великі та швидкі JavaScript-додатки. При розробці динамічних програм з цим інструментом часто доводиться стилізувати контент. Через низку причин використання стандартних засобів 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. Крім того, ми не повинні використовувати для вхідних даних React-компонентів зарезервовані назви (height, width, background-color тощо) . Ще один мінус цієї бібліотеки – стилі не зберігаються в кеші, стиль з’являється лише тоді, коли виконується 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;
Робота з пропсами
Щоб упорядкувати компоненти, створимо окрему директорію, назвемо її компоненти. Створимо там перший компонент – 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.today </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.today </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.today </Title>
</Flex>
</AppWrapper>
);
};
export default App;
Щоб розібратися в цій темі, зробимо щось на зразок симулятора вікна командного рядка. Перейдемо до верстки вікна терміналу – створюємо компонент Console.js. Поле текста розтягнемо на всю ширину, висоту – 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.today </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.today </Title>
</Flex>
<Console/>
<Button>Publish</Button>
</AppWrapper>
Перемістимо кнопку праворуч. Консоль і кнопку обернемо у <Flex>
і додамо пропс для того, щоб змістити кнопку праворуч:
<AppWrapper>
<Flex justify = "center">
<Title color={"blue"}>Highload.today </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, параметром передаємо компонент, від якого хочемо успадковуватися, збільшуємо розмір шрифту.
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.
Сообщить об опечатке
Текст, который будет отправлен нашим редакторам: