topic {
  css-in-js: overflow;
}
topic::meta {
  author: Nick Ribal;
  date: June 2017;
}

Nick Ribal

image/svg+xml

Front-end consultant, freelancer and a family man

Disclaimer

  • I ♥ CSS! I know (in person) only one guy who knows CSS better than me

  • This is not a "WUT CSS SUCKS LOL!!!" talk

  • I've worked on:

    • Content sites

    • 3rd party widgets hosted on others sites

    • Client-side applications

    • Integrations of all of the above

  • ​This talk is meant to make people consider new practices - not replace CSS

Contents

  • Examples of CSS ecosystem FAIL

  • Why it's like that

  • The long history (in front-end terms, lol) of css-in-js

  • Correlation to evolution of modern HTML authoring

  • How css-in-js solves CSS ecosystem deficiencies

  • css-in-js features which you can't have otherwise

  • Examples of popular css-in-js libraries

The trouble with CSS

...is not this

The main trouble with CSS

3a. Use simple <link rel=stylesheet href=hardcoded-CDN.css> just for the reset. Bad practices: another request, not an actual package you manage, not self-hosted

Example #1: "I need CSS reset/normalize"

CSS workflow is stuck in document mode: not modular, not interoperable, not scopable, optimizations aren't built-in

Why is it difficult?

1. Start new project

2. Add CSS reset/normalize

3. ???

4. PROFIT!!!

3b. Copy/paste into your CSS

4. ಠ_ಠ ???

3c. Use complex tooling to do achieve something fundamentally basic (CSS packages in npm are scarce and inconsistent)

Example #2:

"I want to reuse styling of an existing component (from another runtime)"

No easy way to do something which is so fundamentally simple :(

Good idea

Bad implementation

Why can't we easily reuse CSS?

Modern CSS frameworks aren't interoperable

Each is like a country: has it's own language, concepts, conventions, supporting different browser versions

This results in incompatible monoliths, negating basic software development best practices: code sharing, modularity, reuse and huge variance in how the same features are implemented

This is old news...

In November 2014, Christopher "vjeux" Chedeau, who is working on React and React Native at Facebook, gave a thought-provoking talk titled "CSS in JS".

From the documentation of fela, a css-in-js library:

He outlined the problems of CSS at scale and later showed how they solved those at Facebook. They were able to solve most, but in return had to add a lot of additional tooling.

Then he introduced a complete new approach to handle those issues without any actual extra work. Using inline styles. It seemed crazy, but just worked magically.

@vjeux's talk created shockwaves and turmoil in the front-end community

It's all about best practices, which are there for good reasons!

But times are changing...

...and yesterday's best practices stop being best, since they fail to serve their purpose

Because the purpose has changed!

Separation of concerns, old school

Separation of concerns, modern

// Remember jQuery plugins?
$('select').select2()

css-in-js today is catching up with a decade of html-in-js

// SPA frameworks via template engines
var TitleView = Backbone.View.extend({
  template: _.template('<h1><%=text%></h1>')
  // Or Pug, Mustache, Handlebars, etc
})

We experimented A LOT to get to where we are today

// Modern components
function Title({ text, className, }){
  return (
    <h1 { ...{ className } }>{ text }</h1>
  )
}

So now we're running experiments, resulting in css-in-js fatigue

But that's a good GREAT thing!

Since we acknowledge CSS's shortcomings in the modern web

And smart people are coming up with new approaches to tackle these problems all the time!

Smart people experimenting

The premise of css-in-js isn't just catching up to modern front-end

  • Global namespace, isolation and non deterministic resolution (specificity) are replaced with:​
    • Scoped styles - not a best practice (which must be enforced), but the default
  • Lack of dependency management and interoperability:
    • ​It's just JS! Use standard tooling: modules and npm
  • Sharing values with JS:
    • Built-in, by definition :)

