这篇文章也发在我的博客,欢迎围观?
Translated by FrankZhang.
如有错误,敬请不吝告知,谢谢!
Airbnb CSS-in-JavaScript 风格指南
一个 普遍适用的CSS-in-JavaScript方法
目录
命名
-
对象的键名使用驼峰命名法(如Airbnb CSS-in-JavaScript Style Guide)
为什么呢?因为我们在组件中将这些键作为
styles
对象的属性获取,使用驼峰命名是最为方便的方法。// bad { 'bermuda-triangle': { display: 'none', }, } // good { bermudaTriangle: { display: 'none', }, } 复制代码
-
对其他样式的修改器(modifier),使用下划线命名
为什么?类似BEM, 这个命名惯例使它非常清晰地表明这个类就是要用来修改前面添加了下划线的元素的。下划线不需要引用,所以比起其他诸如破折号的元素,更倾向于使用它们。
// bad { bruceBanner: { color: 'pink', transition: 'color 10s', }, bruceBannerTheHulk: { color: 'green', }, } // good { bruceBanner: { color: 'pink', transition: 'color 10s', }, bruceBanner_theHulk: { color: 'green', }, } 复制代码
-
整套的降级适配样式(sets of fallback),使用
selectorName_fallback
原因? 类似于修改器,保持命名的持续性可以帮助更好地反映出,原始样式和适配更多浏览器所使用的适配样式之间的关系。
// bad { muscles: { display: 'flex', }, muscles_sadBears: { width: '100%', }, } // good { muscles: { display: 'flex', }, muscles_fallback: { width: '100%', }, } 复制代码
-
整套的降级适配样式,使用独立的选择器
原因?保持降级适配样式一致被包含在一个独立的对象里面,使他们的目的更清晰明了,更加加强了可读性。
// bad { muscles: { display: 'flex', }, left: { flexGrow: 1, display: 'inline-block', }, right: { display: 'inline-block', }, } // good { muscles: { display: 'flex', }, left: { flexGrow: 1, }, left_fallback: { display: 'inline-block', }, right_fallback: { display: 'inline-block', }, } 复制代码
-
媒体查询的节点,使用与设备无关的名字(诸如"small","medium","large")命名
为什么?通常使用的名字诸如"phone","tablet"以及"desktop",并没有完全吻合真实设备的特征。因此使用这些名字会(对这些媒体查询的效果)产生错误的期待。
// bad const breakpoints = { mobile: '@media (max-width: 639px)', tablet: '@media (max-width: 1047px)', desktop: '@media (min-width: 1048px)', }; // good const breakpoints = { small: '@media (max-width: 639px)', medium: '@media (max-width: 1047px)', large: '@media (min-width: 1048px)', }; 复制代码
顺序
-
在组件之后定义样式
为什么? 我们使用一个更高阶的组件去主体化我们的样式,这样这些样式自然地在组件定义之后被会被使用。将这些样式对象直接传入这个函数中可以减少冗余
// bad const styles = { container: { display: 'inline-block', }, }; function MyComponent({ styles }) { return ( `<div>` 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); // good function MyComponent({ styles }) { return ( `<div>` 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); 复制代码
嵌套
-
在同一个缩进层级的相邻的样式块之间,留出一个空行
为什么?留空可以提高可读性,以及减少合并冲突的可能性
// bad { bigBang: { display: 'inline-block', '::before': { content: "''", }, }, universe: { border: 'none', }, } // good { bigBang: { display: 'inline-block', '::before': { content: "''", }, }, universe: { border: 'none', }, } 复制代码
内联
-
Use inline styles for styles that have a high cardinality (e.g. uses the value of a prop) and not for styles that have a low cardinality.
Why? Generating themed stylesheets can be expensive, so they are best for discrete sets of styles.
// bad export default function MyComponent({ spacing }) { return ( `<div />` ); } // good function MyComponent({ styles, spacing }) { return ( `<div />` ); } export default withStyles(() => ({ periodic: { display: 'table', }, }))(MyComponent); 复制代码
主题
- 使用一个抽象层,例如react-with-styles 来使主题化成为可能。 react-with-styles 让我们可以使用诸如
withStyles()
,ThemedStyleSheet
, 和css()
,这些在文中某些代码中已经使用到的方法
为什么? 使用一系列共享的变量去改变你组件的样式是非常有用的。使用一个抽象层使得这变得更加方便。另外,这可以防止你的组件与任何特定的底层实现紧密耦合,让你可以更自由地使用
-
仅在主题中定义颜色
// bad export default withStyles(() => ({ chuckNorris: { color: '#bada55', }, }))(MyComponent); // good export default withStyles(({ color }) => ({ chuckNorris: { color: color.badass, }, }))(MyComponent); 复制代码
-
仅在主题中定义字体
// bad export default withStyles(() => ({ towerOfPisa: { fontStyle: 'italic', }, }))(MyComponent); // good export default withStyles(({ font }) => ({ towerOfPisa: { fontStyle: font.italic, }, }))(MyComponent); 复制代码
-
将字体作为系列相关样式进行定义
// bad export default withStyles(() => ({ towerOfPisa: { fontFamily: 'Italiana, "Times New Roman", serif', fontSize: '2em', fontStyle: 'italic', lineHeight: 1.5, }, }))(MyComponent); // good export default withStyles(({ font }) => ({ towerOfPisa: { ...font.italian, }, }))(MyComponent); 复制代码
-
在主题中定义基础网格单位(可以是一个值,也可以是一个函数)
// bad export default withStyles(() => ({ rip: { bottom: '-6912px', // 6 feet }, }))(MyComponent); // good export default withStyles(({ units }) => ({ rip: { bottom: units(864), // 6 feet, assuming our unit is 8px }, }))(MyComponent); // good export default withStyles(({ unit }) => ({ rip: { bottom: 864 * unit, // 6 feet, assuming our unit is 8px }, }))(MyComponent); 复制代码
-
仅在主题中定义媒体查询
// bad export default withStyles(() => ({ container: { width: '100%', '@media (max-width: 1047px)': { width: '50%', }, }, }))(MyComponent); // good export default withStyles(({ breakpoint }) => ({ container: { width: '100%', [breakpoint.medium]: { width: '50%', }, }, }))(MyComponent); 复制代码
-
在主题中定义奇淫技巧的降级适配样式
为什么?许多CSS-in-JavaScript实现将样式对象合并在一起,这使得为相同的属性指定降级样式会有那么一点取巧。 为了保持方法统一,建议将这些降级样式放入主题中
// bad export default withStyles(() => ({ .muscles { display: 'flex', }, .muscles_fallback { 'display ': 'table', }, }))(MyComponent); // good export default withStyles(({ fallbacks }) => ({ .muscles { display: 'flex', }, .muscles_fallback { [fallbacks.display]: 'table', }, }))(MyComponent); // good export default withStyles(({ fallback }) => ({ .muscles { display: 'flex', }, .muscles_fallback { [fallback('display')]: 'table', }, }))(MyComponent); 复制代码
-
创建尽量少的自定义主题。很多应用都只有一个主题。
-
命名空间自定义主题设置在一个拥有唯一的描述性键名的嵌套对象中。
// bad ThemedStyleSheet.registerTheme('mySection', { mySectionPrimaryColor: 'green', }); // good ThemedStyleSheet.registerTheme('mySection', { mySection: { primaryColor: 'green', }, }); 复制代码
CSS puns 改编自 Saijo George.