CSS in JS

The Good

The Bad

& The Ugly

Who?

Senior FED

Back to the past (1991)

1995

2002

2005

2011

2010

2014

2008

2015

2010

2014

2002

1991

1995

2005

2008

2011

2013

2015

<Template/>

JS Logic

CSS/SCSS

Component

CSS/SCSS

2013

2017

Component

CSS/SCSS

CSS-in-JS

CSS/SCSS

Just why???

Yippee!

CSS in JS

The Good

The Bad

& The Ugly

The Fear

...of CSS

CSS is awesome

BUT

Scaling

Global namespace

Implicit dependencies

Code Maintenance (DEAD code)

Scaling

Minification

Sharing constants

Non deterministic order of source

Chris

Chris

Chris


/* style.css */

.chris {
  color:'blue';
}

/* style.css */

.chris {
 color:'gold';
}

/* style.css */

.chris {
 color:'green';
}

<div class="my-awesome-container">
    <button class="chris">
        Chris!
    </button>
</div>

Chris!

😰

!important
<h2 class="42">
    I'm happy!
</h2>

You are. But I'm not 🤦‍♀️

The (not) old style

OOCSS & SMACSS

BEM

CSS processors

NOT pure CSS

HARD to migrate

NAMING !

STILL NOT scalable

(that HUGE CSS file!)

Real-time CSS modifiers ?

var()

😍

😱

JavaScript

😰 Performance 

😰 Complexity 

CSS has fundamental flaws at scale that can be solved by writing styles in JS .

@VJEUX — NOVEMBER 2014

SS-in-JS

<Component/>

JS

CSS

React Inline Style

import React from "react";
import { Image } from "cloudinary-react";
import { cloudName } from "../settings";

const avatarStyle = {
  display: "flex",
  position: "relative",
  alignItems: "center",
  width: "150px",
  height: "150px"
};

const Avatar = props => {
  return (
    <div style={avatarStyle}>
      <Image
        cloudName={cloudName}
        publicId={props.publicId}
        alt={props.title}
        width={150}
        height={150}
        crop="thumb"
        radius="max"
        opacity={50}
      />
    </div>
  );
};

export default Avatar;

React INLINE Style

//...
/* style of container */
const avatarStyle = {
  /*...*/
};

/* style of avatar initials */
const titleStyle = {
  position: "absolute",
  display: "flex",
  fontSize: "40px",
  width: "inherit",
  alignItems: "center",
  justifyContent: "center"
};

const Avatar = props => {
  return (
    <div style={avatarStyle}>
      <Image
        cloudName={cloudName}
        publicId={props.publicId}
        alt={props.title}
        width={150}
        height={150}
        crop="thumb"
        radius="max"
        opacity={50}
      />
      <div style={titleStyle}>
        {props.title[0].toUpperCase()}
      </div>
    </div>
  );
};
//...

Animations

Scalability

Media queries

🙄

Readability

How about

INLINE but NOT INLINE?

Ideal concepts

Scoped CSS per component

Extendable CSS in global scope

Full CSS support

SSR (Static CSS extraction)

The EXTEND

Debuggable

Syntax highlighting

Free of dead CSS code

Themes

40+

libraries

2015

<Component/>

JS

CSS

.css

import "./button.css";

//will become

import styles from "./button.css";
/* button.css */

:local(.button) {
/* by default */
/*...*/
}

//is the same as
.button { /*...*/ }

<Component/>

JS

CSS

Scoped

Composition

Share-able

Full CSS support

Pre-processor support

Dynamic modifiers

Reusable CSS

/*Item.module.css*/
.itemCard {
  width: 220px;
  padding: 5px;
  box-shadow: 0 1px 2px rgba(0,0,0,.2);
  border: 1px solid lightgray;
}

.itemCard:hover {
  background-color: #d3d3d363;
  cursor: pointer;
}

