Рубріки: Теорія

Styled Components — стилізація React-додатків

Сергій Бондаренко

Сьогодні ми розглянемо зручну бібліотеку для React – Styled Components. Вона призначена для реалізації стилів у файлах JavaScript на основі вхідних даних React-компонентів — пропсів (props).

Styled ComponentsStyled Components

Особливості 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.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. Поле текста розтягнемо на всю ширину, висоту – 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, параметром передаємо компонент, від якого хочемо успадковуватися, збільшуємо розмір шрифту.

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.

Останні статті

Ми вже виявили кілька вірусів, які не бачили навіть антивіруси — міністр Федоров

Віцепрем’єр-міністр з інновацій, розвитку освіти, науки та технологій, міністр цифрової трансформації Михайло Федоров під час…

18.06.2025

У Києві відбулась конференція Incrypted Conference 2025. Її називають наймасштабнішою криптоподією року

14 червня 2025 року у Києві пройшла Incrypted Conference 2025. Захід, організований командою найбільшого українського…

18.06.2025

AWS досягла 100-відсоткового застосування MFA для root-користувачів та запровадила нові функції безпеки

Amazon Web Services досягла 100-відсоткового застосування MFA (багатофакторної автентифікації) для користувачів root у всіх типах…

18.06.2025

Anysphere пропонує «майже безлімітний» доступ до редактора коду Cursor

Anysphere запустила новий щомісячний тарифний план вартістю $200 для доступу до свого редактора коду Cursor.…

18.06.2025

Міноборони готове платити військовослужбовцям за інноваційні розробки

Міністерство оборони України розробило проект постанови уряду про запровадження грошових винагород для військовослужбовців за впровадження…

18.06.2025

Сем Альтман стверджує, що Марк Цукерберг пропонував по $100 мільйонів топовим співробітникам OpenAI

Сем Альтман заявив, що Марк Цукерберг пропонував топовим співробітникам OpenAI компенсаційні пакети на суму понад…

18.06.2025