css-sucks-2015



css-sucks-2015

3 68


css-sucks-2015

Slides: CSS Still Sucks 2015 & POCss

On Github Huxpro / css-sucks-2015

CSS still Sucks 2015

and how we try to work around it

黄玄/@huxpro

export default () => (
    <Huxpro zh='黄玄' en='Hux'>
        <Wepiao> Frontend Infrastructure Team @2015 </Wepiao>
        <Taobao> Alibaba Trip Mobile Team @2014 </Taobao>
    </Huxpro>
)

Blog / Weibo / GitHub / 知乎

Document Times

HTML is born for document in 1993

Cascading Style Sheet

层叠样式表

Priority & Inheritance

### <em class="b" id="g">Priority</em> & *Inheritance*
h3 {
    color: white;
    font-size: 1.3em;
}
em {
    color: #ffef99;
    font-style: italic;
}
.b { color: blue; }
#g { color: gold; }

we are good at cascading!

thinking globally makes sense

we have got great

Frameworks

Bootstrap and Foundation

and good

Style Guide

OOCSS - Object Oriented CSS

(Nicole Sullivan 2008)

  • Class everything for reusablity
  • Separate structure and skin Reuse visual feature as skins (mixable) Structural semantics are provided by structural classes Reference classes instead of HTML tags. (flexible HTML)

  • Separate container and content Rarely use location-dependent styles Classes over tags, avoid the descendent selector An object should look the same no matter where you put it.

An Introduction To OOCSS →

The Media Object Saves Hundreds Of Lines Of Code →

(Nicole Sullivan 2010)

<div class="media">
    <a href="#" class="img">
        <img src="myAvatar.jpg" alt="huxpro" />
    </a>
    <div class="bd">
        <a href="#">@huxpro</a>
        <span class="detail">14 miniutes ago</span>
    </div>
</div>

Fighting with number of words...

What is meant by an “object” in OOCSS? →

A common case you may be familier with

<div class="mod">
    <div class="inner">
        <div class="hd">Block Head</div>
        <div class="bd">Block Body</div>
        <div class="ft">Block Foot</div>
    </div>
</div>

"Each CSS class is not necessarily an object in its own right, but can be a property of a wrapper class."

Reusable, Portable, Not Easy...

"CSS Zen Garden proved that we can alter a design into a myriad of permutations simply by changing the CSS. However, we’ve rarely seen the flip side of this — the side that is more likely to occur in a project: the HTML changes. We modify the HTML and then have to go back and revise any CSS that goes with it."

Decouple HTML from CSS →

SMACSS - Scalable and Modular Architecture for CSS

(Jonathan Snook 2012)

  • Categorizing CSS Rules Base, Layout, Module, State, Theme
  • Naming Ruleseasier to clarity
  • Minimizing the Depthdecrease reliance on specific HTML

Sharing similar idea with OOCSS Well, It is really a long style guide

Even amazing

Pre-processers

2010 2006!!! 2009

You can't imagine how early they first appeared!

I ❤︎ THEM!

  • Variableseasy to standardize, theming
  • Nestingnested selctors are "scoped" (also increase specificity)
  • Mixinspredictable and flexible code repetitions
  • Selector inheritanceDRY: Dont Repeat Yourself
  • Language Enhancementimport, math, loop, operators...

One more thing

PostCSS

(Since Sep 2013)

Everyone should hear about

not? watch may another talk

Autoprefixer

Yes, one of the most famousPostCSS Plugins!

Well, OfficiallyPostCSS is Not a Post-processor

It is time admit my mistakes. “Postprocessor” term was bad. PostCSS team stoped to use it.

— PostCSS (@PostCSS) July 28, 2015

  • And...
  • PostCSS is NOT a Pre-processor
  • PostCSS is NOT “Future Syntax”
  • PostCSS is NOT a Clean Up / Optimization Tool
  • PostCSS is NOT Any One Thing

But PostCSS plugins can do ALL those cool shit...

PostCSS is a tool for transforming CSS with JS plugins. These plugins can support variables and mixins, transpile future CSS syntax, inline images, and more.

PostCSS is "CSS and beyond" →

In my view, the Babel and Webpack for CSS we will keep mentioning it...

Everything is good until...

Application Times

After 22 years evolution...

Single Page Application

单页面应用

Styling Components

组件样式内聚

2014.11 problems with CSS for building larger applications - NationJS @vjeux →

Let's look at future!

be future-proofing

