.css {

  Craftsmanship

}

Developer Advocate & Trainer Manager
at
@SchibstedSpain


#Web #CSS #Javascript

#Animation #PostCSS

Joan León

.Agenda {

  • CSS-Styleguides { }
  • CSS-Naming { }
  • CSS-Architecture { }
  • CSS-Testing { }
  • CSS-Frameworks { }
  • CSS-Knowledge { }
  • CSS-for Developers { }
  • CSS-Tools { }
  • CSS-Craftsmanship { }

}

1

2

3

.CSS-Styleguides {

.CSS-Styleguides {

}

.CSS-Styleguides {

}

Syntax | Code Guide

    /* Bad CSS */
    .selector, .selector-secondary, .selector[type=text] {
      padding:15px;
      margin:0px 0px 15px;
      background-color:rgba(0, 0, 0, 0.5);
      box-shadow:0px 1px 2px #CCC,inset 0 1px 0 #FFFFFF
    }
    
    /* Good CSS */
    .selector,
    .selector-secondary,
    .selector[type="text"] {
      padding: 15px;
      margin-bottom: 15px;
      background-color: rgba(0,0,0,.5);
      box-shadow: 0 1px 2px #ccc, inset 0 1px 0 #fff;
    }

.CSS-Styleguides {

}

Declaration order​ | Idiomatic CSS

    .selector {
        /* Positioning */
        position: absolute;
        z-index: 10;
        top: 0;
        right: 0;
        bottom: 0;
        left: 0;
    
        /* Display & Box Model */
        display: inline-block;
        overflow: hidden;
        box-sizing: border-box;
        width: 100px;
        height: 100px;
        padding: 10px;
        border: 10px solid #333;
        margin: 10px;
    
        /* Other */
        background: #000;
        color: #fff;
        font-family: sans-serif;
        font-size: 16px;
        text-align: right;
    }

.CSS-Styleguides {

}

Titling​ | CSS Guidelines

    /*------------------------------------*\
      #A-SECTION
    \*------------------------------------*/
    
    .selector { }
    
    
    
    /*------------------------------------*\
      #ANOTHER-SECTION
    \*------------------------------------*/
    
    /**
     * Comment
     */
    
    .another-selector { }

.CSS-Styleguides {

}

Units​ | Sass Guidelines




    $value: 42;
    
    // Yep
    $length: $value * 1px;
    
    // Nope
    $length: $value + px;

}

.CSS-Naming {

.CSS-Naming {

}

.CSS-Naming {

}

  • Block The sole root of the component.
  • Element A component part of the Block.
  • Modifier A variant or extension of the Block.​

BEM

.CSS-Naming {

}

BEM


    /* Block component */
    .btn {}
    
    /* Element that depends upon the block */
    .btn__price {}
    
    /* Modifier that changes the style of the block */
    .btn--orange {}
    .btn--big {}


    <a class="btn btn--big btn--orange" href="...">
      <span class="btn__price">100,00 €</span>
      <span class="btn__text">Subscribe</span>
    </a>

.CSS-Naming {

}

  • c- for Components
  • o- for Objects
  • u- for Utilities
  • is-/has- for States

BEMIT

Block, Element, Modifier + Inverted Triangle

Namespaces

.CSS-Naming {

}

BEMIT


    <div class="o-media  c-user  c-user--premium">
      <img src="" alt="" class="o-media__img  c-user__photo  c-avatar" />
      <p class="o-media__body  c-user__bio">...</p>
    </div>


    $s-config__path--img:   "../img" !default;
    $s-config__path--fonts: "../fonts" !default;
    
    $s-config__breakpoint--separator: \@ !default;
    
    @function s-core-breakpoint-suffix($_bp-name) {
      @return unquote("#{$s-config__breakpoint--separator}#{$_bp-name}");
    }
    
    $f-color__brand-primary:   #f25f5c !default;
    $f-color__brand-secondary: #69b7a4 !default;
    $f-color__brand-accent:    #ffe066 !default;
    
    @mixin t-mq(
      $from:          false,
      $until:         false,
      $and:           false,
      $media-type:    $t-sass-mq__media-type,
      $breakpoints:   $t-sass-mq__breakpoints
    ) {
        ...
    }

Namespaces

.CSS-Naming {

}

  • u-hidden@print – a utility class to hide things when in print context.
  • u-1/4@lg – a utility to make something a quarter width in the large breakpoint.
  • o-layout@md – a layout object in the medium breakpoint.

BEMIT

Block, Element, Modifier + Inverted Triangle

Responsive Suffixes

.CSS-Naming {

}

BEMIT



    <div class="o-media@md  c-user  c-user--premium">
      <img src="" alt="" class="o-media__img@md  c-user__photo  c-avatar" />
      <p class="o-media__body@md  c-user__bio">...</p>
    </div>

Responsive Suffixes

.CSS-Naming {

}

  • Utilities `u-[sm-|md-|lg-]<utilityName>`
  • Components `[<namespace>-]<ComponentName>[-descendentName][--modifierName]`
  • Stat of Component `is-stateName`

SUIT CSS


    .MyComponent {}
    .MyComponent.is-animating {}
    .MyComponent--modifier {}
    
    .MyComponent-part {}
    .MyComponent-anotherPart {}

}

