Component development with CSS in 2018 {#cover}

Varya Stepanova, Intergalactico - Nordcloud Design Studio

Component development with CSS in 2018

Varya Stepanova, Design Systems Specialist
at Intergalactio - Nordcloud Design Studio

Me

Now

Design Systems Specialist
at Intergalactico Nordcloud Design Studio

Before

TMG (Amsterdam, the Netherlands); Yandex (Moscow, Russia)

Area of expertise

Components on the web: design systems, pattern libraries, SGDD, BEM. Techs: CSS, JavaScript, etc.

Spoiler

CSS

Cascading Style Sheets (CSS) is a style sheet language used for describing the look and formatting of a document written in a markup language. Wikipedia

First published in 1996

Industry challenges

Bulletproof Web Desing

Big CSS

Massive web sites

Big teams

Heavy UI

Heavy UI

<form class="b-mail-domik g-js" method="post" action="https://passport.yandex.com/passport?mode=auth&amp;from=mail&amp;origin=hostroot_com_nol_enter&amp;retpath=https%3A%2F%2Fmail.yandex.com">
  <i class="b-mail-domik__roof"></i>
  <table class="b-mail-domik__shadow">
    <tbody>
      <tr>
        <td class="b-mail-domik__shadow__lt">&nbsp;</td>
        <td class="b-mail-domik__shadow__t"></td>
        <td class="b-mail-domik__shadow__rt">&nbsp;</td>
      </tr>
      <tr>
        <td class="b-mail-domik__shadow__l">&nbsp;</td>
        <td class="b-mail-domik__shadow__m">
          <div class="b-mail-domik__form">
            <div class="b-mail-domik__username">
              <label class="b-hint-input g-js" for="b-mail-domik-username11" style="display: block;">username</label>
              <div class="b-input"><input tabindex="1" name="login" id="b-mail-domik-username11" class="b-input__text" autocapitalize="off" autocorrect="off" aria-label="username"></div>
            </div>
            <div class="b-mail-domik__password">
              <label class="b-hint-input g-js" for="b-mail-domik-password11">password</label>
              <div class="b-input"><input type="password" tabindex="2" name="passwd" id="b-mail-domik-password11" class="b-input__text" aria-label="password"></div>
            </div>
            <div class="b-mail-domik__permanent"><input type="hidden" name="twoweeks" value="yes"><input type="checkbox" tabindex="3" id="b-mail-domik-permament11" class="b-mail-domik__check">&nbsp;<label for="b-mail-domik-permament11">don't remember me</label></div>
            <div class="b-mail-domik__button b-mail-domik__button_qr"><span class="b-mail-button b-mail-button_default b-mail-button_button b-mail-button_grey-26px b-mail-button_26px b-mail-button_lead"><span class="b-mail-button__inner"><span class="b-mail-button__text">Log in</span></span><input type="submit" tabindex="4" class="b-mail-button__button" value="Log in"></span><a href="https://passport.yandex.com/auth/?mode=qr&amp;retpath=https%3A%2F%2Fmail.yandex.com" class="js-button-qr b-mail-button b-mail-button_default b-mail-button_button b-mail-button_grey-26px b-mail-button_26px b-mail-button_dependent"><span class="b-mail-button__inner"><span class="b-mail-button__ico b-mail-button__ico_qr"></span></span></a></div>
            <div class="b-mail-domik__remember"><a tabindex="5" class="b-mail-domik__remind js-count-click" href="https://passport.yandex.com/passport?mode=restore" data-metrika="Клики на 'Вспомнить пароль'" data-paranja="check">Forgot your password?</a></div>
            <div class="b-mail-domik__social"><a class="b-mail-domik__social-link js-social-link" data-provider="fb"><i class="b-mail-domik__social-icon b-mail-domik__social-icon_provider_fb"></i></a><a class="b-mail-domik__social-link js-social-link" data-provider="tw"><i class="b-mail-domik__social-icon b-mail-domik__social-icon_provider_tw"></i></a><a class="b-mail-domik__social-link js-social-link" data-provider="gg"><i class="b-mail-domik__social-icon b-mail-domik__social-icon_provider_gg"></i></a></div>
          </div>
        </td>
        <td class="b-mail-domik__shadow__r">&nbsp;</td>
      </tr>
      <tr>
        <td class="b-mail-domik__shadow__lb">&nbsp;</td>
        <td class="b-mail-domik__shadow__b"></td>
        <td class="b-mail-domik__shadow__rb">&nbsp;</td>
      </tr>
    </tbody>
  </table>
  <div class="antivirus js-antivirus">Yandex.Mail has <a href="http://www.drweb.com/" target="_blank"></a> virus protection</div>
</form>

Long running projects

Where is CSS hard?

Building meme

Is this good?

H1 { color: blue }
P EM { font-weight: bold }
A:link IMG { border: 2px solid blue }
A:visited IMG { border: 2px solid red }
A:active IMG { border: 2px solid lime }

What makes CSS hard?

What really makes CSS hard?

CSS has no scoping

a { /* Affects all the links */
  color: red;
}
ul li a { /* Affects all the links in lists */
  color: green;
}

Specificity

Specificity is the means by which a browser decides which property values are the most relevant to an element and gets to be applied. Specificity is only based on the matching rules which are composed of selectors of different sorts.

The most specific matters

<div id="test">
  <span>Text</span>
</div>
div#test span { color: green }
span { color: red }
div span { color: blue }

How to overwrite?

<div class="sidebar">Left floated sidebar</div>

Specificity hell

.navbar-inverse .navbar-nav>li>a {
  color: #999;
}

#home-menu-container #home-menu li a {
  color: red;
}