.itemTitle {
  color: rebeccapurple;
  margin: 0;
  padding: 0.8rem 0;
  border-top: 1px solid lightgray;
}
/*Item.js*/
import React from "react";
import { Image } from "cloudinary-react";
import { cloudName } from "../../settings";
import styles from "./Item.module.css";

const Item = props => {
  return (
    <div className={styles.itemCard}>
      <Image
        cloudName={cloudName}
        publicId={props.id}
        width="200"
        crop="scale"
      />
      <h3 className={styles.itemTitle}>
        {props.title}
      </h3>
    </div>
  );
};

export default Item;
npm install node-sass --save
/*Item.module.scss*/
.itemCard {
  width: 220px;
  padding: 5px;
  box-shadow: 0 1px 2px rgba(0,0,0,.2);
  border: 1px solid lightgray;

  &:hover {
    background-color: #d3d3d363;
    cursor: pointer;
  }
}

.itemTitle {
  color: rebeccapurple;
  margin: 0;
  padding: 0.8rem 0;
  border-top: 1px solid lightgray;
}
/* Item.js */
import React from "react";
import { Image } from "cloudinary-react";
import { cloudName } from "../../settings";
import styles from "./Item.module.scss";

const Item = props => {
  return (
    <div 
        className={props.isGrid 
            ? styles.itemCard 
            : styles.itemRow}>
      <Image
        cloudName={cloudName}
        publicId={props.id}
        width={props.isGrid ? "200" : ""}
        height={props.isGrid ? "" : "60"}
        crop="scale"
      />
      <h3 className={styles.itemTitle}>
        {props.title}
      </h3>
    </div>
  );
};

export default Item;
/* Item.module.scss */
.item{
  border: 1px solid lightgray;
  padding: 5px;

  &:hover {
    background-color: #d3d3d363;
    cursor: pointer;
  }
}

.itemCard {
  composes: item;
  width: 220px;
  box-shadow: 0 1px 2px rgba(0,0,0,.2);
}

.itemRow {
  composes: item;
  min-height: 60px;
  display: flex;

  .itemTitle {
    border:none;
    font-size: 18px;
    margin-left: 10px;
    line-height: 2;
  }
}








/* .css */
.container {...}

/* will be mapped to */

<div 
    class="elements__Container-l1fwko0zmfBG">
    ...
</div>

Random class generator

BUT

CSS in JS

not really

It's still

NOT Full extendable CSS in global scope

NO EASY way for theming

NAMING (not name collisions)

THE CSS-in-JS

The challenge

List-view

Grid-view

<Item/>

/* Item.css */
.item{
  border: 1px solid lightgray;
  padding: 5px;

  &:hover {
    /* Hover styles */
  }
}

.itemCard {
  composes: item;
  margin-right:10px;
  margin-bottom: 10px;
  width: 220px;
  box-shadow: 0 1px 2px rgba(0,0,0,.2);
}

.itemRow {
  composes: item;
  min-height: 60px;
  display: flex;

  .itemTitle {
    border:none;
    font-size: 18px;
    margin-left: 10px;
    line-height: 2;
  }
}
/* Item.js */
import styled, {css} from "styled-components";

const rowStyle = css`
    /* styles for row view */
`;

const cardStyle = css`
    /* styles for card view */
`;

const ItemContainer = styled.div`
    /* default styles*/
    
    ${props => props.isGrid 
             ? rowStyle : cardStyle}
`;

const Item = props => {
  return (
    <ItemContainer isGrid={props.isGrid}>
      <Image
        /*...*/
      />
      <ItemTitle>{props.title}</ItemTitle>
    </ItemContainer>
  );
};
/* Item.js */
import styled, {css} from "styled-components";

const rowStyle = css`
    /* styles for row view */
`;

const cardStyle = css`
    /* styles for card view */
`;

const ItemContainer = styled.div`
    /* default styles*/
    
    ${props => props.isGrid 
            ? rowStyle : cardStyle}
`;

