Skip to content

Latest commit

 

History

History

css-in-javascript

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 

Руководство по написанию CSS-in-JavaScript кода от Airbnb

Наиболее разумный подход к написанию CSS-in-JavaScript кода

Оглавление

  1. Именование
  2. Порядок
  3. Вложенность
  4. Inline
  5. Темы

Именование

  • Используйте верблюжийРегистр (camelCase) для ключей объекта (т.е. "селекторы").

    Почему? Мы получаем доступ к этим ключам, как свойствам объекта styles в компоненте, поэтому удобнее использовать верблюжийРегистр.

    // плохо
    {
      'bermuda-triangle': {
        display: 'none',
      },
    }
    
    // хорошо
    {
      bermudaTriangle: {
        display: 'none',
      },
    }
  • Используйте подчёркивание для модификаторов других стилей.

    Почему? Подобно БЭМ, это соглашение даёт понять, что стили предназначены для модификации элемента, которому предшествует символ подчёркивания. Подчёркивания не надо брать в кавычки, поэтому они предпочтительнее других символов, таких как тире.

    // плохо
    {
      bruceBanner: {
        color: 'pink',
        transition: 'color 10s',
      },
    
      bruceBannerTheHulk: {
        color: 'green',
      },
    }
    
    // хорошо
    {
      bruceBanner: {
        color: 'pink',
        transition: 'color 10s',
      },
    
      bruceBanner_theHulk: {
        color: 'green',
      },
    }
  • Используйте selectorName_fallback для набора резервных стилей.

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

    // плохо
    {
      muscles: {
        display: 'flex',
      },
    
      muscles_sadBears: {
        width: '100%',
      },
    }
    
    // хорошо
    {
      muscles: {
        display: 'flex',
      },
    
      muscles_fallback: {
        width: '100%',
      },
    }
  • Используйте отдельный селектор для наборов резервных стилей.

    Почему? Сохранение резервных стилей, содержащихся в отдельном объекте, разъясняет их цель, что улучшает читаемость.

    // плохо
    {
      muscles: {
        display: 'flex',
      },
    
      left: {
        flexGrow: 1,
        display: 'inline-block',
      },
    
      right: {
        display: 'inline-block',
      },
    }
    
    // хорошо
    {
      muscles: {
        display: 'flex',
      },
    
      left: {
        flexGrow: 1,
      },
    
      left_fallback: {
        display: 'inline-block',
      },
    
      right_fallback: {
        display: 'inline-block',
      },
    }
  • Используйте абстрактные имена (такие как "small", "medium" и "large"), чтобы назвать контрольные точки медиавыражений.

    Почему? Обычно используемые имена, такие как "phone", "tablet" и "desktop" не соответствуют характеристикам устройств в реальности. Использование этих имён задаёт неправильные ожидания.

    // плохо
    const breakpoints = {
      mobile: '@media (max-width: 639px)',
      tablet: '@media (max-width: 1047px)',
      desktop: '@media (min-width: 1048px)',
    };
    
    // хорошо
    const breakpoints = {
      small: '@media (max-width: 639px)',
      medium: '@media (max-width: 1047px)',
      large: '@media (min-width: 1048px)',
    };

⬆ к оглавлению

Порядок

  • Определяйте стили после компонента.

    Почему? Мы используем компонент высшего порядка для темизации наших стилей, которые естественно используются после определения компонента. Передача объекта стилей непосредственно в функции уменьшает косвенность.

    // плохо
    const styles = {
      container: {
        display: 'inline-block',
      },
    };
    
    function MyComponent({ styles }) {
      return (
        <div {...css(styles.container)}>
          Never doubt that a small group of thoughtful, committed citizens can
          change the world. Indeed, it’s the only thing that ever has.
        </div>
      );
    }
    
    export default withStyles(() => styles)(MyComponent);
    
    // хорошо
    function MyComponent({ styles }) {
      return (
        <div {...css(styles.container)}>
          Never doubt that a small group of thoughtful, committed citizens can
          change the world. Indeed, it’s the only thing that ever has.
        </div>
      );
    }
    
    export default withStyles(() => ({
      container: {
        display: 'inline-block',
      },
    }))(MyComponent);

⬆ к оглавлению

Вложенность

  • Оставляйте пустую строку между соседними блоками на одном и том же уровне отступов.

    Почему? Пробельное пространство улучшает читаемость и уменьшает вероятность конфликтов при слиянии.

    // плохо
    {
      bigBang: {
        display: 'inline-block',
        '::before': {
          content: "''",
        },
      },
      universe: {
        border: 'none',
      },
    }
    
    // хорошо
    {
      bigBang: {
        display: 'inline-block',
    
        '::before': {
          content: "''",
        },
      },
    
      universe: {
        border: 'none',
      },
    }

⬆ к оглавлению

Inline

  • Используйте inline-стили там, где стили изменяют свои значения (например, через свойства (props)).

    Почему? Создание темизированных таблиц стилей является дорогостоящей операцией, поэтому они лучше всего подходят для дискретных наборов стилей.

    // плохо
    export default function MyComponent({ spacing }) {
      return (
        <div style={{ display: 'table', margin: spacing }} />
      );
    }
    
    // хорошо
    function MyComponent({ styles, spacing }) {
      return (
        <div {...css(styles.periodic, { margin: spacing })} />
      );
    }
    export default withStyles(() => ({
      periodic: {
        display: 'table',
      },
    }))(MyComponent);

Темы

  • Используйте абстрактный слой, такой как react-with-styles, чтобы включить темизацию. react-with-styles предоставляет такие инструменты, как withStyles(), ThemedStyleSheet и css(), которые используются в некоторых примерах в этой документации.

Почему? Полезно иметь набор общих переменных для стилизации компонентов. Использование слоя абстракции делает это более удобным. К тому же, это может помочь предотвратить тесную связь компонентов с какой-либо конкретной базовой реализацией, что даёт вам больше свободы.

  • Определяйте цвета только в темах.

    // плохо
    export default withStyles(() => ({
      chuckNorris: {
        color: '#bada55',
      },
    }))(MyComponent);
    
    // хорошо
    export default withStyles(({ color }) => ({
      chuckNorris: {
        color: color.badass,
      },
    }))(MyComponent);
  • Определяйте шрифты только в темах.

    // плохо
    export default withStyles(() => ({
      towerOfPisa: {
        fontStyle: 'italic',
      },
    }))(MyComponent);
    
    // хорошо
    export default withStyles(({ font }) => ({
      towerOfPisa: {
        fontStyle: font.italic,
      },
    }))(MyComponent);
  • Определяйте шрифты как наборы связанных стилей.

    // плохо
    export default withStyles(() => ({
      towerOfPisa: {
        fontFamily: 'Italiana, "Times New Roman", serif',
        fontSize: '2em',
        fontStyle: 'italic',
        lineHeight: 1.5,
      },
    }))(MyComponent);
    
    // хорошо
    export default withStyles(({ font }) => ({
      towerOfPisa: {
        ...font.italian,
      },
    }))(MyComponent);
  • Определяйте базовые единицы сетки в теме (либо как значение, либо как функцию, которая принимает множитель).

    // плохо
    export default withStyles(() => ({
      rip: {
        bottom: '-6912px', // 6 футов
      },
    }))(MyComponent);
    
    // хорошо
    export default withStyles(({ units }) => ({
      rip: {
        bottom: units(864), // 6 футов, предполагая, что наш блок 8px
      },
    }))(MyComponent);
    
    // хорошо
    export default withStyles(({ unit }) => ({
      rip: {
        bottom: 864 * unit, // 6 футов, предполагая, что наш блок 8px
      },
    }))(MyComponent);
  • Определяйте медиазапросы (media queries) только в темах.

    // плохо
    export default withStyles(() => ({
      container: {
        width: '100%',
    
        '@media (max-width: 1047px)': {
          width: '50%',
        },
      },
    }))(MyComponent);
    
    // хорошо
    export default withStyles(({ breakpoint }) => ({
      container: {
        width: '100%',
    
        [breakpoint.medium]: {
          width: '50%',
        },
      },
    }))(MyComponent);
  • Определяйте сложные фолбэки в темах.

    Почему? Многие реализации CSS-in-JavaScript объединяют стили вместе, что делает определение фолбэка для одного и того же свойства (например, display) немного сложным. Чтобы сохранить подход единым, поместите эти фолбэки в тему.

    // плохо
    export default withStyles(() => ({
      .muscles {
        display: 'flex',
      },
    
      .muscles_fallback {
        'display ': 'table',
      },
    }))(MyComponent);
    
    // хорошо
    export default withStyles(({ fallbacks }) => ({
      .muscles {
        display: 'flex',
      },
    
      .muscles_fallback {
        [fallbacks.display]: 'table',
      },
    }))(MyComponent);
    
    // хорошо
    export default withStyles(({ fallback }) => ({
      .muscles {
        display: 'flex',
      },
    
      .muscles_fallback {
        [fallback('display')]: 'table',
      },
    }))(MyComponent);
  • Создайте как можно меньше пользовательских тем. Многие приложения могут иметь только одну тему.

  • Пространство имён темы во вложенном объекте должно содержать уникальный и наглядный ключ.

    // плохо
    ThemedStyleSheet.registerTheme('mySection', {
      mySectionPrimaryColor: 'green',
    });
    
    // хорошо
    ThemedStyleSheet.registerTheme('mySection', {
      mySection: {
        primaryColor: 'green',
      },
    });

CSS каламбуры взяты из Saijo George.