React項目 - 幾種CSS實踐

前言
團隊在使用react時,不斷探索,使用了不少不一樣的css實現方式,此篇blog總結了,react項目中常見的幾種css解決方案:inline-style/radium/style-component,只列舉了團隊項目中用過的一下實現方式,還有其餘的不過多展開css

css的不足
樣式與狀態相關的狀況愈來愈多,須要動態、能直接訪問組件state的css。
一切樣式都是全局,產生的各類命名的痛苦,BEM等命名規則能解決一部分問題,但當你使用三方插件時卻沒法避免命名衝突。react

Vue怎麼解決
scoped 屬性
動態css的語法 v-bind class stylewebpack

react中使用css的標準
是否解決了React開發的痛點:局部css,動態css?
是否支持全部css甚至是sass用法?僞類,嵌套,動畫,媒體查詢?
是否兼容你須要使用的第三方UI庫?
是否能和純css,或者是其餘css框架很好共存,以備遇到特殊狀況能夠有方案B?
性能?大小?web

react 原生css
inline style數組

const textStyles = {
  color: 'white',
  backgroundColor: this.state.bgColor
};

<p style={textStyles}>inline style</p>

缺點:瀏覽器

發明了一套新的 css-in-js 語法,使用駝峯化名稱等一些規則
不支持全部的 css,例如 media queries, browser states (:hover, :focus, :active) and modifiers (no more .btn-primary!).
inline 寫法若是直接同行寫影響代碼閱讀,不清晰優雅

Radium
Features:
Conceptually simple extension of normal inline styles 原生css擴展,改良版
Browser state styles to support :hover, :focus, and :active 支持瀏覽器樣式
Media queries 支持媒體查詢
Automatic vendor prefixing 自動組件前綴 scope
Keyframes animation helper 寫動畫更方便,封裝Keyframes
ES6 class and createClass support 支持react類和createClass的寫法sass

簡單使用:babel

<Button kind="primary">Radium Button</Button>

import Radium from 'radium';
import React from 'react';
import color from 'color';

class Button extends React.Component {
  static propTypes = {
    kind: PropTypes.oneOf(['primary', 'warning']).isRequired
  };

  render() {
    return (
      <button
        // 多個樣式使用數組方便合併
        style={[
          styles.base,
          styles[this.props.kind]
        ]}>
        {this.props.children}
      </button>
    );
  }
}

// 使用了HOC的方式注入樣式
// Radium's primary job is to apply interactive or media query styles, but even // if you are not using any special styles, the higher order component will still:

// Merge arrays of styles passed as the style attribute
// Automatically vendor prefix the style object
// Radium(config)(component) 還能夠傳入一些配置
Button = Radium(Button);

var styles = {
  base: {
    color: '#fff',
    ':hover': {
      background: color('#0074d9').lighten(0.2).hexString()
    }
  },

  primary: {
    background: '#0074D9'
  },

  warning: {
    background: '#FF4136'
  }
};

keyframes使用app

class Spinner extends React.Component {
  render () {
    return (
      <div>
        <div style={styles.inner} />
      </div>
    );
  }
}

Spinner = Radium(Spinner);

var pulseKeyframes = Radium.keyframes({
  '0%': {width: '10%'},
  '50%': {width: '50%'},
  '100%': {width: '10%'},
}, 'pulse');

var styles = {
  inner: {
    // Use a placeholder animation name in `animation`
    animation: 'x 3s ease 0s infinite',
    // Assign the result of `keyframes` to `animationName`
    animationName: pulseKeyframes,
    background: 'blue',
    height: '4px',
    margin: '0 auto',
  }
};

Css Modules
適用於全部使用 webpack 等打包工具的開發環境框架

{
  loader: "css-loader",
  options: {
    importLoaders: 1,
    modules: true,
    localIdentName: "[name]__[local]___[hash:base64:5]"  // 爲了生成類名不是純隨機
  },
},

import styles from './table.css';

    render () {
        return <div className={styles.table}>
            <div className={styles.row}>
                <div className={styles.cell}>A0</div>
                <div className={styles.cell}>B0</div>
            </div>
        </div>;
    }

/* table.css */
.table {}
.row {}
.cell {}

缺點:

class名必須是駝峯形式,不然不能正常在js裏使用 styles.table 來引用
因爲css模塊化是默認,當你但願使用正常的全局css時,須要經過:local 和 :global 切換,不方便
全部的 className 都必須使用 {style.className} 的形式
寫在外部樣式文件中,沒法處理動態css

優化:

babel-plugin-react-css-modules
 能夠照常寫 'table-size' 之類帶橫槓的類名
 正常書寫字符串類名,不用加style前綴
// .bablerc
{
  "plugins": [
    ["react-css-modules", {
      // options
    }]
  ]
}

缺點:

不過使用 styleName 遇到三方UI庫該怎麼辦呢

補充:
create-react-app v2 直接使用css-moudues和sass
使用方法爲一概將css文件命名爲 XXX.modules.css, 以上例,即爲 table.modules.css, 便可使用。這一解決法的優雅在於,全局的css能夠正常使用,只有帶.modules.css後綴的纔會被modules化

styled-components
使用 ES6 的模板字符串,在js文件裏寫純粹的css。

補充sass經常使用語法

變量:以$開頭/變量須要在字符串之中,在#{}之中
計算: 屬性可使用算式
嵌套: &引用父元素
繼承: @extend
重用: @mixin命令,定義一個代碼塊(能夠傳參數)/@include命令,調用這個mixin
引入文件: @import

// 變量
    $blue : #1875e7;
    $side : left;
    div {
      color : $blue;
    }
    .rounded {
       border-#{$side}-radius: 5px;
    }

// 計算
   body {
    margin: (14px/2);
    top: 50px + 100px;
    right: $var * 10%;
  }

// 嵌套
   a {
    &:hover { color: #ffb3ff; }
  }

// 繼承
    .class1 {
    border: 1px solid #ddd;
  }
    .class2 {
    @extend .class1;
    font-size:120%;
  }

// 重用
    @mixin left($value: 10px) {
    float: left;
    margin-right: $value;
  }
    div {
    @include left(20px);
  }

//引入外部文件
    @import "path/filename.scss"
相關文章
相關標籤/搜索