body #home-menu ul li a {
  color: blue !important;
}

Family guy meme

Non-deterministic matches

#content div div {
  float: left;
}

Doctor meme

Dependency management

No dependencies, sorry

No, sorry again.

Removing unused code

100 pages in projects

.person div a {
  color: pink;
}

Can I remove it? Will it break something? Maybe it is for a third-party HTML code?

Where CSS is hard?

This is not hard in CSS This is!
#sidebar ul li a {
  color: red;
  display: block;
  padding: 1em;
}
#sidebar ul li a {
  color: red;
  display: block;
  padding: 1em;
}

How do we architect encapsulated components?

Dealing with CSS

Ways out

Standards

W3C

Web Components

Web Components

HTML import, library

<!-- Import element -->
<link rel="import" href="my-lib/google-map.html">

<!-- Use element -->
<google-map lat="37.790" long="-122.390"></google-map>

Web Components Status Quo

Web Components Polyfills

Make it work

<!-- Polyfill Web Components support for older browsers -->
<script src="webcomponents.min.js"></script>

<!-- Import element -->
<link rel="import" href="google-map.html">

<!-- Use element -->
<google-map lat="37.790" long="-122.390"></google-map>

Ready-made components

Usage examples

Methodologies

OOCSS

Nicole
Sullivan

SMACSS

Jonathan
Snook

BEM

Vitaly
Harisov

Sergey
Berezhnoy

BEM eco-system

Harry & Nicolas

Harry
Roberts

Nicolas
Gallagher

BEM

Interface

Interface of blocks

Everything is a block

<body class="page">

<div class="header">
  <img class="logo" ... />
  <div class="search">...</div>
  <div class="menu">...</div>
</div>

<div class="layout">
  <div class="sidebar">...</div>

Why not to use ID?

<ul id="menu">
  <li>Tab 1</li>
  <li>Tab 2</li>
<ul>
#menu {
  /* styles for the menu */
}

Someday you will need to repeat the block at the same page.

Elements

Elements markup

<div class="tabbed-pane">
  <ul>
    <li class="tabbed-pane__tab">Tab1</li>
    <li class="tabbed-pane__tab">Tab2</li>
    <li class="tabbed-pane__tab">Tab3</li>
  </ul>
  <div class="tabbed-pane__pane">
    ...
  </div>
</div>

CSS for an element

.block {
  /* styles for block */
}
.block__element {
  /* styles for element */
}

Why not cascade?

<ul class="menu">
  <li class="item">Tab 1</li>
  <li class="item">Tab 2</li>
<ul>
.menu .item {
  /* styles for element */
}