.CSS-Architecture {

.CSS-Architecture {

}

.CSS-Architecture {

}

Atomic Design


    base/
    atom/
    molecule/
    organism/
    template/
    page/
    style.scss

.CSS-Architecture {

}

7 in 1 Pattern


    base/
    components/
    layout/
    pages/
    themes/
    abstracts/
    vendors/
    main.scss

.CSS-Architecture {

}

haiticss

}

.CSS-Testing {

.CSS-Testing {

}

Browsers

.CSS-Testing {

}

Show me the code

    <!DOCTYPE html>
    <html>
      <head>
        <title>CSS Grid Layout Test: free space unit</title>
        <link rel="author" title="Leo Deng" href="mailto:myst.dg@gmail.com">
        <link rel="help" href="http://www.w3.org/TR/css-grid-1/#free-space">
        <link rel="match" href="../reference/grid-layout-basic-ref.html">
        <meta name="assert" content="the layout should behave the same as reference.">
        <style>
          body {
            margin: 0;
            padding: 0;
          }
          #caseTitle {
            margin: 10px;
            height: 40px;
          }
          #grid {
            width: 150px;
            background: #eee;
            display: grid;
            grid-template-columns: 1fr 50px;
          }
          .a {
            background: blue;
            grid-column: 1;
            grid-row: 1;
          }
          .b {
            background: yellow;
            grid-column: 2;
            grid-row: 1;
          }
        </style>
      </head>
      <body>
        <p id="caseTitle">The test passes if it has the same visual effect as reference.</p>
        <div id="grid">
          <div class="a"> </div>
          <div class="b"> </div>
        </div>
      </body>
    </html>

.CSS-Testing {

}

Third-Party Testing Services

Browsers & Mobile Devices for Live Testing
Real Mobile & Tablet Devices for App Live Testing
Browsers & Mobile Devices for Selenium Testing
Browsers & Mobile Devices for JavaScript Testing
Browsers & Mobile Devices for Screenshot Testing

.CSS-Testing {

}

CSS Regresion Testing

.CSS-Testing {

}

CSS Regresion Testing

#SCBCN16

}

.CSS-Frameworks {

.CSS-Frameworks {

}

.CSS-Frameworks {

}



#Alias
alias pullAllDir='find . -type d -depth 1 -exec git --git-dir={}/.git --work-tree=$PWD/{} pull origin master \;'

}

