• CSS Modules
  • Inline Styles
  • CSS in JS

Let’s start at the beginning…

Creative HTML Design book cover

Documents

— vs. —

Web Apps

Global scope

— vs —

Maintenance

  • OOCSS
  • SMACSS
  • BEM
  • SUIT
.Block__Element--Modifier { ... }
<div class="page my-page">
 <header class="header">
 <h1 class="heading header__heading">...</h1>
 </header>
 
 <article class="post">
 <header class="post__header">
 <h1 class="heading post__heading">Hello World</h1>
 </header>
 <section class="post__content">...</section>
 </article>
 
 <footer class="footer">...</footer>
 
</div>

The Age

— of —

Components

  • Backbone
  • Angular’s directives
  • Ember.Component
  • Web components
  • Polymer

React

Components are nothing new

<select>
 <option>...</option>
 <option>...</option>
 <option>...</option>
</select>
<input type="date" />

CSS and images

— are —

private to a component

Unless you use third-party components…

jQuery UI Date Picker

Our tools reflected this

gulp.task('js', function() {
 return gulp.src('src/js/index.js')
 .pipe(browserify());
});
gulp.task('css', function() {
 return gulp.src('src/styles/index.scss')
 .pipe(sass());
});
gulp.task('images', function() { ... });
@import "vendor/normalize";
@import "config/colors";
@import "config/media_queries";
@import "modules/btn";
@import "modules/dropdown";
@import "modules/header";
@import "utilities/align";
@import "utilities/clearfix";

Tooling

— for the —

component age?

Webpack

require('./MyComponent.css');
export default () => (
 <div className="MyComponent">
 <div className="MyComponent__Icon">Icon</div>
 ...
 </div>
);

Simple interface

import MyComponent from 'MyComponent';
export default () => <MyComponent />;

Progressive

Single Page Apps

  • Server rendered CSS
  • :visited, :before, :hover, :focus, etc.
  • Media queries
  • CSS animations
  • Psuedo classes for non-JS interactions…?

Checkbox hacks

.menu {
 transform: translateX(-100%);
 transition: all .3s ease;
}
.toggle:checked ~ .menu {
 transform: none
}

Late 2014…

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

@vjeux — November 2014

MicheleBertoli/css-in-js

react-style

— by @andreypopp —

import StyleSheet from 'react-style';
const styles = StyleSheet.create({
 foo: {
 color: 'red',
 backgroundColor: 'white'
 }
});
export default () => (
 <div style={styles.foo}>
 Hello, world!
 </div>
);

but…

  • (削除) Media queries (削除ここまで)
  • (削除) CSS animations (削除ここまで)
  • (削除) Psuedo classes (削除ここまで)

And yet…

😍

— How do we embrace the —

inline style mindset in regular CSS?

BEM

A block

— is —

a component

“Never use a block outside
a component of the same name”

components/
 MyComponent/
 MyComponent.js
 MyComponent.css
 icon.svg
 
.MyComponent__foo { ... }
.MyComponent__bar { ... }
.MyComponent__bar--expanded { ... }

“Block, Element, Modifying Your JavaScript Components”

Meanwhile…

Local Scope

require('./MyComponent.css');
// becomes...
import styles from './MyComponent.css';

What does ‘styles’

evaluate to?

First, let’s look at the CSS…

:local(.header) { ... }
:local(.footer) { ... }
import styles from './MyComponent.css';
export default () => (
 <div>
 <div className={styles.header}>...</div>
 <div className={styles.footer}>...</div>
 </div>
);
:local(.header) { ... }
:local(.footer) { ... }

Becomes:

/* Globally unique classes */
._1rJwx92-gmbvaLiDdzgXiJ { ... }
._ah6Hch-gjsAdSE53CxzaEs { ... }

No more

naming collisions

// Styles object:
{
 'header': '_1rJwx92-gmbvaLiDdzgXiJ',
 'footer': '_ah6Hch-gjsAdSE53CxzaEs'
}
loader: 'css?localIdentName=[name]__[local]'
.MyComponent__foo { ... }
.MyComponent__bar { ... }
:local(.field) { ... }
:local(.field):focus { ... }
:local(.backdrop) { ... }
:local(.root_isCollapsed) :local(.backdrop) { ... }
:local(.panel) .transition-active-enter { ... }

