CSS Components in Practice

Andrey Sitnik, Evil Martians

Russia

Our Projects

Russia

Components

Components

everywhere

Component is a small and isolated

part of an interface

Project Structure

  • compontents/
    
    • logo/
      • logo.js
      • logo.css
    • header/
      • header.css
      • header.js

Why small components

are a big deal?

Programming ≠ Frameworks

jQuery

Backbone

Angular

React

Backbone

Angular

React

?

Programming ≠ Code

“Controlling complexity

is the essence

of computer programming”

— Brian Kernighan

3 objects

6 objects

3 connections

15 connections

Complexity Grows Fast

“Divide and Conquer”

No components

With components

2. Tools

.window {
  …
}
.name {
  background: red;
}
.popup {
  …
}
.name {
  border-color: blue;
}
.window {
  …
}
.name {
  background: red;
}

← Conflict →

.popup {
  …
}
.name {
  border-color: blue;
}

BEM?

.popup_name {
  background: red;
}

.window_name {
  border-color: blue;
}

Versions Conflict

  • header

    • search-field 2.0
       

  • legacy-page

    • search-field 1.0

Prefixes Conflict

@import "bankform";

@import "../bankform";

“Autoprefixer” for BEM?

.name {
    …
}
.popup_name_hv65 {
    …
}
.block_element_hash { }
        

CSS Modules — AutoBEM

import style from "./popup.css";

export default Popup = (props) => (
  <div class={ style.popup }>
    <h1 style={ style.name }>
      { props.name }
    </h1>
  </div>
);

No React?

CSS Modules

PostCSS plugin 1

PostCSS plugin 3

PostCSS plugin 2

PostCSS plugin 4

postcss-modules

PostCSS

PostCSS plugin 1

PostCSS plugin 3

PostCSS plugin 2

PostCSS plugin 4

.name {
  …
}
.Logo_name_6gj5 {
  …
}
{
  name: "Logo_name_6gj5"
}

Ruby on Rails

- style = load_json('logo.css.json');

%div{ class: style.name }

Problem

CSS Modules

Another way?

Inline CSS?

const style = {
  color: 'blue'
};

return <a style={ style }></a>;

Bad Performance

JSS

jss.createStyleSheet({

  name: {
    color: 'blue',
    '&:hover': {
      color: 'red'
    }
  }

}).attach();


.name--jss-0-0 {
  color: blue;
}
.name--jss-0-0:hover {
  color: red;
}

CSS Modules

Server-side render

CSS syntax

JSS

Dynamic values

JS syntax

<Header>
  <Logo />
</Header>
<Footer>
  <Logo />
</Footer>

Problem 2

<Header>
  <Logo />
</Header>
<Footer>
  <Logo />
</Footer>
.header {
  line-height: 1.4;
}
.footer {
  line-height: 1;
}
.logo {
}
.logo {
}

Inherited properties

.header
  .logo
​    a
{ line-height: 1.4; }
line-height: 1.4
line-height: 1.4
.header {
  line-height: 1.4;
}
.footer {
  line-height: 1;
}
.logo {

}
.logo {

}
line-height: 1.4;
line-height: 1;

Conflict

<Logo />

Project 1

Project 2

/* Reset */
* {
  padding: 0;
}
/* Reset */
* {
  box-sizing: border-box;
}

Local Reset

h1, h2, …, div {
  /* Reset */
}

.header {
}
.logo {
}
.header, .logo {
  /* Reset */
}

.header {
}
.logo {
}

Global Reset

Reset

Header

Logo

Reset

Header

Reset

Local Reset

Global Reset

Logo

.header
  .logo
​    a
line-height: 1.4
line-height: default
line-height: default

Isolated

Explicit Inherit

.button {
  font: inherit;
}

Isolates from this Too

h1 {
  padding-bottom: 10px;
}
.article div {
  background: blue;
}

postcss-autoreset

require('postcss-autoreset')({
  reset: {
    all:       'initial',
    font:      'inherit',
    boxSizing: 'border-box'
  }
})

jss-isolate

require('jss-isolate')({
  reset: {
    all:       'initial',
    font:      'inherit',
    boxSizing: 'border-box'
  }
})

Isolation Overview

Selectors: CSS Modules or JSS

Properties: postcss-autoreset or jss-isolate

Open Questions

  1. CSS Modules syntax sugar for server-side
  2. Move Local Reset practice

3. Practice

Best Tools ≠ Good Code

Problem 1

.logo {
  &.is-small { }
  &.is-smaller { }
  &.is-super-small { }
  &.is-super-small-but-no-so-small { }
}

Size in Container

.logo {
  width: 100%;
  height: 100%;
}

.headerLogo {
  position: relative;
  width: 32px;
  height: 32px;
  margin: 10px 0;
}
<div style={ s.headerLogo }>
  <Logo></Logo>
</div>

Scale by Font Size

.button {
  height: 3em;
}

.formSubmit {
  font-size: 20px;
}
.formBack {
  font-size: 14px;
}

Container Queries

.form:container(width >= 100px) {
    flex-direction: column;
}

CQ Prolyfills

Problem 2

.button_icon {
  &.is-ok     {  }
  &.is-back   {  }
  &.is-remove {  }
  &.is-time   {  }
  &.is-close  {  }
  …
}

Use Component’s Children

<Button text="Remove">
  <RemoveIcon></RemoveIcon>
</Button>

Animation Components

<AnimakitRotator
  side={ this.state.loading ? 1 : 0 }
>
  <SubmitButton>
  <Loader>
</Rotator>

React Shuffle

<ReactShuffle>
  <Icon key="1"></Icon>
  <Icon key="2"></Icon>
  <Icon key="3"></Icon>
  <Icon key="4"></Icon>
  <Icon key="5"></Icon>
  <Icon key="6"></Icon>
</ReactShuffle>

Open Questions

  1. Component Themes

4. Benefits

Widgets

<link rel="stylesheet"
      src="/💩💩💩.css">

<link rel="stylesheet"
      src="https://a.com/widget.css">

Components from npm

<BillingForm color={ colors.main }
             onPay={ this.pay.bind(this) }>
</BillingForm>

Shared Components

<UIKitButton></UIKitButton>

Project 1

Project 2

Big Company

Less Tests

Better Tools

.LogoText {
  font-wight: bold;
  color: blue;
}

.HeaderName {
  font-wight: bold;
  color: blue;
}
.LogoText, .HeaderName {
  font-wight: bold;
  color: blue;
}

Links