Shadow DOM

provides encapsulation for the JavaScript, CSS, and templating in a Web Component.

CSS "4"

Houdini

Houdini: Maybe The Most Exciting Development In CSS You’ve Never Heard Of →

Well...future is still future.

Let's back to Today.

when we talk about "today", what we actually mean is community...

Naming Convention

Believe me, This is a long story

.TheStory__ofNamingConvention--whateverYouChoose.is-kindsOfLooong{}

BEM - “block, element, modifier”

(2012)

.block__element--modifier

.block{}
.block__element{}
.block--modifier{}
.block__element--modifier{}

check getBEM.com to get started

Let's draw a BEMed Button!drawing button is the "hello world" of a styling tool

.slds-button{}                   /*block*/
.slds-button--inverse{}          /*inverse modifier*/
.slds-button__icon{}             /*icon element in block*/
.slds-button__icon--left{}       /*icon element in the left*/
.slds-button__icon--right{}      /*icon element in the right*/
<button class="slds-button">normal</button>
<button class="slds-button slds-button--inverse">inverse</button>
<button class="slds-button">button with a right icon
    <svg class="slds-button__icon slds-button__icon--right"></svg>
</button>

Uuuugly? This is a real-world example Button - "Salesforce design system" → Building an Enterprice CSS Framework →

‘Why BEM?’ in a nutshell →

decrease cascading

/* Bad */
.block .element{}        /* nesting */
.element.modifier{}     /* chained */

/* Good */
.block__element{}
.element--modifier{}
Why not use element type selectors with child or sibling combinators (like ul > li + li) to avoid inheritance issues?

Get loose coupled CSS from HTML! Remember OOCSS? →

Nesting is such a brilliant feature of pre-processors! With BEM it sucks.
.block{
    .element{
        &.modifier{ color: red; }
    }
    .modifier{ color: blue; }
}

// Generates
.block .element.modifier{ color: red; }
.block .modifier{ color: blue; }

// hmm...what's the color when you use .modifier?

Is It Real?

Sass 3.3 supports BEM officially! - Sass Blog

[2014.03] "With the rise in popularity of BEM, OOCSS, and SMACSS, people became more and more interested in adding suffixes to classes."
.block{
    &__element{
        &--modifier{ color: red; }
    }
    &--modifier{ color: blue; }
}

// Generates
.block__element--modifier{ color: red; }
.block--modifier{ color: blue; }

perfect flat!!

I want to highlight this person:

Nicolas@Twitter

  • normalize.css
  • react-native-web

About HTML semantics and front-end architecture →

[Youtube] Adaptation and Components → In this video, he introduce us...

SUIT CSS - Style for components

(2014)

Another Interesting Shit

Atomic CSS

What's that??

The Plain Way (metaCSS):

  <div class="fwb tar bd1"></div>
  <div class="m-5 mt-10"></div>

Yahoo! Atomizer:

<div>
  <div class="Bgc(#0280ae.5) H(90px) IbBox W(50%) foo_W(100%)"></div>
  <div class="Bgc(#0280ae) H(90px) IbBox W(50%) foo_W(100%)"></div>
</div>

God...

Atomic CSS - Better Inline Styling

(Thierry 2013)

  • Classes related to presentation instead of content WAT!? It's non-semantics and a anti-pattern → "Reinventing Inline CSS!" Well, I hold similar POV (1)(2) in the most beginning

  • Better inline styling with classes Lower specificity of classes Pseudo-classes or pseudo-elements support Portable, reusable (like OOCSS) Better caching and compression!

2013.10 Challenging CSS Best Practices →

For the end result

  • Borrows many of pros from inline styles Stop specificity wars Pure Presentational classes lead to=> Few content-derived class or context-based selector => Work around the global namespace and scope issues.

  • Classes is static analysable Dead code elimination possible Classnames uglification/minification possible Perfect compile-target (react-native-web/styleSheet API)

I should recall 'Atomic CSS is wrong' → separate the whole concept into two parts makes things clearThe End Result vs "Authoring Time"

Why not give up CSS entirely?

WAT?

why not?

CSS in JS

Story back to crazy facebook

2014.11 React: CSS in JS @vjeux →This talk is INSANE and you had better go through it yourself

This idea just erupted!

2015.07 [Youtube][ReactEurope] Michael Chan -Inline Styles: themes, media queries, contexts, & when it's best to use CSS →The BEST talk I watched about inline styles

Inline Styles - React Doc

