CSS with a hash
...from a convention to a hash
css-modules && styled-components

Who
  Why
     How
Who
...a little bit of ❤️
CSS Modules
💅🏻 styled-components



Glen Maddern
@geelen
Glen Maddern
@geelen
Mark Dalgleish
@markdalgleish

Max Stoiber
@mxstbr


Tobias Koppers
@sokra
Why
...problems with CSS at scale
- 
	Global Namespace 
 
- 
	Implicit dependencies between CSS and JS 
 
- 
	Dead code elimination 
 
- 
	Sharing constants & theming 
 
- 
	Isolation & cascade 
🔴
✅
✅
🔴
🔴
css-modules
The local scope and webpack

css-modules
...it starts with a hash
- 
	Write CSS as in CSS - 
		No inline styles or "CSS in JS" 
 
 
- 
		
- 
	Processed to add a hash - 
		Webpack or PostCSS 
 
 
- 
		
- 
	Imported in JS components - 
		React, Angular, etc 
 
 
- 
		
- 
	Adds custom composition - 
		Avoid cascading in CSS 
 
- 
		
:local scope
gets hashed
when imported
._1rJwx92-gmbvaLiDdzgXiJ { ... }
._ah6Hch-gjsAdSE53CxzaEs { ... }:local(.header) { ... }
:local(.footer) { ... }import styles from './stylez.css';{
  'header': '_1rJwx92-gmbvaLiDdzgXiJ',
  'footer': '_ah6Hch-gjsAdSE53CxzaEs'
}:global scope
:local became default
.header { ... }:global(.header) { ... }CSS
JS & HTML
Output
import styles from './button.css';
buttonElem.outerHTML = `
  <button class=${styles.normal}>Submit</button>
`.normal { /* all styles for Normal */ }
.disabled { /* overrides for Disabled */ }<button class="button__normal__abc5436">
  Hit it!
</button>Style Composition I
Output
.normal { /* all the common styles you want */ }
.inProgress { 
  composes: normal;
  color: red
}.button__normal__abc5436 { /* font-sizes, padding, border-radius */ }
.button__inProgress__def6547 { /* blue color, light blue background */ }styles: {
  normal: "button__normal__abc5436",
  inProgress: "button__normal__abc5436 button__inProgress__def6547"
}Internally & Exports
Style Composition II
.primary {
  color: #720;
}
.secondary {
  color: #777;
}.common { ... }
.normal {
  composes: common;
  composes: primary from "../constants/colors.css";
}.component {
  composes: padding-large margin-small from "./layout.css";
}.component {
  composes: large from "./typography.css";
  composes: dark-text from "./colors.css";
  composes: subtle-shadow from "./effect.css";
}PostCSS and webpack
{
  test: /\.css$/,
  loader: '
     style!css-loader?modules&importLoaders=
     1&localIdentName=[name]__[local]___[hash:base64:5]' 
}:global .page {
    padding: 20px;
}
.title {
    composes: title from "./mixins.css";
    color: green;
}webpack loader configuration
postcss-modules
._title_116zl_1 {
    color: black;
    font-size: 40px;
}
{
  "title": "_title_xkpkl_5 _title_116zl_1"
}Interoperable CSS (ICSS)
- 
Explicit cross-language dependencies
	- Describe each file's dependencies
 
 
- Describe each file's dependencies
- 
CSS - JS interoperability
	- Dynamic classnames (elem.addClass( styles.elemClass ))
 
 
- Dynamic classnames (elem.addClass( styles.elemClass ))
- 
Specification
	- :import and :export as pseudo selectors
 
styled-components
Enforcing best practices

styled-components
All about Higher Order Components
Remove mapping
between styles and component
import React from 'react';
import styled from 'styled-components';
const Title = styled.h1`
  font-size: 1.5em;
  text-align: center;
  color: palevioletred;
`;styled.*
const Title = styled.h1`
  font-size: 1.5em
`;in DOM
<h1 class="ae0869e501">...</h1>while CSS
<link href="stylez.css" />React components
const Title = styled.default.h1`
  font-size: 1.5em;
  text-align: center;
  color: palevioletred;
`;
const Wrapper = styled.default.section`
  padding: 4em;
  background: papayawhip;
`;
class Example extends React.Component {
    render() {
      return (
        <Wrapper>
          <Title>Hello World!</Title>
        </Wrapper>
      )
    }
}
ReactDOM.render(
    <Example />,
    document.getElementById('container')
);Composition of components
import React from 'react';
import styled from 'styled-components';
import Button from './Button';
const TomatoButton = styled(Button)`
  color: tomato;
  border-color: tomato;
`;
export default TomatoButton;Animations
import styled, { keyframes } from 'styled-components';
const rotate360 = keyframes`
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
`;const Rotate = styled.div`
  display: inline-block;
  animation: ${rotate360} 2s linear infinite;
`;Definition
Usage
Interpolation
const padding = '3em';
const Section = styled.section`
    color: white;
    padding: ${padding};
    background: ${(props) => props.background};
    border: ${(props) => props.theme.main}
`;Change by props
Theming
import { ThemeProvider } from 'styled-components';
const theme = {
  main: 'mediumseagreen',
};
const GreenSection = (props) => {
  return (
    <ThemeProvider theme={theme}>
      {props.children}
    </ThemeProvider>
  );
}ThemeProvider
props.theme
const Button = styled.button`
  background: ${props => props.theme.main};
  border: 2px solid ${props => props.theme.main};
`;Why
...problems with CSS at scale
- 
	Global Namespace 
 
- 
	Implicit dependencies between CSS and JS 
 
- 
	Dead code elimination 
 
- 
	Sharing constants & theming 
 
- 
	Isolation & cascade 
✅
✅
✅
✅
✅
❗️ Thanks ❗️
❓ Questions ❓
CSS with a hash
By Tobias Deekens
CSS with a hash
From a convention to a hash. Tales of CSS modules and styled-components.
- 1,738
 
   
   
  