Component development in CSS

Varya Stepanova, SC5 Online

Component development in CSS

by Varya Stepanova from SC5 Online

Me

Now

Senior Frontend Developer for SC5 Online

Before

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

Area of expertise

Components on the web: 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

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>
.sidebar { /* Does is redefine `div.sidebar`?! */
  float: right;
}
body .sidebar { /* Overwrites 'div.sidebar {}' */
  float: right;
}

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;
}

Non-deterministic matches

#content div div {
  float: left;
}

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?

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>
      <div class="menu">...</div>
  </div>

Why not…?

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

No IDs

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…?

<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 an elements’ modifier

.block
  /* styles for block */
}
  .block--element {
    /* styles for element */
  }
    .block--element_modifier {
      /* styles for modified element
    }

Why not…?

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

Why not…?

<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, baby */
}

BEM & CSS preprocessors

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

getbem.com

This is solved

Web Components

Technologies behind

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>

Are We Componentized Yet?

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

SGDD

Living Styleguides

A living styleguide represents UI components of your website with exact the same styles which you use across the project.

Style Guide Driven Development

Styleguide Driven Development is the practise of using the styleguide as the focal point for all front-end UI development tasks.

sc5-styleguide package

npm install sc5-styleguide

SC5 Styleguide

http://styleguide.sc5.io

Killer features

How it works

my-styles/
  atoms/
    header.sass
    menu.sass
    footer.sass
  common.sass
  index.sass
  products.sass
  • CLI
  • Gulp
  • Grunt
Gulp Stream

KSS Knyle Style Sheets

// A button suitable for giving a star to someone.
//
// :hover             - Subtle hover highlight.
// .star-given        - A highlight indicating you've already given a star.
// .star-given:hover  - Subtle hover highlight on top of star-given styling.
// .disabled          - Dims the button to indicate it cannot be used.
//
// Styleguide 2.1.3.
a.button.star{
  ...
  &.star-given{
    ...
  }
  &.disabled{
    ...
  }
}

Integration

Build the data

gulp.task('styleguide:generate', function() {
  return gulp.src('*.scss') // Or *.less, or *.css
    .pipe(styleguide.generate({
        rootPath: './output',
        overviewPath: 'README.md'
      }))
    .pipe(gulp.dest(outputPath));
});

Integration

Apply styles

gulp.task('styleguide:applystyles', function() {
  return gulp.src('main.scss')
    .pipe(sass({
      errLogToConsole: true
    }))
    .pipe(styleguide.applyStyles())
    .pipe(gulp.dest('./output'));
});

Integration

Watch the changes

gulp.task('styleguide',
          ['styleguide:generate', 'styleguide:applystyles']);

gulp.task('watch', ['styleguide'], function() {
  gulp.watch(['*.scss'], ['styleguide']);
});

Development with SC5 Styleguide

Component development in CSS

varya.me/component-development-css

Fork me on Github