const Item = props => {
  return (
    <ItemContainer isGrid={props.isGrid}>
      <Image
        /*...*/
      />
      <ItemTitle>{props.title}</ItemTitle>
    </ItemContainer>
  );
};
/* Item.js */
import styled from "@emotion/styled";

const ItemContainer = styled.div(
  `
  /* default styles */
`,
  props =>
    props.isGrid
      ? {
          /* card styles */
        }
      : {
          /* row styles */
        }
);

const Item = props => {
  return (
    <ItemContainer isGrid={props.isGrid}>
      <Image
        /*...*/
      />
      <ItemTitle>{props.title}</ItemTitle>
    </ItemContainer>
  );
};

The GOOD

Easy to theme

NO Dead code

First class first

Extendable

Super scoped

/* Item.js */
import styled from "styled-components";

const Item = props => {
  return (
    <ItemContainer isGrid={props.isGrid}>
      <Image
        /*...*/
      />
      <ItemTitle>{props.title}</ItemTitle>
    </ItemContainer>
  );
};

const ExtendedItem = styled(Item)`
    /* extended styled*/
`

NO more CSS file!

It's awesome!

Or is it really ? 😏

The NOT so good (and ugly)

Fragmentation

Box

/* Box.js */

import React from "react";
import styled from "@emotion/styled";

const StyledBox = styled.div(props => ({
  width: `${props.size}px`,
  height: `${props.size}px`,
  background: "grey",
  marginLeft: "auto",
  marginRight: "auto",
  marginTop: "10px"
}));

const Box = props => <StyledBox {...props} />;

export default Box;

Input size of box

Interactive Comp

😱

JS

CSS

Parse CSS

Inject to Stylesheet

stylesheet.insertRule

Browser

HTML Paint

load

 😮 Accessibility?

NO Cache

download

How about

Scaling & Sharing ?

Scaling & Sharing ?

CSS

JS

CSS

Dev

Des

Des

Scaling & Sharing ?

CoolJS

CSS

🤯

How about

Re-render problem?

Re-render problem

/*index.js*/

import { ThemeProvider } from "emotion-theming";

function App() {
  const [theme, changeTheme] = useState({
    color: "rebeccapurple"
  });

  return (
    <StyledApp>
      <h1>The Pokemons</h1>
      <select
        defaultValue={theme.color}
        onChange={e => changeTheme({ 
            color: e.target.value
          })}
      >
        <option value="orange">Orange</option>
        <option value="lime">Lime</option>
        <option value="pink">Pink</option>
        <option value="yellow">Yellow</option>
        <option value="rebeccapurple">Purple</option>
      </select>
      <ThemeProvider theme={theme}>
        <StyledLayout />
      </ThemeProvider>
    </StyledApp>
  );
}
/*Item.js*/
const ItemTitle = styled.h3`
  color: ${props => props.theme.color};
  //...
`;

How about

Security?

Security?

CSS-in-JS means

It's still CSS! (not JS)

Learning CSS is still required! 😆

Should we use CSS-in-JS?

Yes, but with caution

So

Easy to theme

NO Dead code

First class first

Nested class

Scoped

Extra re-render

Styles on run time

Security

Portability

One standard?

Context switch

Messy code

CSS-in-JS

The Good

The Bad

The Ugly

Themeable

One standard

Portable

No scope

Non deterministic

Bundle size

Dead code (somewhere)

Naming

Private to JS code

Re-usable?

Load once

No re-render

CSS-in-CSS

The Good

The Bad

The Ugly

React Native

"Use the right tool for the right job"

And naming is not a good enough reason...

“Use the right tool for the job”

And naming is not a good enough reason...

CSS-in-JS

CSS

When?

React Native App

CSS modules

CSS consistency between projects

Same technology (React) for all projects

Simple and isolated component

Macro view of app styling

Security is a concern

Full control over component styling

CSS/SCSS (global)

CSS Modules (component)

My choice

BEM (naming)

Resources

Thank you