Pull to refresh

Эффективное создание компонентов с помощью styled system

Reading time4 min
Views15K
image

Для стилизации react компонентов наша команда использует styled-components.

О styled-components уже есть статьи на Хабре, поэтому подробно останавливаться на этом не будем.

Знакомство с Styled components
Лучше, быстрее, мощнее: styled-components v4

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

Например во многих компонентах мы писали так:

  padding-top: ${props => props.paddingTop || '0'};
  padding-bottom: ${props => props.paddingBottom || '0'};
  padding-right: ${props => props.paddingRight || '0'};
  padding-left: ${props => props.paddingLeft || '0'};

Styled system


Копирование повторяющихся свойств начало раздражать, и мы вынесли повторяющиеся куски кода в отдельные переиспользуемые функции. Но я задумался о том, что возможно кто-то уже реализовал подобное до нас и наверняка более красиво и универсально. Начал гуглить и нашел styled system.

Styled-System предоставляет набор стилевых функций. Каждая функция стиля предоставляет собственный набор свойств, которые стилизуют элементы на основе значений, определенных в теме приложения. styled system имеет богатый API с функциями для большинства свойств CSS.

Пример использования styled system на основе styled-components

import { space, width, fontSize, color } from 'styled-system';
import styled, { ThemeProvider } from 'styled-components';
import theme from './theme';

const Box = styled.div`
  ${space}
  ${width}
  ${fontSize}
  ${color}
`;

render(
  <ThemeProvider theme={theme}>
    <Box p={3} bg="whites.10" color="orange">
      This is a Box
    </Box>
  </ThemeProvider>,
);

Основные преимущества


  • Добавляет свойства, которые можно использовать в собственных темах
  • Быстрая установка отзывчивых font-size, margin, padding, width и других свойств css через props
  • Масштабируемость типографики
  • Масштабируемость отступов margin и padding
  • Поддержка любой цветовой палитры
  • Работает с большинством библиотек css-in-js, включая styled-components и emotion
  • Используется в Rebass, Rebass Grid, и Priceline Design System

Подключение темы


Выше я приводил пример кода, в котором используется ThemeProvider. Мы передаем в провайдер нашу тему, а styled system обращается к ней через props.

Пример нашей темы

export const theme = {
  /** Размер шрифтов */
  fontSizes: [
    12, 14, 16, 18, 24, 32, 36, 72, 96
  ],
  /** Отступы и границы */
  space: [
    // margin and padding
    0, 4, 8, 16, 32, 64, 128, 256
  ],
  /** Общие цвета */
  colors: {
    UIClientError: '#ff6c00',
    UIServerError: '#ff0000',
    UITriggerRed: '#fe3d00',
    UITriggerBlue: '#00a9f6',
    UIModalFooterLightBlueGray: '#f3f9ff',
    UIModalTitleDefault: colorToRgba('#5e6670', 0.4),
    UICheckboxIconCopy: colorToRgba('#909cac', 0.2)
  },
  /** Размеры кнопок */
  buttonSizes: {
    xs: `
      height: 16px;
      padding: 0 16px;
      font-size: 10px;
    `,
    sm: `
      height: 24px;
      padding: 0 24px;
      font-size: 13px;
    `,
    md: `
      height: 34px;
      padding: 0 34px;
      font-size: 14px;
      letter-spacing: 0.4px;
    `,
    lg: `
      height: 56px;
      padding: 0 56px;
      font-size: 20px;
    `,
    default: `
      height: 24px;
      padding: 0 30px;
      font-size: 13px;
    `,
  },
  /** Цвета кнопок */
  buttonColors: {
    green: `
      background-color: #a2d628;
      color: ${colorToRgba('#a2d628', 0.5)};
    `,
    blue: `
      background-color: #507bfc;
      color: ${colorToRgba('#507bfc', 0.5)};
    `,
    lightBlue: `
      background-color: #10aee7;
      color: ${colorToRgba('#10aee7', 0.5)};
    `,
    default: `
      background-color: #cccccc;
      color: ${colorToRgba('#cccccc', 0.5)};
    `
  }
}

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

Например мы передали компоненту color=«red». В объекте темы нет значения color.red, но значение red будет транслироваться в css как red. Таким образом после транспиляции в инспекторе мы увидим

color: red;


Другие примеры использования значений темы
// font-size: 24px (theme.fontSizes[4])
<Box fontSize={4} />

// margin: 16px (theme.space[3])
<Box m={3} />

// color: #ff6c00 (theme.colors.UIClientError)
<Box color="UIClientError" />

// background color (theme.colors.UITriggerBlue)
<Box bg="UITriggerBlue" />

// width: 50%
<Box width={1/2} />

Responsive styles


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

<Box
  width={[
    1,    // 100% below the smallest breakpoint
    1/2,  // 50% from the next breakpoint and up
    1/4   // 25% from the next breakpoint and up
  ]}
/>

// responsive font size
<Box fontSize={[ 1, 2, 3, 4 ]} />

// responsive margin
<Box m={[ 1, 2, 3, 4 ]} />

// responsive padding
<Box p={[ 1, 2, 3, 4 ]} />

Variants


styled system позволяет нам определять переиспользуемые объекты в нашей теме, которые содержат наборы цветов, стили текста и тп. Например в нашей теме, представленной выше, мы
используем варианты размеров и цветов кнопок.

  /** Размеры кнопок */
  buttonSizes: {
    xs: `
      height: 16px;
      padding: 0 16px;
      font-size: 10px;
    `,
    sm: `
      height: 24px;
      padding: 0 24px;
      font-size: 13px;
    `,
    default: `
      height: 24px;
      padding: 0 30px;
      font-size: 13px;
    `,
  },
  /** Цвета кнопок */
  buttonColors: {
    green: `
      background-color: #a2d628;
      color: ${colorToRgba('#a2d628', 0.5)};
    `,
    blue: `
      background-color: #507bfc;
      color: ${colorToRgba('#507bfc', 0.5)};
    `,
    lightBlue: `
      background-color: #10aee7;
      color: ${colorToRgba('#10aee7', 0.5)};
    `,
    default: `
      background-color: #cccccc;
      color: ${colorToRgba('#cccccc', 0.5)};
    `
  }

Реализация варианта:

/** Для размеров кнопок */
export const buttonSize = variant({
  /** Свойство компонента */
  prop: 'size',
  /** Свойство темы*/
  key: 'buttonSizes'
});

/** Для цветов кнопок */
export const buttonColor = variant({
  /** Свойство компонента */
  prop: 'colors',
  /** Свойство темы*/
  key: 'buttonColors'
});


Компонент Button
/** Описание компонента */
export const Button = styled(Box.withComponent('button'))`
  ${buttonSize}
  ${buttonColor}
`;

Button.propTypes = {
  ...buttonSize.propTypes,
  ...buttonColor.propTypes,
}

Пример использования кнопки размера medium синего цвета

<Button 
   size="md"
   colors="blue"
/>

Более подробное описание и документация styled system на оф. странице в github

UPD: во время написания статьи styled system обзавелся собственной страницей с документацией и примерами https://styled-system.com/.
Tags:
Hubs:
Total votes 15: ↑15 and ↓0+15
Comments12

Articles