Кто сказал styled-components?

Анна Селезнёва, Spiral Scout

Кто сказал
styled-components?

GDG Minsk February Meetup, 28 февраля 2019

Обо мне

Анна Селезнёва

#freehugs

План

  1. История появления
  2. Устройство и использование
  3. Расширенные возможности
  4. Оптимизация и отладка
  5. Достоинства и недостатки
-in-JS
Источник картинки: Medium

Организация файлов v0

Организация файлов v1

Организация файлов v2

Разметка v0

      <button class="button">
  Submit
</button>

<button class="armageddon">
  Reset
</button>
      
    

Разметка v1

      <button class="button">
  Submit
</button>

<button class="button button_red">
  Reset
</button>
      
    

Разметка v2

      import styles from './style.css';
    
      <button className={styles.button}>
  Submit
</button>

<button className={`${styles.button} ${red ? styles.buttonRed : ''}`}>
  Reset
</button>
      
    

Разметка v3

      <Button>
  Submit
</Button>

<Button red>
  Reset
</Button>
      
    

Стили v0

      .button {
  background: blue;
  color: white;
}

.button_red {
  background: red;
}
      
    

Стили v1

      .button {
  background: blue;
  color: white;

  &_red {
    background: red;
  }
}
      
    

Стили v2

      const Button = 🎁`
  background: blue;
  color: white;

  ${props => props.red && css`
    background: red;
  `}
`;
      
    

by @okonet

npm init 16.08.2016

v4.1.3

Поехали!

      import styled from 'styled-components';
      
    
      styled(element)`` 🎉
      
    

Устройство

      const Button = styled('button')``
    

аналогично

      const Button = ({ children }) =>
  <button>{children}</button>
      
    

Устройство

      React.createElement(
  elementToBeCreated,
  propsForElement
);
      
    

Использование

      styled('button')``;
    

аналогично

      styled.button``;
    

Тегированный шаблонный литерал

      
tag`This ${component} has ${styles}`
    

аналогично

      tag(['This ', ' has '], component, styles)
    

Использование

        const RedButton = styled.button`
  background: red;
  color: white;
`;
      
    
        <RedButton>Click</RedButton>
      
    

Результат

      <button class="rDbtTn">Click</button>
      
    

Результат

      <style data-styled-components="">
  .rDbtTn {
    background: red;
    color: white;
  }
</style>
      
    

Свойства

        <Button background="blue">
      
    
      const Button = styled.button`
  background: ${({ background }) => background};
  color: white;
`;
      
    

Наследование

      const Button = styled.button`
  background: blue;
  color: white;
`;

const RedButton = styled(Button)`
  background: red;
`;
      
    

Наследование

      import { Link } from 'react-router-dom';

const RedLink = styled(Link)`
  color: red;
`;
      
    

Атрибуты

      const Button = styled.button.attrs(({ type }) => ({
  type: type || 'button',
}))`
  background: blue;
`;
      
    

Подмена тега

      <Button
  as="a"
  href="/next_page"
>
  Skip
</Button>
      
    

Подмена тега

      import { Link } from 'react-router-dom';
    
      <Button
  as={Link}
  to="/next_page"
>
  Skip
</Button>
      
    

Миксин

      import { css } from 'styled-components';

const blueOrRedBackground = css`
  background: ${props => props.red ? 'red' : 'blue'};
`;
/* или */
const blueOrRedBackground = props => css`
  background: ${props.red ? 'red' : 'blue'};
`;
      
    

Миксин

      export const Button = styled.button`
  ${blueOrRedBackground};
`;
export const Square = styled.div`
  width: 100px;
  height: 100px;
  ${blueOrRedBackground};
`;
      
    

Анимации

      import styled, { keyframes } from 'styled-components';

const spin = keyframes`
  to: { transform: rotate(360deg); }
`;
const Spinner = styled.div`
  animation: ${spin} 1s linear infinite;
`;
      
    

Глобальные стили

      import { createGlobalStyle } from 'styled-components';

const GlobalStyle = createGlobalStyle`
  body {
    color: red;
  };
`;
      
    

Глобальные стили

      
<React.Fragment>
  <GlobalStyle />
  <App />
</React.Fragment>
      
    

Темы

export const theme = {
  color: {
    primary: 'blue',
    success: 'green',
    error: 'red',
  }
};
    

Темы

import { ThemeProvider } from 'styled-components';
      <ThemeProvider theme={theme}>
  <App />
</ThemeProvider>
    

Темы

const Button = styled.button`
  background: ${({ theme }) => theme.color.success};
`;
    

