Доброго времени суток, друзья!

Представляю вашему вниманию перевод небольшой заметки про использование стилизованных компонентов (далее — СК) в React.

Без лишних слов.

Что такое СК?


СК — это библиотека для React и React Native для создания и управления CSS.

Данное решение относится к концепции «CSS-in-JS», когда вы определяете CSS прямо в JavaScript-файле (т.е. в компоненте в случае с React).

О популярности этого решения в среде React-разработчиков свидетельствует около 8 млн скачиваний в месяц из npm и 30 тыс звезд на GitHub.

Разумеется, для знакомства со СК необходимо хотя бы в общих чертах знать React.

Преимуществами СК является следующее:

  • Это обычный CSS. Да, вы пишете CSS в JS-файле, но синтакис от этого не меняется
  • При использовании СК автоматически добавляются вендорные префиксы, обеспечивающие кроссбраузерность
  • Неиспользуемые стили также автоматически удаляются
  • Более того, автоматически генерируются названия классов компонентов, что избавляет от необходимости использования методогии типа БЭМ

Установка СК


Для использования СК нужно их сначала установить:

npm i styled-components

Далее их нужно импортировать в каждом файле, в котором они будут использоваться:

import styled from 'styled-components'

После этого можно с ними работать.

Создание СК


Откройте проект, над которым вы работаете, или быстро создайте его с помощью npx create-react-app app-name и откройте любой компонент, например, App.js.

Давайте добавим в него наш первый СК:

// App.js
import React from 'react'
import styled from 'styled-components'

// СК
const Button = styled.a`
    background-color: teal;
    color: white;
    padding: 1rem 2rem;
`

const App = () => {
    return (
        <Button>Кнопка</Button>
    )
}

export default App

Разберем данный код:

  • Объявляем название компонента посредством const Button
  • styled предоставляет нам функционал СК
  • Обратите внимание на «a» после styled. Это HTML-тег «a». В СК можно использовать любые HTML-теги (section, h1, div и т.д.)

<Button>, возвращаемый в App, это обычный React-компонент.

В предыдущем примере мы создали СК внутри существующего компонента.

Однако это можно (и даже нужно) сделать в отдельном файле (например, в Button.js):

// Button.js
import styled from 'styled-components'

const Button = styled.a`
    background-color: teal;
    color: white;
    padding: 1rem 2rem;
`

export default Button

После этого мы можем импортировать Button как любой другой компонент:

// App.js
import React from 'react'
import styled from 'styled-components'
// импортируем кнопку
import Button from './Button'

const App = () => {
    return (
        <Container>
            <Button>Кнопка</Button>
        </Container>
    )
}

export default App

Готово.

Поздравляю, вы только что создали свой первый СК.

Использование пропсов для редактирования СК


Представьте, что у вас есть компонент Button, и вам нужно применять к нему разные стили в зависимости от назначения кнопки (primary — главная или основная, secondary — второстепенная или дополнительная, danger — опасность, предупреждение и т.д.)

Для этого можно использовать пропсы.

Рассмотрим пример.

Здесь мы рендерим две кнопки, стиль одной из который зависит от пропса:

// App.js
import React from 'react'
import styled from 'styled-components'
import Button from './Button'

const App = () => {
    return (
        <>
            <Button>Кнопка</Button>
            <Button primary>Главная кнопка</Button>
        </>
    )
}

export default App

Обратите внимание на использование сокращенного синтаксиса фрагмента (<></>).

После этого добавляем динамические стили в компонент Button:

// Button.js
import styled from 'styled-components'

const Button = styled.a`
    display: imline-block;
    border-radius: 3px;
    padding: 0.5rem 0;
    margin: 0.5rem 1rem;
    width: 11rem;
    border: 2px solid white;
    background: ${props => props.primary ? 'white' : 'palevioletred'};
    color: ${props => props.primary ? 'palevioletred' : 'white'};
`

export default Button

Здесь мы возвращаем то или иное значение CSS-свойства в зависимости от пропса.

Выражение background: ${props => props.primary? 'white': 'palevioletred'} означает, что если пропс будет иметь значение true, то цвет фона будет белым, а цвет текста — palevioletred.

Такой способ можно использовать в простых случаях, однако он не подходит для случаев, когда нужно обрабатывать несколько пропсов, а также при наличии нескольких свойств, зависящих от них.

