Skip to content

Instantly share code, notes, and snippets.

@rafaelsales
Forked from igorsantos07/1 General info.md
Created April 22, 2016 17:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rafaelsales/568332eb58f7acd3f515515b934e09b1 to your computer and use it in GitHub Desktop.
Save rafaelsales/568332eb58f7acd3f515515b934e09b1 to your computer and use it in GitHub Desktop.
CSS tools on React

Main comparison

  1. Traditional CSS

  • Simple approach, known API
  • we would have to deal with namespace conflicts
  • leverages browser caching, storing the entire app style in the first load and reducing following reloads
  1. Style-based implementations

  • Processes JSON-based style rules and creates data to be injected in the component's style attribute, plus some event-wrappers (see next)
  • Can be more powerful but is hackish, as some CSS features do not work on the style attribute (pseudo-selectors for instance)
  • Slower as style takes longer to be processed
  • Heavier: code reuse would be made through separate files (similar to SASS-based), but style contents would still be repeated

Libraries

  • Radium
  1. [Inline] Stylesheet-based implementations

  • Processes JSON-based style rules and creates a hash of classes, to be used in the component's className
  • Might use some browser caching, if the stylesheet is extracted to a file
  • Helps reducing repeated code, as the page stylesheet would be compiled and can be optimized before attaching it to the DOM
  • pure JS approach to features previously seen in different syntaxes such as Less/SASS/SCSS

Libraries

  • Stilr: replaces the same stylesheet node's content
  • JSS + JSS-React: ataches a stylesheet node whenever a new component is instantiated, and detaches when all references are gone

Not yet reviewed

Other smaller libraries

| GHS | GitHub Stars | | DLM | NPM Downloads in last month |

JSS / JSS-React - GH* 872 / 181

Pros

  • avoids issues with namespacing / style collision
  • the initial load is smaller, as there's no single CSS file to be downloaded - instead, small chunks of CSS will be sent to the user
  • Similar to Stilr

Cons

  • CSS impossible to be cached, as different pages would yield different rules - even if you extract the CSS into files, it's still much harder to cache
  • Similar to Stilr

Sample

import React, { Component } from 'react'
import useSheet from 'react-jss'

// You can use jss directly too!
import jss from 'jss'
import vendorPrefixer from 'jss-vendor-prefixer'
jss.use(vendorPrefixer)

const styles = {
  button: {
    'background-color': 'yellow'
  },
  label: {
    'font-weight': 'bold'
  }
}

@useSheet(styles)
export default class Button extends Component {
  render() {
    const { classes } = this.props.sheet

    return (
      <div className={classes.button}>
        <span className={classes.label}>
          {this.props.children}
        </span>
      </div>
    )
  }
}

Radium - CSS in JS - GH*=2.9k

An extension on pure inline CSS as React describes it. Includes what's missing on the React approach, such as pseudo-selectors and media-queries, plus what we expect from preprocessors: math, functions and so on.

Pros

  • style goes inside the component definition file, bundling everything it needs together in one package
  • better than pure React suggestion, as it feels like SASS in a programmer's perspective
  • "automatic vendor prefixing" - how? Autoprefixer is not a dependency...
  • dynamic styles: as the "stylesheet" is compiled at runtime, it can be changed through code easily

Cons

  • CSS reimplementation? A little bit smelly, but maybe as much as JSX or Angular are, in respect to pure HTML markup
    • Probably includes a small performance drawback, as POJO must be interpreted into styles to be applied, and some stuff like pseudo-selectors are implemented as JavaScript events (!!!)
  • only :hover, :active and :focus are supported
  • depends on the style attr (ref), what means: no cache from external CSS files, and probably more code to be loaded by the browser - as there could be many components with style attributes. style processing is slower than stylesheets as well (ref).

Sample

<Button kind="primary">Radium Button</Button>
var Radium = require('radium');
var React = require('react');
var color = require('color');

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

  render() {
    // Radium extends the style attribute to accept an array. It will merge
    // the styles in order. We use this feature here to apply the primary
    // or warning styles depending on the value of the `kind` prop. Since its
    // all just JavaScript, you can use whatever logic you want to decide which
    // styles are applied (props, state, context, etc).
    return (
      <button
        style={[
          styles.base,
          styles[this.props.kind]
        ]}>
        {this.props.children}
      </button>
    );
  }
}