“What if locally scoped
CSS was the default?”

.backdrop { ... }
.root_isCollapsed .backdrop { ... }
.field { ... }
.field:focus { ... }
.panel :global(.transition-active-enter) { ... }

PostCSS

postcss-local-scope

— Turned .class into :local(.class) —

The End

— of —

Global CSS

“I hope it’s ok if I integrate your postcss-local-scope module into the css-loader”

@sokra — May 24, 2015

‘css-loader?module’

“Have you thought about writing a standard for CSS modules that others could implement?”

@markdalgleish — May 23, 2015

‘css-loader?modules’

  • Class composition
  • Values, i.e. shared constants

github.com/css-modules

  • Webpack
  • Browserify
  • JSPM
  • PostCSS
  • Babel

Let’s rewind a little…

Why not CSS in JS?

  • (削除) Media queries (削除ここまで)
  • (削除) CSS animations (削除ここまで)
  • (削除) Psuedo classes (削除ここまで)

Inline styles

CSS in JS

— isn’t restricted to —

Inline Styles

Khan Academy

Aphrodite

Jamie Wong / Emily Eisenberg

import { StyleSheet } from 'aphrodite';
const styles = StyleSheet.create({
 field: {
 margin: '0 10px',
 ':focus': { outline: '2px solid blue' },
 '@media (min-width: 600px)': { margin: '0 20px' }
 }
});
import { css } from 'aphrodite';
export default () => (
 <div>
 <input className={css(styles.field)} />
 </div>
);
import { StyleSheetServer } from 'aphrodite';
var {html, css} = StyleSheetServer.renderStatic(() => {
 return ReactDOMServer.renderToString();
});
return `
 <html>
 <head>
 <style data-aphrodite>${css.content}</style>
 </head>
 
 <body>
 <div id='app'>${html}</div>
 ...
 </body>
 </html>
`;

“We must deliver the absolute minimum amount of CSS necessary by only sending down CSS in use by components in the server-side rendered body”

Jamie Wong — March 2016

Personal

preference

CSS Modules

— or —

CSS-in-JS…

What do these
approaches have
in common?

First Class Styles

Locally define styles

— then —

Pass directly to elements

.foo { color: red }
import styles from './Component.css';
<div className={styles.foo} />
const styles = StyleSheet.create({
 foo: { color: 'red' }
});
<div style={styles.foo} />

We've been putting this into practice
for the past year...

  • 70 CSS files
  • 782 rules
  • 948 selectors
  • 2,886 declarations
  • 211 media queries

Our global CSS footprint?

/* http://meyerweb.com/eric/tools/css/reset/ 
 v2.0 | 20110126
 License: none (public domain)
*/
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed, 
figure, figcaption, footer, header, hgroup, 
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
 margin: 0;
 padding: 0;
 border: 0;
 font-size: 100%;
 font: inherit;
 vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure, 
footer, header, hgroup, menu, nav, section {
 display: block;
}
body {
 line-height: 1;
}
ol, ul {
 list-style: none;
}
blockquote, q {
 quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
 content: '';
 content: none;
}
table {
 border-collapse: collapse;
 border-spacing: 0;
}
html {
 font-family: @base-font-stack;
 font-size: unit(@base-font-size, px);
 background-color: @sk-background;
 box-sizing: border-box;
 min-height: 100%;
 overflow-y: auto;
}
*,
*:before,
*:after {
 font-family: inherit;
 box-sizing: inherit;
 -webkit-tap-highlight-color: rgba(0,0,0,0);
 -webkit-tap-highlight-color: transparent; /* For some Androids */
}
body {
 overflow-y: hidden;
}
input {
 margin: 0;
}
input[type=search]::-webkit-search-decoration {
 -webkit-appearance:none;
}
  • Increased authoring speed
  • Less fear of change
  • Maintainable by default
  • Faster debugging
  • Simpler onboarding

Easier style guide extraction

But that’s a topic for another day…

👍
😍😍😍

AltStyle によって変換されたページ (->オリジナル) /