No cascade

<div class="panels">
  <div class="item">
    <ul class="goods">
      <li class="item">
        <!-- Remember: non-deterministic matches -->
      </li>
    </ul>
  </div>
</div>

Modified block

Modifier

<ul class="menu menu--footer">
  <li class="menu__item"></li>
  ...
</ul>
.menu--footer {
  font-size: 0.8em;
}

CSS for a modifier

.block {
  /* styles for block */
}
.block--modifier {
  /* styles for modifier */
}
.block__element {
  /* styles for element */
}

Modified element

Element’s modifier

<ul class="menu">
  <li class="menu__item">Tab 1</li>
  <li class="menu__item menu__item--current">Tab 2</li>
  <li class="menu__item">Tab 3</li>
</ul>

CSS for element modifier

.block
  /* styles for block */
}
.block__element {
  /* styles for element */
}
.block__element--modifier {
  /* styles for modified element
}

Why not combined selector?

<ul class="menu footer"><ul>
.menu.footer { /* combined selector */
  font-size: 0.8em;
}

Why not combined selector?

<ul class="menu">
  <li class="menu__item current">Tab 2</li>
<ul>
.menu__item.current { /* combined selector */
  background-color: red;
}

No overspecific selectors

You would suffer when redefining

.menu__item.current {
  background: white;
}
.menu--dark .menu__item {
  background: black; /* Still white, babe */
}

BEM & CSS preprocessors

.block {
  /* styles for block */
  &--modifier {
    /* styles for modifier */
  }
  &__element {
    /* styles for element */
  }
}

getbem.com

This is solved

Technology

Modular CSS

CSS modules

Glen
Maddern

Manual CSS

page.html

<h1 class="title">An example heading</h1>

styles.css

.title {
  background-color: red;
}

CSS modules input

page.js -> page.html

import styles from "./styles.css";

element.innerHTML = 
  `<h1 class="${styles.title}">
     An example heading
  </h1>`;

CSS modules output

page.html

<h1 class="_styles__title_309571057">
  An example heading
</h1>

styles.css

._styles__title_309571057 {
  background-color: red;
}

Automated BEM

BEM CSS modules
.button {  }
.button--disabled {  }
.button__label {  }
.button {  }
.disabled {  }
.label {  }

styles: {
  button: 'button__abc5436',
  disabled: 'button__disabled__deff65',
  label: 'button__label__1638bcd'
}

CSS modules pros and cons

JSS

Oleg

JSS syntax

export const styles = {
  button: {
    padding: '10px',
    '&:hover': {
      background: blue;
    }
  }
}

Injecting JSS into HTML

import injectSheet from 'react-jss';
import styles from './styles.js'

const Button = ({ classes, children }) => (
  <button className={classes.button}>
    {children}
  </button>
)

export default injectSheet(styles)(Button);

JSS pros and cons

Why to write classes?

Styled components

Styled crew

To style component

const Title = styled.h1`
  font-size: 1.5em;
  text-align: center;
  color: green;`;

render(
  <Title>
    Hello, world!
  </Title>
)

Reflect the state

const Button styled.button`
  background: ${props => props.primary ? 'green' : 'white' };
  color: ${props => props.primary ? 'white' : 'green' };
  font-size: 1em;`;

render (
  <div>
    <Button>Normal</Button>
    <Button primary>Primary</Button>
  </div>
);

What does browser get?

HTML

<button class="sc-bxivhb clMJJc">Normal</button>
<button class="sc-bxivhb iJPdAn">Primary</button>

CSS

.clMJJc {
  /* ... other rules */
  background: white; color: green;
}
.iJPdAn {
  /* ... other rules */
  background: green; color: white;
}

Styled components

Styled innovation

styled-components […] remove the mapping between components and styles

www.styled-components.com

Component development with CSS in 2018

Thank you

Varya Stepanova, Intergalactico - Nordcloud Design Studio
; on the web: varya.me

Slides

varya.me/component-development-css-2018

Credits

Roman Komarov, @kizmarh; Andrey Okonetchnikov, @okonetchnikov; Vadim Makeev, @pepelsbey_.

Fork me on Github