Modular CSS v2 (CSS-in-JS edition)

Modular CSS v2 (CSS-in-JS edition)

Slides of my evolved "Modular CSS" talk from React Alicante

69bb6b30cd7b682ba5d5a1f352e6862a?s=128

Andrey Okonetchnikov

September 29, 2017
Tweet

Transcript

  1. None
  2. Thanks to our sponsors!

  3. Andrey Okonetchnikov @okonetchnikov

  4. None
  5. ColorSnapper http://colorsnapper.com

  6. None
  7. Past Current time Future

  8. A brief history of CSS

  9. CSS 1.0 Present Future CSS 2.1 Proposed 1996 2004

  10. Present Future 1996 2004

  11. CSS was designed for documents

  12. How many of you have ever re-designed a web-site with

    CSS changes only? ✋
  13. Present Future 1996 2004

  14. Present Future 1996 2004 2005

  15. 2005 Present Future 1996 2004

  16. None
  17. None
  18. None
  19. Web-applications are built with UI Components

  20. UI Components Button

  21. Button UI Components

  22. 20+ years since the release of CSS 1.0

  23. CSS was designed for documents, not for web-applications

  24. Best practices

  25. Separation of concerns

  26. Separation of concerns JS CSS HTML

  27. Separation of concerns JS CSS HTML Checkbox Button Dropdown List

    Modal
  28. None
  29. Natural mapping

  30. Natural mapping

  31. Past Current time Future

  32. HTML-in-JS a.k.a. JSX

  33. None
  34. None
  35. None
  36. None
  37. https://trends.google.com/trends/explore?q=%2Fm%2F012l1vxv, %2Fm%2F0268gyp

  38. None
  39. Everything is a component!

  40. f(state) => UI

  41. What about styles?

  42. • Logic • HTML • Styles Button • Logic •

    HTML • Styles • Logic • HTML • Styles
  43. • Logic • HTML • Styles Button • Logic •

    HTML • Styles • Logic • HTML • Styles Global styles
  44. • Logic • HTML • Styles Button • Logic •

    HTML • Styles • Logic • HTML • Styles Global styles
  45. None
  46. Global CSS 1 .btn { 2 /* styles for button

    */ 3 } 4 5 .active { 6 /* styles for active button */ 7 background-color: blue; 8 } 9 10 .label { 11 /* styles for button label */ 12 } 1 .star { 2 /* styles for star */ 3 } 4 5 .active { 6 /* styles for active star 7 background-color: orange; 8 } 9
  47. .btn.active

  48. .content .albums .btn.active

  49. None
  50. None
  51. BEM https://en.bem.info/

  52. B E M

  53. .Block .Block --element .Block --element __modifier Block Element Modifier

  54. BEM <button class="button active"> <span class="label"> Click me! </span> </button>

  55. BEM <button class="Button Button __active"> <span class="Button --label"> Click me!

    </span> </button>
  56. Manual work

  57. <ul class="nav"> <li class="nav__item nav__item_active"> <a class="nav__link">One</a> </li> <li class="nav__item">

    <a class="nav__link">Two</a> </li> <li class="nav__item"> <a class="nav__link">Three</a> </li> </ul>
  58. .nav __item { padding: 4px 10px; color: black; } .nav

    __item_active { font-weight: bold; background: #ffc7c7; } .navigation __item { padding: 4px 10px; color: black; } .navigation __item_active { font-weight: bold; background: #ffc7c7; }
  59. None
  60. None
  61. Manual work

  62. None
  63. +

  64. https://github.com/css-modules/css-modules

  65. Before: BEM-style const Button = ({ children }) => (

    <button className="Button"> <span className="Button __label"> { children } </span> </button> )
  66. After: CSS-modules import styles from './Button.css' const Button = ({

    children }) => ( <button className={styles.button}> <span className={styles.label}> { children } </span> </button> )
  67. After: CSS-modules import styles from './Button.css' const Button = ({

    children }) => ( <button className={styles.button}> <span className={styles.label}> { children } </span> </button> )
  68. How CSS-modules work?

  69. Before: BEM-style /* Button.css */ .Button { /* general rules

    */ } .Button --disabled { /* disabled rules */ } .Button --active { /* active rules */ } .Button __label { /* label rules */ }
  70. After: CSS-modules /* Button.css */ .root { /* general rules

    */ } .disabled { /* disabled rules */ } .active { /* active rules */ } .label { /* label rules */ }
  71. The result 1 styles: { 2 root: "Button __root __abc5436",

    3 disabled: "Button __disabled __def65 4 active: "Button __active __1638bcd", 5 label: "Button __label __5dfg462" 5 } 1 /* Button.css */ 2 3 .root { } 4 .disabled { } 5 .active { } 6 .label { }
  72. CSS-modules import styles from './Button.css' const Button = ({ children

    }) => ( <button className={styles.button}> <span className={styles.label}> { children } </span> </button> )
  73. BEM for free! ❤

  74. CSS-modules ✅ Explicit imports ✅ Scoped & fast selectors ✅

    True rules isolation ✅ Code reuse, expressiveness ✅ Framework agnostic Non standard syntax (compose, vals, etc.) Build step is required No dead code elimination No automatic vendor prefixing
  75. None
  76. +

  77. https://cssinjs.org

  78. export const styles = { button: { padding: '10px', '&:hover':

    { background: 'blue' } }, '@media (min-width: 1024px)': { button: { padding: '20px' } } }
  79. Before: CSS-modules import styles from './Button.css' const Button = ({

    children }) => ( <button className={styles.button}> <span className={styles.label}> { children } </span> </button> )
  80. After: JSS import injectSheet from 'react-jss' import styles from './styles'

    const Button = ({ classes, children }) => ( <button className={classes.button}> <span className={classes.label}> {children} </span> </button> ) export default injectSheet(styles)(Button)
  81. CSS-in-JS (JSS) ✅ Explicit imports ✅ Scoped & fast selectors

    ✅ True rules isolation ✅ Code reuse, expressiveness ✅ Framework agnostic ✅ Uses w3c standard ✅ No build step is required ✅ Dead code elimination ✅ Automatic vendor prefixing
  82. —If we generate class names, why do we still use

    class attribute?
  83. https://www.styled-components.com/

  84. // Create a Title component that'll render an <h1> tag

    with some styles const Title = styled.h1` font-size: 1.5em; text-align: center; color: palevioletred; `; render( <Title> Hello React Alicante! </Title> );
  85. const Button = styled.button` /* Adapt the colors based on

    primary prop */ background: ${props => props.primary ? 'palevioletred' : 'white'}; color: ${props => props.primary ? 'white' : 'palevioletred'}; font-size: 1em; margin: 1em; padding: 0.25em 1em; border: 2px solid palevioletred; border-radius: 3px; `; render( <div> <Button>Normal </Button> <Button primary>Primary </Button> </div> );
  86. styled-components ✅ No messing with classNames (implementation detail) ✅ Same

    mental model and structure for the whole application
  87. “styled-components […] removes the mapping between components and styles.” https://www.styled-components.com/

  88. Styled Components

  89. Styled Primitives

  90. styled-components for react-native import styled from 'styled-components/native'; const StyledView =

    styled.View` background-color: papayawhip; `; const StyledText = styled.Text` color: palevioletred; `; class MyReactNativeComponent extends React.Component { render() { return ( <StyledView> <StyledText>Hello World! </StyledText> </StyledView> ) } }
  91. styled-components for Sketch

  92. None
  93. Past Current time Future

  94. Universal rendering

  95. import React from 'react'; import {AppRegistry, Pano, Text, View} from

    'react-vr'; class WelcomeToVR extends React.Component { render() { // Displays "hello" text on top of a loaded 360 panorama image. // Text is 0.8 meters in size and is centered three meters in front of you. return ( <View> <Pano source={asset('chess-world.jpg')} /> <Text style={{ fontSize: 0.8, layoutOrigin: [0.5, 0.5], transform: [{translate: [0, 0, -3]}], }}> hello </Text> </View> ); } }; AppRegistry.registerComponent('WelcomeToVR', () => WelcomeToVR);
  96. None
  97. None
  98. None
  99. None
  100. Design systems shared between designers and developers!

  101. None
  102. Wait! But… Myths & misconceptions about CSS-in-JS

  103. “CSS-in-JS is slow”

  104. None
  105. 1. CSS-in-JS ≠ inline styles!

  106. import { css } from 'glamor' const title = css({

    fontSize: '1.8em', fontFamily: 'Comic Sans MS', color: 'blue' }) console.log(title) // → 'css-1pyvz'
  107. 2. CSS-in-JS is fast enough

  108. http://cssinjs.org/function-values/

  109. 3. Maintanability > Speed

  110. https://twitter.com/dan_abramov/status/842329893044146176

  111. None
  112. https://codepen.io/malyw/pen/XRRgeB

  113. None
  114. “Crafted CSS is better for performance”

  115. None
  116. https://meiert.com/en/blog/20170531/70-percent-css-repetition/ “In CSS, we repeat ourselves too much. While it’s

    absolutely, practically possible to limit declaration repetition to 10– 20%, reality averages 72% (median 66%).”
  117. Functional CSS?

  118. http://tachyons.io

  119. Tachyons <article class="pa3 pa5-ns"> <h1 class="f3 f1-m f-headline-l"> Title </h1>

    <p class="measure lh-copy"> Lorem ipsum dolor sit amet. </p> </article>
  120. None
  121. None
  122. Manual work

  123. None
  124. Enables CSS optimisations

  125. …but uses very simple API import {styled} from 'styletron-react'; const

    Panel = styled('div', (props) => ({ backgroundColor: props.alert ? 'orange' : 'lightblue', fontSize: '12px' })); <Panel alert>Danger! </Panel>
  126. airbnb.com CSS output size

  127. Use functional CSS

  128. Generate functional CSS

  129. None
  130. None
  131. “It’s not real CSS!”

  132. None
  133. SASS has variables, mixins, etc.

  134. JavaScript has variables, functions

  135. https://una.im/sass-es2015/#

  136. Variables let color = "red"; $color: "red";

  137. Lists const colorArray = ["red", "yellow", "green"]; for (let color

    of colorArray) { console.log(color); } $colorList: "red", "yellow", "green"; @each $color in $colorList { @debug $color; }
  138. Functions function PrintMe(firstArg, ...theRest) { console.log(firstArg, theRest); } @mixin funCircle($size,

    $gradient ...) { width: $size; height: $size; background: radial-gradient($gradient); }
  139. https://polished.js.org/

  140. // Styles as object usage const styles = { background:

    lighten(0.2, '#CCCD64'), background: lighten(0.2, 'rgba(204,205,100,0.7)'), } // styled-components usage const div = styled.div` background: ${lighten(0.2, '#FFCD64')}; background: ${lighten(0.2, 'rgba(204,205,100,0.7)')}; ` // Output element { background: "#e5e6b1"; background: "rgba(229,230,177,0.7)"; }
  141. “You should use the Platform”* * Or, just Google Chrome?

  142. None
  143. None
  144. None
  145. None
  146. None
  147. styled-jsx export default () => ( <div> <p>only this paragraph

    will be red </p> <style jsx>{` p { color: red; } `} </style> </div> )
  148. styled-jsx import _JSXStyle from 'styled-jsx/style' export default () => (

    <div data-jsx='cn2o3j'> <p data-jsx='cn2o3j'>only this paragraph will get the style :) </p> <_JSXStyle styleId='cn2o3j' css={`p[data-jsx=cn2o3j] {color: red;}`} /> </div> )
  149. None
  150. “CSS is simple”

  151. CSS is simple

  152. CSS is simple CSS is easy ≠

  153. https://adactio.com/journal/12571 “It is simple in the sense of “not complex”,

    but that doesn’t mean it’s easy. Mistaking “simple” for “easy” will only lead to heartache.”
  154. How many of you know how to extract critical CSS

    or doing that? ✋
  155. Critical CSS with <> import { renderToString } from 'react-dom/server'

    import { ServerStyleSheet } from 'styled-components' const sheet = new ServerStyleSheet() const html = renderToString(sheet.collectStyles(<YourApp />)) const css = sheet.getStyleTags()
  156. https://medium.com/seek-blog/a-unified-styling-language- d0c208de2660 “If you build your app with progressive enhancement

    in mind, despite being written entirely in JavaScript, it might not require JavaScript on the client at all.”
  157. Takeaways

  158. None
  159. “CSS-in-JS enforces the best practices trough technology and shared knowledge.”

  160. It’s still CSS and you still have to learn it!

  161. It’s not about how fast you can write code, it’s

    about how fast you can read it.
  162. Stay open-minded & keep experimenting!

  163. None
  164. Thank you!

  165. Andrey Okonetchnikov @okonetchnikov http://okonet.ru https://github.com/okonet UI Engineer @ Feedly