Ссылка на элемент

        <Button ref={ref => { this.buttonRef = ref }}>
  Submit
</Button>
      
    

Утилиты

yarn add polished

Polished — это, по сути Lodash в мире CSS-в-JS

Mail.ru

Polished

      import { hideVisually } from 'polished';

const div = styled.div`
  ${hideVisually()};
`;
      
    

Polished

Результат:

      {
  border: 0;
  clip: rect(0 0 0 0);
  clipPath: inset(50%);
  height: 1px;
  margin: -1px;
  overflow: hidden;
  padding: 0;
  position: absolute;
  whiteSpace: nowrap;
  width: 1px;
}
      
    

Polished

      radialGradient, ellipsis, timingFunctions, darken, lighten
    

и многое другое

polished.js.org

Сброс стилей

      import styledNormalize from 'styled-normalize';
/* или */
import styledSanitize from 'styled-sanitize';

const GlobalStyle = createGlobalStyle`
  ${styledNormalize}
  ...
`;
      
    

Babel-плагин

      yarn add babel-plugin-styled-components
      
    
.babelrc
      {
  "plugins": ["babel-plugin-styled-components"]
}
      
    

Отладка

      <button class="Button-stLdCm stLdCm" />
    

вместо

      <button class="stLdCm" />
    

Production

env.production
      "plugins": [
  [
    "babel-plugin-styled-components",
    { "displayName": false }
  ]
]

    

Линтинг

      stylelint-processor-styled-components
stylelint-config-styled-components
stylelint-config-recommended
      
    

Линтинг

.stylelintrc
      {
  "processors": ["stylelint-processor-styled-components"],
  "extends": [
    "stylelint-config-recommended",
    "stylelint-config-styled-components"
  ]
}
      
    

Тестирование

      import 'jest-styled-components';

test('it works', () => {
  const tree = renderer.create(<RedButton />).toJSON();

  expect(tree).toHaveStyleRule('background', 'red');
});
      
    

В чём подвох?

Runtime

Нечитабельный код

        export const marginProps = props => css`
  ${props.marginBottom && `margin-bottom: ${typeof (props.marginBottom) === "string" ? props.marginBottom : "1em"}`};
  ${props.marginTop && `margin-top: ${typeof (props.marginTop) === "string" ? props.marginTop : "1em"}`};
  ${props.marginLeft && `margin-left: ${typeof (props.marginLeft) === "string" ? props.marginLeft : "1em"}`};
  ${props.marginRight && `margin-right: ${typeof (props.marginRight) === "string" ? props.marginRight : "1em"}`};
  ${props.margin && `margin: ${typeof (props.margin) === "string" ? props.margin : "1em"}`};
  ${props.marginVertical && `
    margin-top: ${typeof (props.marginVertical) === "string" ? props.marginVertical : "1em"}
    margin-bottom: ${typeof (props.marginVertical) === "string" ? props.marginVertical : "1em"}
  `};
  ${props.marginHorizontal && `
    margin-left: ${typeof (props.marginHorizontal) === "string" ? props.marginHorizontal : "1em"}
    margin-right: ${typeof (props.marginHorizontal) === "string" ? props.marginHorizontal : "1em"}
  `};
`;
        
        
      

Нежелательные атрибуты

      const Square = styled.div`
  width: ${({ size }) => size}px;
  height: ${({ size }) => size}px;
`;
    
      <Square size="100"></Square>
      
    

Нежелательные атрибуты

      
<div size="100" class="..."></div>
      
    

reactjs.org/warnings/unknown-prop.html

Нежелательные атрибуты

      const Square = styled(
  ({size, ...restProps}) => <div {...restProps} />
)`
  width: ${({ size }) => size}px;
  height: ${({ size }) => size}px;
`;
    

Особенности реализации

      const Tag = styled.div`
  font-size: ${({ size }) => size}px;
`;
      
    
      <Tag size={/* anything */} />
    

Особенности реализации


      
<style data-styled-components="">

      
</style>

Over 200 classes were generated for component styled.div

Оптимизация

      const Tag = styled.div.attrs({
  style: ({ size }) => ({ fontSize: `${size}px` })
})`
  ...
`;
      
    

Дополнительные возможности

CSS-in-JS альтернативы

Источник картинки: Medium
Источник картинки: npm trends

Преимущества styled-components

Из документации

Достоинства

Недостатки

Кто сказал styled-components?

Выбор за вами

Спасибо!

asktwi

anna.selezniova

askd.rocks


Презентация: askd.rocks/pres/styled-gdg