.CSS-forDevelopers {

.CSS-forDevelopers {

}

preProcessors

.CSS-forDevelopers {

}

Sass


    /// Find the last simple selector in a selector
    @function _last-simple-selector($selector) {
        $parsed: selector-parse($selector);
    
        @if length($parsed) > 1 {
            @if $bem-throw-errors {
                @error '`#{$selector}` contains #{length($parsed)} selectors and the `_last-simple-selector()`function accepts only 1.';
            }
            @return false;
        }
    
        $last-simple-selector: nth(nth($parsed, 1), -1);
    
        @return $last-simple-selector;
    }

.CSS-forDevelopers {

}

Sass

.CSS-forDevelopers {

}

Sass

.CSS-forDevelopers {

}

PostCSS

    import postcss from "postcss"
    import replaceRuleSelector
      from "postcss-selector-matches/dist/replaceRuleSelector"
    
    const CUSTOM_SELECTOR_RE = /:--[\w-]+/g
    
    export default postcss.plugin("postcss-custom-selectors", function(options) {
      const {
        extensions,
        lineBreak,
        transformMatches,
      } = {
        extensions: {},
        lineBreak: true,
        transformMatches: true,
        ...options || {},
      }
    
      const transformMatchesOnRule = transformMatches
        ? (rule) => replaceRuleSelector(rule, {
          lineBreak,
        })
        : (rule) => rule.selector
    
      return function(css, result) {
        const toRemove = []
        const customSelectors = {}
    
        // first, read custom selectors
        css.walkAtRules(function(rule) {
          if (rule.name !== "custom-selector") {
            return
          }
    
          // @custom-selector = @custom-selector <extension-name> <selector>
          const params = rule.params.split(/\s/)
          const customName = params.shift()
          const customList = rule.params.replace(customName, "").trim()
          customSelectors[customName] = customList
    
          toRemove.push(rule)
        })
    
        // Add JS defined selectors
        Object.keys(extensions).forEach(function(extension) {
          customSelectors[extension] = extensions[extension]
        })
    
        // Convert those selectors to :matches()
        css.walkRules(function(rule) {
          if (rule.selector.indexOf(":--") > -1) {
            rule.selector = rule.selector.replace(
              CUSTOM_SELECTOR_RE,
              function(extensionName, matches, selector) {
    
                if (!customSelectors[extensionName]) {
                  result.warn(
                    "The selector '" + rule.selector + "' is undefined",
                    {node: rule}
                  )
    
                  return selector
                }
    
                return ":matches(" + customSelectors[extensionName] + ")"
              }
            )
    
            rule.selector = transformMatchesOnRule(rule)
          }
        })
    
        toRemove.forEach(function(rule) {
          rule.remove()
        })
    
      }
    })

}

.CSS-Knowledge {

.CSS-Knowledge {

}

  • Follow the CSS Working Group
  • Track upcoming browser implementations and official news
  • Researching interoperability and webcompat issues

What’s happening in CSS? (Rachel Andrew)

.CSS-Knowledge {

}

The authentic CSS Crafts[wo]man every day are reading...

.CSS-Knowledge {

}

More Knowledge...

}