The current set of tooling for this approach is yet to properly support progressive enhancement (support for media queries, pseudo classes and sibling selectors is patchy, at best), but this is an area that is showing a lot of promise.

2015.04 SEEK UI Engineering - Block, Element, Modifying Your JavaScript Components →

Remember "SEEK UI Engineering", you will know...

BLOOOOOM! Libs come to help

Bunch of CSS in JS Libs for React...

Radium - Comparison of CSS in JS Libraries for React →

Quick Look

2015.07 [Youtube] Michael Chan -Inline Styles: themes, media queries, contexts, & when it's best to use CSS →NOT BAD!

Problem solved!

2014.11 React: CSS in JS @vjeux →And supporters hold that React Native use it

Caaaaaaaalm Down!

and learn javascript listen some negative voice...

Overengineered, Unstable... Learning Curve & Migration Costs

It's great. But maybe you like

a little 'old way'

to write css in .css file

The community is insane...

CSS Modules

Post by "SEEK UI Engineering"!

Believe me, It's unbelievable

1. Local by default

Let's draw some buttons!

/* components/submit-button.css */
.Button { /* all styles for Normal */ }
.Button--disabled { /* overrides for Disabled */ }
.Button--error { /* overrides for Error */ }
.Button--in-progress { /* overrides for In Progress */

Before CSS Modules

/* components/submit-button.css */
.normal { /* all styles for Normal */ }
.disabled { /* all styles for Disabled */ }
.error { /* all styles for Error */ }
.inProgress { /* all styles for In Progress */

With CSS Modules

Time for JavaScript

/* components/submit-button.js */
import styles from './submit-button.css';

buttonElem.outerHTML = `
  <button class=${styles.normal}>Submit</button>
`

↓ time for magic

<button class="components_submit_button__normal__abc5436">
  Processing...
</button>

BLOOOOOOOM! Did you see the classnames? It's HASHED!

2. Composition is everything

shared styles between all the states

/* BEM Style */
innerHTML = `<button class="Button Button--in-progress">`

/* CSS Modules */
innerHTML = `<button class="${styles.inProgress}">`

each class should contain all the styles

.common {
  /* all the common styles you want */
}
.inProgress {
  composes: common;    /* similar to Sass @extend */
  /* anything that only applies to In Progress */
}

CSS Modules changes which classes are exported to JavaScript.

Under the hood

.common { /* font-sizes, padding, border-radius */ }
.normal { composes: common; /* blue color, light blue background */ }
.error { composes: common; /* red color, light red background */ }
.components_submit_button__common__abc5436 { /* font-sizes, padding, border-radius */ }
.components_submit_button__normal__def6547 { /* blue color, light blue background */ }
.components_submit_button__error__1638bcd { /* red color, light red background */ }

In your JS code, import styles from "./submit-button.css" returns:

styles: {
  common: "components_submit_button__common__abc5436",
  normal: "components_submit_button__common__abc5436 components_submit_button__normal__def6547",
  error: "components_submit_button__common__abc5436 components_submit_button__error__1638bcd"
}

that's how we get multiple class rendered into the DOM.

3. Sharing between files

@import or require dependencies

/* colors.css */
.primary {
  color: #720;
}
.secondary {
  color: #777;
}
/* other helper classes... */
/* submit-button.css */
.common { /* font-sizes, padding, border-radius */ }
.normal {
  composes: common;
  composes: primary from "../shared/colors.css";
}

Influencer: Smarter CSS(SCSS) builds with Webpack

4. Single responsibility modules

@mixin also has a replacement

.element {
  composes: large from "./typography.css";
  composes: dark-text from "./colors.css";
  composes: padding-all-medium from "./layout.css";
  composes: subtle-shadow from "./effect.css";
}
/* this short hand: */
.element {
  composes: padding-large margin-small from "./layout.css";
}

/* is equivalent to: */
.element {
  composes: padding-large from "./layout.css";
  composes: margin-small from "./layout.css";
}
2015.08 Welcome to the future → github repos →

wanna listen some low-level stories?

Let's Go A Little Deeper

History of CSS Modules

Local Scope changed everything new feature landed in webpack css-loader

require('./MyComponent.css');

// becomes...
import styles from './MyComponent.css';
:local(.header) { ... }
:local(.footer) { ... }

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

NO MORE NAMING COLLISIONS!

Classname Mapping

// Styles object:
{
  'header': '_1rJwx92-gmbvaLiDdzgXiJ',
  'footer': '_ah6Hch-gjsAdSE53CxzaEs'
}
import styles from './MyComponent.css';

export default () => (
  <div>
    <div className={styles.header}>...</div>
    <div className={styles.footer}>...</div>
  </div>
);

“What if locally scoped CSS was the default?”

and only global class need :global()

PostCSS-local-scopeTurned .class into :local(.class)

“I hope it’s ok if I integrate your postcss-local-scope module into the css-loader”@SOKRA — MAY 24, 2015

css-loader?modulescss-loader?modules&localIdentName=[name][local]_[hash:base64:5]

Interoperable CSSlow-level file format that enabled CSS Modules

That is now supported by default in Webpack & JSPM, and available with plugins for Browserify. And it hopes to do for CSS what CommonJS did for JavaScript.

[Youtube] 2015.10 CSSconf EU 2015 | Glen Maddern: Interoperable CSS → github repos →

hmm...seems perfect...

I Truly Love it but

there is still something trouble...

  • You can never override classes from another file Import className from fileName #40 → Damn easy to override a class in old css by using selectors (.scope .be-overrode{}) With CSS Modules, a css file can never know the actual classname another css file

  • This is a half way between CSS and CSS-in-JS Every style need to be set in .JS file, and some stuff can be only done in JS, Which means all your CSS is highly coupled with your JS There is still a expensive migration costs for old projects. There is still a learning curve especially for HTML/CSS-only Engineers

  • Future of CSS? Or a present compromise.Until ICSS is officially inclued into CSS spec

They don't trouble JSer

It just force you thinking everthing in JavaScript and Components

"Anyway, this all is the cost of the encapsulation. Which is harder, but absolutely better." - #40

But, what if there are HTML/CSS Engineers in the team? It's very common. for example your designer can do CSS?

HTML/CSS-only Engineer

I searched Linkedin

PSD-to-HTML + SCSS + RWD + Gitpretty nice!

in China, we call it Web Rebuild

Im confusing! where does this naming come from?

What the hell is this translating...

we already saw its power

PostCSS, again

some nice idea

There are possibilities in PostCSS community I believed

At your own risk to use in production...

You ask me

My Opinion?

it’s not like one approach is de facto better than the other as this would depend on which factors are to be taken into consideration. @Thierry

  • Small and full-stack team CSS Modules/Inline CSS/Atomic CSS...Go pick your favourite one! They are all extremely engineering way, but solve problem perfectly Everyone in your team had better to know modern JavaScript (and webpack) well

  • Big and tranditional team Pick a Naming Convention (BEM/SUIT/ECSS etc) or make your own. Especially there is HTML/CSS engineers in your team, let them do what they do best

  • Hey Im working on websites, not apps Just keep your old way if it is satisfied! Those stuff may well are over-engineered to your product!

A pragmatic naming proposal used in my team

Pages override Components CSS

for component-based multi-entries SPA

In multi-entries SPA

  • Pages share components with different business logic
  • The order of loading styles is dynamic

1. Scoping Components CSS Blocks should only be used inside a component of the same name.

// Component/index.scss
.ComponentName {
    &__decendentName {
        &--modifierName {}
    }
    .isStateOfComponent {}
}
// Component/index.js
require('./index.scss');

CSS is always bundled with components(from loading, mount to unmount)

2015.05 Smarter CSS(SCSS) builds with Webpack → 2015.04 Block, Element, Modifying Your JavaScript Components →

2. Components can be Overrode by Pages There is always requirements to rewrite styles of components in pages

// Pages/PageA.scss
#PageA {
    .pagelet-name {
        .pagelet-descendent-name {}
    }
    .ComponentName{ /* override */ }
}
// Pages/index.js
require('./PageA.scss');
  • #Page for absolutely scoping between pages
  • .pagelet-name should be lowercase to prevent conflicting with components

Why POCss?

  • It's technology-agnostic One css framework can be played with whatever technology stacksYou can combined Scss, PostCSS and whatever you want

  • Solving problems, and easy Makes reading and teamwork much easierGet all benefit from BEM, SUITCSS and others

  • Leverage the power of cascading properly Scoping components but allow reasonable overridingIt's pragmatic, flexible and hitting the sweet spot

“It was the best of times, it was the worst of times”

Question

Hey, don't be shy.

huangxuan.me/css-sucks-2015

Open Source @ Github

THE END

黄玄
Blog / Weibo / GitHub / 知乎