Поэтому имеет смысл импортировать { css } из styled-components:

// Button.js
import styled, { css } from 'styled-components'

const Button = styled.a`
display: inline-block;
    border-radius: 3px;
    padding: 0.5rem 0;
    margin: 0.5rem 1rem;
    width: 11rem;
    background: transparent;
    color: white;
    border: 2px solid white;

    ${props => props.primary && css`
        background: white;
        color: palevioletred;
    `}
`

export default Button

Это позволяет использовать динамические стили для разных пропсов.

Например, добавим стили для danger:

// Button.js
import styled, { css } from 'styled-components'

const Button = styled.a`
display: inline-block;
    border-radius: 3px;
    padding: 0.5rem 0;
    margin: 0.5rem 1rem;
    width: 11rem;
    background: transparent;
    color: white;
    border: 2px solid white;

    ${props => props.primary && css`
        background: white;
        color: palevioletred;
    `}

    ${props => props.danger && css`
        backround: red;
        color: white;
    `}
`

export default Button

Отлично.

Как сделать кнопку более отзывчивой или адаптированной?

Использование медиа-запросов


Для этого следует добавить медиа-запросы в шаблон (внутрь шаблонного или строкового литерала):

// Button.js
const Button = styled.a`
    display: inline-block;
    border-radius: 3px;
    padding: 0.5rem 0;
    margin: 0.5rem 1rem;
    width: 9rem;
    background: transparent;
    color: white;
    border: 2px solid white;

    @media (min-width: 768px) {
        padding: 1rem 2rem;
        width: 11rem;
    }

    @media (min-width: 1024px) {
        padding: 1.5rem 2.5rem;
        width: 13rem;
    }
`

export default Button

Обработка псевдоселекторов


Это делается по аналогии с медиа-запросами.

Например, добавим обработку наведения курсора на кнопку (псевдоселектор hover):

// Button.js
import styled from 'styled-components'

const Button = styled.a`
    display: inline-block;
    border-radius: 3px;
    padding: 0.5rem 0;
    margin: 0.5rem 1rem;
    width: 9rem;
    background: transparent;
    color: white;
    border: 2px solid white;

    :hover {
        border-color: green;
    }
`

export default Button

Создание глобальных стилей


Основная ментальная модель React — все есть компонент.

Для этого интерфейс приложения разбивается на отдельные части, а затем эти части собираются в один файл таким образом, чтобы сохранялась возможность расширения или масштабирования приложения.

Такой подход имеет ряд преимуществ, но существует одна проблема: как использовать одинаковые стили для нескольких компонентов? Т.е. как применить глобальные стили?

Мы можем, например, захотеть следующее:

  • Установить шрифт для всего текста
  • Установить фон для всех страниц
  • Перезаписать некоторые браузерные стили (т.е. стили, устанавливаемые по умолчанию)

В СК для этого используется функция createClodabStyle.

Сначала откройте основной компонент приложения.

Таким компонентом, обычно, является App.js.

Затем импортируйте в него createClodabStyle и определите некоторые стили в компоненте GlobalStyle (вы можете назвать его как угодно):

// App.js
import React from 'react'
import styled, { createGlobalStyle } from 'styled-components'
import { Container, Nav, Content } from '../components'

const GlobalStyle = createGlobalStyle`
    body {
        margin: 0;
        padding: 0;
        background: teal;
        font-family: Open-Sans, Helvetica, Sans-Serif;
    }
`

const App = () => {
    return (
        <Container>
            <Nav />
            <Content />
        </Container>
    )
}

export default App

Для того, чтобы это работало, нужно добавить созданный компонент в начало App:

// App.js
import React from 'react'
import styled, { createClodabStyle } from 'styled-components'
import { Container, Nav, Content } from '../components'

const GlobalStyle = createGlobalStyle`
    body {
        margin: 0;
        padding: 0;
        background: teal;
        font-family: Open-Sans, Helvetica, Sans-Serif;
    }
`

const App = () => {
    return (
        <>
            <GlobalStyle />
            <Container>
                <Nav />
                <Content />
            </Container>
        </>
    )
}

export default App

Добавление GlobalStyle в качестве узла в начало виртуального DOM является обязательным требованием для использования глобальных стилей.

Надеюсь, статья была вам полезной. Благодарю за внимание.