Руководство по написанию CSS-in-JavaScript кода от Airbnb
Наиболее разумный подход к написанию CSS-in-JavaScript кода
Оглавление
Именование
-
Используйте верблюжийРегистр (
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= /> ); } // хорошо 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.