Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

CSS in React

1,669 views

Published on

CSS in React is a talk I gave at the ReactJS San Francisco Bay Area meetup yesterday. It covers viable options for implementing CSS in JavaScript React components and the good and bad parts of various solutions including Radium, react-css-modules, styled components, combined with Sass, Webpack, Babel, and ES6.

It also includes a github repo https://github.com/joeshub/css-in-react where you can run all the examples locally

Published in: Engineering
  • Be the first to comment

CSS in React

  1. 1. CSS IN React
  2. 2. Joe Sei     @joesei
  3. 3. THE BAD THE GOOD AND THE UGLY
  4. 4. Familiarity - (CSS Level 1 released 19 years ago) Optimized Browser parsing and layout JavaScript DOM API Inheritance structure - JSON like Media Queries - size and feature detection Pseudo Selectors - browser states Basic math via calc() CSS3 (THE GOOD)
  5. 5. Flat - nested rules not supported Needs vendor pre xes No variables, no functions Some dynamic updates still require JavaScript CSS3 (THE BAD)
  6. 6. Global namespace pollution Importance, speci city wars, & eventually !important Nondeterministic, depends on source order Encapsulation - sharing code across components is scary Changes & dead code elimination are manual Missing rules and syntax errors at runtime CSS3 (THE UGLY)
  7. 7. (like ux for CSS) Object-Oriented CSS (OOCSS) Scalable and Modular Architecture for CSS (SMACSS) Block, Element, Modi er (BEM) ATOMIC CSS SUIT CSS METHODOLOGIES
  8. 8. (like babel for CSS) SASS LESS Stylus PostCSS Autopre xer / cssnext PRE/POST PROCESSORS
  9. 9. a like button EXAMPLE:
  10. 10. HTML <button class="btn btn‐primary">    Like <span class="badge">9</span>  </button> 
  11. 11. OR
  12. 12. JSX & REACT const LikeButton = ({ likes }) => {    return (      <button className="btn btn‐primary">        Like <span className="badge">{likes}</span>      </button>    )  } 
  13. 13. DOM API 1. const LikeButton = ({ likes }) => { 2. return ( 3. <button className="btn btn-primary"> 4. Like <span className="badge">{likes}</span> 5. </button> 6. ) 7. } 8.
  14. 14. AND
  15. 15. CSS3.btn {    display: inline‐block;    border: 0;    padding: 6px 12px;  }  .btn.btn‐primary {    color: #fff;    background‐color: #f74A27;  }  .btn.btn‐primary:hover {    background‐color: #ff7857;  }  .btn.btn‐primary > .badge {    color: #f74A27;    background‐color: #fff;  }  .btn > .badge {    display: inline‐block;    border‐radius: 10px;    padding: 3px 6px;  }     SASS.btn {    display: inline‐block;    border: 0;    padding: 6px 12px;    &.btn‐primary {      color: $text‐color;      background‐color: $button‐color;      &:hover {        background‐color: $button‐color‐hover;      }      .badge {        color: $button‐color;        background‐color: $text‐color;      }    }        .badge {      display: inline‐block;      border‐radius: 10px;      padding: 3px 6px;    }  } 
  16. 16. RESULTLike  9
  17. 17. NOW LET'S TRY THE SAME WITH INLINE STYLES in React
  18. 18. JSONconst styles = {    'btn': {      'display': 'inline‐block',      'border': '0',      'padding': '6px 12px'    },    'btn_primary': {      'color': '#fff',      'backgroundColor': '#f74A27'    },    'btn_primary_hover': {      'backgroundColor': '#ff7857'    },    'btn_primary__badge': {      'color': '#f74A27',      'backgroundColor': '#fff'    }    'btn__badge': {      'display': 'inline‐block',      'borderRadius': '10px',      'padding': '3px 6px'    }  }  REACTimport React, { Component } from 'react'  import { styles } from './styles'  export const LikeButton = ({ likes }) => {    return (      <button style={{        ...styles.btn,        ...styles.btn_primary        }}>        Like        <span          style={{          ...styles.btn__badge,          ...styles.btn_primary__badge          }}>          {likes}        </span>      </button>    )  }    
  19. 19. CSS IN JAVASCRIPT 1. const styles = { 2. 'btn': { 3. 'display': 'inline-block', 4. 'border': '0', 5. 'padding': '6px 12px' 6. }, 7. 8. 'btn_primary': { 9. 'color': '#fff', 10. 'backgroundColor': '#f74A27' 11. }, 12. 'btn_primary_hover': { 13. 'backgroundColor': '#ff7857'
  20. 20. 14. }, IN YOUR COMPONENT 1. import React, { Component } from 'react' 2. 3. import { styles } from './styles' 4. 5. export const LikeButton = ({ likes }) => { 6. return ( 7. <button style={{ 8. ...styles.btn, 9. ...styles.btn_primary 10. }}> 11. Like 12. <span 13. style={{
  21. 21. 14. ...styles.btn__badge, RESULT WITH JSONLike  9
  22. 22. No pseudo selectors :hover :before etc. No media queries @media viewport etc. No rule nesting No auto pre xing No CSS extraction FOUC ISSUES WITH USING THE PLAIN JSON object
  23. 23. Radium react-css-modules styled-components aphrodite, jss, cxs, csjs, glamor, so many more FRAMEWORKS FOR CSS in JS
  24. 24. RADIUMexport const styles = {    btn: {      display: 'inline‐block',      border: '0',      padding: '6px 12px',      btn_primary: {        color: '#fff',        backgroundColor: '#f74A27',        ':hover': {          backgroundColor: '#ff7857'        },        badge: {          color: '#f74A27',          backgroundColor: '#fff'        }      }      badge: {        display: 'inline‐block',        borderRadius: '10px',        padding: '3px 6px'      }    }  }  REACTimport React, { Component } from 'react'  import Radium from 'radium'  import { styles } from './styles'  @Radium  class LikeButton extends Component {    render () {      const { likes } = this.props      return (        <button style={[          styles.btn,          styles.btn.btn_primary        ]}>          Like <span style={[            styles.btn.badge,            styles.btn.btn_primary.badge          ]}>{likes}</span>        </button>      )    }  }  export default LikeButton    
  25. 25. RADIUM STYLE SYNTAX 1. export const styles = { 2. btn: { 3. display: 'inline-block', 4. border: '0', 5. padding: '6px 12px', 6. 7. btn_primary: { 8. color: '#fff', 9. backgroundColor: '#f74A27', 10. 11. ':hover': { 12. backgroundColor: '#ff7857' 13. },
  26. 26. 14. RADIUM REACT SYNTAX 1. import React, { Component } from 'react' 2. import Radium from 'radium' 3. import { styles } from './styles' 4. 5. @Radium 6. class LikeButton extends Component { 7. render () { 8. const { likes } = this.props 9. return ( 10. <button style={[ 11. styles.btn, 12. styles.btn.btn_primary 13. ]}>
  27. 27. 14. Like <span style={[ Wraps your function or component with @decorators Creates a class to manage state for :hover :active :focus Radium.getState(this.state, 'btnPrimary', ':hover') Style similar child elements with .map() matchMedia for media queries - IE poly ll, server-side? Styles are inline, extract into CSS for production? RADIUM NOTES
  28. 28. No globals (with caveats) Built in dead code elimination, only used components Presentation logic is in your view, nd and edit State, constants Composition, loops, computation Distribute via import and export Dynamic styling, app & DOM state e.g. data attributes Some :pseudo selectors re-implemented in JavaScript For example :last-child becomes i === arr.length - 1 INLINE STYLES (THE GOOD)
  29. 29. No ::after ::before ::selection Media queries have to use window.matchMedia() Autopre xing display: -webkit-flex; display: flex; Animations via @keyframes re-implemented in JS Highest priority before !important No Speci city Cascading Performance Debugging in devtools is a pain Duplicate markup for similar elements INLINE STYLES (THE BAD)
  30. 30. CSS MODULES
  31. 31. Based on Interoperable CSS - loadable, linkable CSS Works with SASS, PostCSS etc. Broken CSS = compile error Using an unde ned CSS Module = no warning REACT-CSS-MODULES
  32. 32. SASS@import "variables.scss";  .btn {    display: inline‐block;    border: 0;    padding: 6px 12px;    &.btn‐primary {      color: $text‐color;      background‐color: $button‐color;      &:hover {        background‐color: $button‐color‐hover;      }      .badge {        color: $button‐color;        background‐color: $text‐color;      }    }    .badge {      display: inline‐block;      border‐radius: 10px;      padding: 3px 6px;    }  }  REACTimport React, { Component } from 'react'  import CSSModules from 'react‐css‐modules'  import styles from '../styles/likebutton.scss'  @CSSModules(styles, {allowMultiple: true})  class LikeButton extends Component {    render () {      const { likes } = this.props      return (        <button styleName="btn btn‐primary">          Like <span styleName="badge">{likes}</span>        </button>      )    }  }  export default LikeButton    
  33. 33. REACT-CSS-MODULES SYNTAX 1. import React, { Component } from 'react' 2. import CSSModules from 'react-css-modules' 3. import styles from '../styles/likebutton.scss' 4. 5. @CSSModules(styles, {allowMultiple: true}) 6. class LikeButton extends Component { 7. render () { 8. const { likes } = this.props 9. return ( 10. <button styleName="btn btn-primary"> 11. Like <span styleName="badge">{likes}</span> 12. </button> 13. )
  34. 34. 14. } styles object or this.props.styles[yourClasslassName] Con gure your component classnames via localIdentName Webpack CSS loader [path]___[name]__[local]___[hash:base64:5] Generated classname styles-___likebutton__btn-primary___HYx7V No overruling, intentionally nor unintentionally Composition composes: parentClass same as @extend in Sass Others from ICSS :global :export :import Use extract text plugin in production REACT-CSS-MODULES NOTES
  35. 35. STYLED COMPONENTS
  36. 36. STYLEDimport styled from 'styled‐components'  const StyledLikeButton = styled.button`    display: inline‐block;    border: 0;    padding: 6px 12px,    &.btn‐primary {      color: #fff;      background‐color: #f74A27;      &:hover {        background‐color: #ff7857;      }      .badge {        color: #f74A27;        background‐color: ${THEME.bgColor};      }    }    .badge {      display: inline‐block;      border‐radius: 10px;      padding: 3px 6px;    }  `  export default StyledLikeButton  REACTimport React, { Component } from 'react'  import StyledLikeButton from './StyledLikeButton'  class LikeButton extends Component {    render () {      const { likes } = this.props      return (        <StyledLikeButton className="btn‐primary">          Like <span className="badge">{likes}</span>        </StyledLikeButton>      )    }  }  export default LikeButton    
  37. 37. STYLED COMPONENTS SYNTAX 1. import styled from 'styled-components' 2. 3. const StyledLikeButton = styled.button` 4. display: inline-block; 5. border: 0; 6. padding: 6px 12px, 7. &.btn-primary { 8. color: #fff; 9. background-color: #f74A27; 10. &:hover { 11. background-color: #ff7857; 12. } 13. .badge {
  38. 38. 14. color: #f74A27; STYLED COMPONENTS USAGE 1. import React, { Component } from 'react' 2. import StyledLikeButton from './StyledLikeButton' 3. 4. class LikeButton extends Component { 5. 6. render () { 7. const { likes } = this.props 8. return ( 9. <StyledLikeButton className="btn-primary"> 10. Like <span className="badge">{likes}</span> 11. </StyledLikeButton> 12. ) 13. }
  39. 39. 14. Autopre xing included for free Write plain CSS, no weird poly lls needed Generated classnames are namespaced btn-primary gjkSC Injects style tags into the document head Supports server-side rendering, but not extract text plugin keyframes helper keeps your rules local to your component Theming is built in STYLED COMPONENTS NOTES
  40. 40. Web Components and Shadow DOM cssnext CSS4 ¿¡ !? WHAT'S NEXT
  41. 41. View examples on Github THANK YOU!

×