.CSS-Tools {

.CSS-Tools {

}

Styleguide Generators

.CSS-Tools {

}

Styleguide Generators

    /*------------------------------------*\
    	$NOTIFICATIONS
    \*------------------------------------*/
    
    /*
    Notifications
    
    Contextual notifications for messages.
    
    The modifier classes are `.notification-error` for errors, `.notification-success` for success,  `.notification-system for information and `.notification-warning` for warnings.<br>
    Use class `.notification-dismissable` for notifications with close button.<br>
    Wrap in div with class `.notification-toast-fixed` to fix at top of the page, <a href="#{$sgp-notificationToast}" target="blank">#{$sgp-openPage}</a>
    
    Markup:
    <!-- Notification succes-->
      <div class="notification-success" role="alert">
        <div class="notification-body">
          <span class="notification-icon iconfont-Big-check"></span>
          <p>Lorem ipsum dolor sit amet,Lorem ipsum dolor sit amet,Lorem ipsum dolor sit amet, Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget. <a href="#" class="link-underline">Link underline</a></p>
          <button class="notification-close js-notification-close" type="button" aria-label="Close"><span aria-hidden="true" hidden>Close</span></button>
        </div>
      </div>
    <!-- /Notification success-->
    <div class="container-expanded">
    <!-- Notification error -->
    <div class="notification-error" role="alert">
      <div class="notification-body">
        <span class="notification-icon iconfont-Alert"></span>
        <p>Lorem ipsum dolor sit amet,Lorem ipsum dolor sit amet,Lorem ipsum dolor sit amet, Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget.</p>
        <button class="notification-close js-notification-close" type="button" aria-label="Close"><span aria-hidden="true" hidden>Close</span></button>
      </div>
    </div>
    <!-- /Notification error -->
    </div>
    <div class="container-expanded">
    <!-- Notification system -->
    <div class="notification-system" role="alert">
      <div class="notification-body">
        <p>Lorem ipsum dolor sit amet,Lorem ipsum dolor sit amet,Lorem ipsum dolor sit amet, Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget. <a href="#" class="link-underline">Link underline</a></p>
        <button class="notification-close js-notification-close" type="button" aria-label="Close"><span aria-hidden="true" hidden>Close</span></button>
      </div>
    </div>
    <!-- /Notification info -->
    </div>
    <div class="container-expanded">
    <!-- Notification warning -->
    <div class="notification-warning" role="alert">
      <div class="notification-body">
        <span class="notification-icon iconfont-Info"></span>
        <p>Lorem ipsum dolor sit amet,Lorem ipsum dolor sit amet,Lorem ipsum dolor sit amet, Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget. <a href="#" class="link-underline">Link underline</a></p>
        <button class="notification-close js-notification-close" type="button" aria-label="Close"><span aria-hidden="true" hidden>Close</span></button>
      </div>
      <div class="notification-footer">
        <button class="btn-small btn-default-alternative" type="button">Secondary alternative</button>
      </div>
    </div>
    <!-- /Notification warning -->
    </div>
    
    Styleguide #{$sgi-notifications}
    */
    
    $notifications: success $bamboo , system $outer-king, error $trueblood, warning $kiiro;
    
    @mixin notification-fixed {
      position: fixed;
      width: 100%;
      max-width: $container-width;
      margin: 0 auto;
    
      .inner & {
        margin-left: -10px;
        @include mediaquery ($bp-tablet) {
          margin-left: -20px;
        }
      }
    }
    
    @mixin notification {
      @include font-rendering;
      font-size: $base-font-size;
      line-height: $base-line-height;
      width: 100%;
      z-index: $zindex-sticky-content;
      overflow: hidden;
    }
    
    .notification {
    
      &-body {
        @include display-flex;
        @include align-items(flex-start);
        padding: $padding $padding 0 $padding;
    
        &:only-child {
          padding-bottom: $padding;
        }
    
        p {
          @include flex(1 1 100%);
          margin: 0;
        }
    
        a {
          white-space: nowrap;
        }
      }
    
      &-close {
        @include btn-close;
        @include flex(1 0 auto);
        color: inherit;
        margin-left: $padding/2;
      }
    
      &-icon {
        display: none;
    
        @include mediaquery($bp-tablet) {
          @include flex(1 0 auto);
          display: block;
          margin-right: 5px;
          color: inherit;
          &::before {
            color: inherit;
          }
        }
      }
    
      &-footer {
        padding: $padding/2 $padding $padding $padding;
        text-align: right;
    
      }
    
      @each $notification-type in $notifications {
        $key: nth($notification-type, 1);
        $value: nth($notification-type, 2);
    
        &-#{$key} {
          @include notification;
          background: $value;
          color: set-color-contrast($value);
    
          a,
          a:hover,
          a:focus {
            color: set-color-contrast($value);
          }
        }
      }
    
      &-toast,
      &-advise {
        position: relative;
        z-index: $zindex-notification;
        margin-top: -$padding/2;
    
        @include mediaquery ($bp-tablet) {
          margin-top: $padding/2;
        }
      }
    
      @at-root .notification-toast > [class*="notification-"] {
        @include close-animate;
        position: absolute;
        transition: height .5s;
    
        &.is-fixed {
          @include notification-fixed;
          top: 0;
        }
      }
    
      @at-root .notification-advice > [class*="notification-"] {
        border-top: 1px solid rgba(0, 0, 0, 0.4);
    
        &.is-fixed {
          @include notification-fixed;
          bottom: 0;
          transition: bottom .5s;
        }
    
        &.is-closed {
          @include close-fixed-bottom;
        }
      }
    
      @media print {
        display: none;
      }
    }

.CSS-Tools {

}

Linters

.CSS-Tools {

}

Critical-path

.CSS-Tools {

}

Forensic CSS

CSS Dig (Chrome Extension)

.CSS-Tools {

}

Forensic CSS

CSS Stats

.CSS-Tools {

}

Forensic CSS

CSS Stats | #scbcn17

.CSS-Tools {

}

Forensic CSS

CSS Coverage (DevTools)

.CSS-Tools {

}

}

.CSS-Craftsmanship {

Not only working css,

          but also well-crafted css

 

Not only responding to change,

          but also steadily adding value

 

Not only individuals and interactions,

          but also a community of professionals

 

Not only customer collaboration,

          but also productive partnerships

Enjoy CSS

}

.ThankYou { }

CSS Craftsmanship

By Joan León

CSS Craftsmanship

Slides de la charla CSS Craftsmanship en la conferencia Software Craftsmanship Barcelona 2017 http://scbcn.github.io/

  • 6,044