The real premise of css-in-js is reimagining what's possible compared to plain old CSS!

  • Dead code elimination, ​Code coverage and Testing
  • Critical CSS: above the fold inlining
  • ​Smarter optimizations:
    • html-in-js + css-in-js = super minification with name mangling, like we've had in JavaScript for years
    • Stuff like webpack's CommonsChunkPlugin

Optimizations and

static analysis

Standardization, modularity and code reuse

  • Standard libraries instead of current CSS silos: think stuff from Sass land and lodash for CSS
  • CSS component packages

BUT WAIT, THERE'S MORE!!1111

Ready for the next best thing since sliced bread?

Non browser styling

Feature showcase of popular css-in-js libraries

  • CSS modules
  • JSS
  • styled-components
  • Aphrodite
  • Styletron

CSS Modules (most common today)

/* toast.css */
.message { font-weight: bold; }
.success { color: green; }
.fail { color: red; }
import {
  message, success, fail,
} from './toast.css'

function Toast(isSuccess, text){
  const statusClass = isSuccess ? success : fail
  const toastProps = {
    className: [message, statusClass].join(' ')
  }
  return <div { ...toastProps }>{ text }</div>
}

JSS

import jss from 'jss'
import preset from 'jss-preset-default'
import color from 'color'

// One time setup with plugins and settings
jss.setup(preset())

// Create or compose your CSS
const styles = {
  button: {
    fontSize: 12,
    '&:hover': { // CSS pseudo-classes
      background: 'blue'
    }
  },
  ctaButton: {
    extend: 'button', // mixins
    '&:hover': {
      background: // Runtime JS colors
        color('blue').darken(0.3).hex()
    }
  },
  '@media (min-width: 1024px)': {
    // CSS media queries
    button: {
      width: 200
    }
  }
}

// Attach stylesheet to DOM (or SSR)
const {classes} =
  jss.createStyleSheet(styles).attach()

// Render your HTML with generated classes
document.body.innerHTML = `
  <button class="${classes.button}">
    Button
  </button>
  <button class="${classes.ctaButton}">
    CTA Button
  </button>
`
  • Fast JS to CSS compiler in client and server-side
  • Compatible with React and other libraries
  • Small and extensible via plugins
import {h1} from 'styled-components'

const Title = h1`
  font-family: Comic Sans MS;
  color: blue;
`
// Usage
<Title>Hello World!</Title>

Why even bother with class names?

They are merely an implementation detail

// a styled component
import {
  StyleSheet, css,
} from 'aphrodite'

const styles = StyleSheet.create({
  title: { ... }
})

function Heading(props){
  const headingProps = {
    ...props,
    className: css(styles.title)
  }
  return <h1 { ...headingProps } />
)

// SSR with critical CSS inlined
import { StyleSheetServer } from 'aphrodite'

const { html, css } = StyleSheetServer.renderStatic(
  () => ReactDOMServer.renderToString(<App/>)
)

// Send in response body
const criticalCss = `
  <style data-aphrodite>
    ${css.content}
  </style>
`

OK, so what's my point?

Good news

.

Bad news

The good news is,

With so many choices, each with a variety features and tradeoffs

I have no idea which ones will become popular ¯\_(ツ)_/¯

IT'S A CELEBRATION!

It's as if we've seen this before ;)

You should try these for yourself and draw your own conclusions!

The bad news is,

CSS is here to stay

And you still have to learn it

Sources and references

Thank you and

stay curious

:)

* { css-in-js: overflow }

By Nick Ribal

* { css-in-js: overflow }

While JS and HTML have progressed incredibly in recent years, CSS is the last bastion of old-school web development which we all love to hate. CSS-in-JS is the latest attempt at solving this hard problem. If it succeeds, CSS-in-JS will fast-forward CSS into the modern era. Moreover, it will revolutionize how we compose, maintain, share and optimize styling across the modern web, native apps and collaborate with designers and product people. I will present an overview of the history, evolution, challenges, current solutions and benefits in this exciting landscape!

  • 2,070