// You can create your style objects dynamically or share them for
// every instance of the component.
var styles = {
  base: {
    color: '#fff',

    // Adding interactive state couldn't be easier! Add a special key to your
    // style object (:hover, :focus, :active, or @media) with the additional rules.
    ':hover': {
      background: color('#0074d9').lighten(0.2).hexString()
    }
  },

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

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

Basically, every component would have its own scss file when needed. That could be used in two ways:

  1. required inline through Webpack loaders. This would isolate better the files usage, but would bring more network complexity, as each page would bring a different mix of CSS rules, creating a lot more of HTTP traffic on the long run.
  2. they would all be @import'ed manually in a main.scss file in the root folder, and that would be required in the main template file. It would make up for a single file, easily cacheable by the browser.

Pros

  • Structure similar to what the project already holds (somewhat similar example: http://i.imgur.com/5KxdGRH.png)
  • Proven technology, no headaches besides adding a SASS compiler (we already have one, right?)
  • Widely known structure and feels natural. It's common to have SCSS files for separate pages on a site and have them bundled together in a main file, so the migration into component SCSS files it expected
  • Separates pure JS constructs (behaviour and JSX/HTMLish markup) from traditional styling
  • Enables usage of other preprocessors, such as Autoprefixer

Cons

  • It would require some work on naming rules, as namespace clashes could occur. Simple HTML tags would not be purely styled (such as adding rules to a pure p or span), and so on.
  • Slow selectors might occur, based on the point above - modular CSS usually generates shallower selectors, that are easier for the browser to work with
  • It's just besides the component but not inside it; behaviour and markup are already mingled together, but the styles would still be separate.
  • would still need classes or IDs in the markup, so markup + style work together (something we dropped when changing from jQueryland to Reactworld)
  • primarily, vendor-prefixing would be global. Some modular CSS approaches allow CSS to be prefixed just for the current browser, reducing download size

Stilr - GH*=170

For each component you code the stylesheet in JSON and it returns you a unique CSS class you can use in the component.

Pros

  • avoids issues with namespacing / style collision
  • blocks with the exact same style yields the same classes - CSS may get smaller but does not save us from DRYing the code
  • claims to play nice with React Hot Reloader and server-side rendering
  • the initial load is smaller, as there's no single CSS file to be downloaded - instead, small chunks of CSS will be sent to the user
  • similar benefits to Radium

Cons

  • CSS reimplementation? A little bit smelly, but maybe as much as JSX or Angular are, in respect to pure HTML markup
    • Probably includes a small performance drawback, as POJO must be interpreted into styles to be applied
  • CSS impossible to be cached, as different pages would yield different rules - even if you extract the CSS into files, it's still much harder to cache

Sample

import StyleSheet from 'stilr';
import { palm } from './breakpoints';
import { color, font } from './theme';

const styles = StyleSheet.create({
  base: {
    transition: 'background-color .25s',
    borderRadius: 2,
    textAlign: 'center',
    fontSize: 20,
    padding: 6,
    color: '#fff',
    border: `${ color.border } 1px solid`,
    [palm]: {
      fontSize: 18
    }
  },
  primary: {
    backgroundColor: color.primary,
    ':hover': {
      color: 'tomato'
    }
  },
  secondary: {
    backgroundColor: 'tomato',
    color: '#eee'
  }
});
import React, { PropTypes } from 'react';
import Button from './button';
import StyleSheet from 'stilr';

class Button extends React.Component {
  static propTypes = {
    type: PropTypes.oneOf(['primary', 'secondary'])
  }

  render() {
    const { type, children } = this.props;
    const buttonStyles = [
      styles.base,
      styles[ type ]
    ].join(' ');

    return (
      <button className={ buttonStyles }>
        { children }
      </button>
    );
}


React.render(
  <Button type='primary' />,
  document.getElementById('root')
);

//here the style is injected in the page, as pure CSS
const css = postcss(autoprefixer()).process(StyleSheet.render()).css;
document.getElementById('stylesheet').textContent = css;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment