# Руководство по написанию CSS-in-JavaScript кода от [Airbnb](https://github.com/airbnb/javascript/tree/master/css-in-javascript) *Наиболее разумный подход к написанию CSS-in-JavaScript кода* ## Оглавление 1. [Именование](#naming) 1. [Порядок](#ordering) 1. [Вложенность](#nesting) 1. [Inline](#inline) 1. [Темы](#themes) ## Именование - Используйте верблюжийРегистр (`camelCase`) для ключей объекта (т.е. "селекторы"). > Почему? Мы получаем доступ к этим ключам, как свойствам объекта `styles` в компоненте, поэтому удобнее использовать верблюжийРегистр. ```js // плохо { 'bermuda-triangle': { display: 'none', }, } // хорошо { bermudaTriangle: { display: 'none', }, } ``` - Используйте подчёркивание для модификаторов других стилей. > Почему? Подобно БЭМ, это соглашение даёт понять, что стили предназначены для модификации элемента, которому предшествует символ подчёркивания. Подчёркивания не надо брать в кавычки, поэтому они предпочтительнее других символов, таких как тире. ```js // плохо { bruceBanner: { color: 'pink', transition: 'color 10s', }, bruceBannerTheHulk: { color: 'green', }, } // хорошо { bruceBanner: { color: 'pink', transition: 'color 10s', }, bruceBanner_theHulk: { color: 'green', }, } ``` - Используйте `selectorName_fallback` для набора резервных стилей. > Почему? Подобно модификаторам, сохранение согласованности имён помогает обнаружить взаимосвязь этих стилей со стилями, которые переопределяют их в подходящих браузерах. ```js // плохо { muscles: { display: 'flex', }, muscles_sadBears: { width: '100%', }, } // хорошо { muscles: { display: 'flex', }, muscles_fallback: { width: '100%', }, } ``` - Используйте отдельный селектор для наборов резервных стилей. > Почему? Сохранение резервных стилей, содержащихся в отдельном объекте, разъясняет их цель, что улучшает читаемость. ```js // плохо { 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" не соответствуют характеристикам устройств в реальности. Использование этих имён задаёт неправильные ожидания. ```js // плохо 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)', }; ``` **[⬆ к оглавлению](#Оглавление)** ## Порядок - Определяйте стили после компонента. > Почему? Мы используем компонент высшего порядка для темизации наших стилей, которые естественно используются после определения компонента. Передача объекта стилей непосредственно в функции уменьшает косвенность. ```jsx // плохо 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); ``` **[⬆ к оглавлению](#Оглавление)** ## Вложенность - Оставляйте пустую строку между соседними блоками на одном и том же уровне отступов. > Почему? Пробельное пространство улучшает читаемость и уменьшает вероятность конфликтов при слиянии. ```js // плохо { bigBang: { display: 'inline-block', '::before': { content: "''", }, }, universe: { border: 'none', }, } // хорошо { bigBang: { display: 'inline-block', '::before': { content: "''", }, }, universe: { border: 'none', }, } ``` **[⬆ к оглавлению](#Оглавление)** ## Inline - Используйте inline-стили там, где стили изменяют свои значения (например, через свойства (props)). > Почему? Создание темизированных таблиц стилей является дорогостоящей операцией, поэтому они лучше всего подходят для дискретных наборов стилей. ```jsx // плохо 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](https://github.com/airbnb/react-with-styles), чтобы включить темизацию. *react-with-styles предоставляет такие инструменты, как `withStyles()`, `ThemedStyleSheet` и `css()`, которые используются в некоторых примерах в этой документации.* > Почему? Полезно иметь набор общих переменных для стилизации компонентов. Использование слоя абстракции делает это более удобным. К тому же, это может помочь предотвратить тесную связь компонентов с какой-либо конкретной базовой реализацией, что даёт вам больше свободы. - Определяйте цвета только в темах. ```js // плохо export default withStyles(() => ({ chuckNorris: { color: '#bada55', }, }))(MyComponent); // хорошо export default withStyles(({ color }) => ({ chuckNorris: { color: color.badass, }, }))(MyComponent); ``` - Определяйте шрифты только в темах. ```js // плохо export default withStyles(() => ({ towerOfPisa: { fontStyle: 'italic', }, }))(MyComponent); // хорошо export default withStyles(({ font }) => ({ towerOfPisa: { fontStyle: font.italic, }, }))(MyComponent); ``` - Определяйте шрифты как наборы связанных стилей. ```js // плохо 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); ``` - Определяйте базовые единицы сетки в теме (либо как значение, либо как функцию, которая принимает множитель). ```js // плохо 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) только в темах. ```js // плохо 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`) немного сложным. Чтобы сохранить подход единым, поместите эти фолбэки в тему. ```js // плохо 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); ``` - Создайте как можно меньше пользовательских тем. Многие приложения могут иметь только одну тему. - Пространство имён темы во вложенном объекте должно содержать уникальный и наглядный ключ. ```js // плохо ThemedStyleSheet.registerTheme('mySection', { mySectionPrimaryColor: 'green', }); // хорошо ThemedStyleSheet.registerTheme('mySection', { mySection: { primaryColor: 'green', }, }); ``` --- CSS каламбуры взяты из [Saijo George](https://saijogeorge.com/css-puns/).