一个 普遍适用的CSS-in-JavaScript方法

目录

  1. 命名
  2. 顺序
  3. 嵌套
  4. 内联
  5. 主题

命名

  • 对象的键名使用驼峰命名法(如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.

余下全文(1/3)

本文最初发表在www.zcfy.cc,文章内容属作者个人观点,不代表本站立场。

分享这篇文章:

请关注我们:

发表评论

电子邮件地址不会被公开。 必填项已用*标注