Refactoring CSS - Programming Principles for Designers

A204ca511ddee820957e715d6d363548?s=47 John W. Long
October 14, 2014

Refactoring CSS - Programming Principles for Designers

From my presentation at CSS Dev Conf 2014.

Abstract:

Over the years as designers have transitioned from print to the web we've had a reluctant relationship with code. Pixel perfection is a demanding standard. It's required us to get close to the metal and learn HTML and CSS. Some of us have transitioned well and have actually grown to love our curly-braces and semicolons, but it wasn't what we trained for.

For programmers on the other hand, writing code and doing it well is the primary part of their job. And there's actually a lot that we can learn from them about writing good CSS.

In this talk, John will examine a number of programming principles and demonstrate how they apply within the context of CSS. Principles like:

* Keeping your code DRY (Don't repeat yourself)
* Abstracting common problems
* Choosing great names
* Creating a well structured project
* Being aware of common code smells
* Making your code more modular

You are certain to walk away with something to apply to your current project.

See also:
* http://bit.ly/css-for-grownups
* http://bit.ly/defensive-sass-sept-2013
* http://thesassway.com/modular-css

A204ca511ddee820957e715d6d363548?s=128

John W. Long

October 14, 2014
Tweet

Transcript

  1. 9.

    “It’s almost a challenge to find a development team that’s

    working on a codebase that’s more than a couple of years old where the CSS isn’t the most frightening and hated part of that system.” #refactorcss Andy Hume CSS for Grownups SXSW Interactive, 2012 bit.ly/css-for-grownups
  2. 15.

    Refactoring A disciplined approach to changing code to make it

    easy to understand and cheaper to modify in the future
 without changing its observed behavior. #refactorcss Based on Martin Fowler’s definition.
  3. 16.

    Goals of Refactoring • Clean maintainable code • Easy to

    understand • Composable parts • Reusable without modification • Parts behave the same in all contexts • Hard to break #refactorcss
  4. 19.
  5. 21.

    ul.menubar { background: white; @include box-shadow(rgba(black, 0.2) 0 1 list-style:

    none; font-size: 14px; padding: 0 10px; > li { display: inline-block; position: relative; > a { color: black; display: block; padding: 10px 14px; text-decoration: none; &:hover { background: #29a7f5; color: white; } } > ul { @include box-shadow(rgba(black, 0.5) 0 @include border-radius(3px); @include border-top-left-radius(0); display: none; position: absolute; <ul class="menubar"> <li> <a href="#">File</a> <ul> <li><a href="#">Open</a></li> <li><a href="#">Save</a></li> <li><a href="#">Save as...</a></li> <li><a href="#">Close</a></li> <li class="separator"></li> <li><a href="#">Exit</a></li> </ul> </li> ... </ul> bit.ly/menu-1 1 #refactorcss
  6. 22.

    <ul class="menubar"> <li> <a class="menubar-item" href="#">File</a> <ul class="menu" > <li><a

    class="menu-item" href="#">Open</a></li> <li><a class="menu-item" href="#">Save</a></li> <li><a class="menu-item" href="#">Save as...</a></li> <li><a class="menu-item" href="#">Close</a></li> <li class="menu-separator"></li> <li><a class="menu-item" href="#">Exit</a></li> </ul> </li> ... </ul> .menubar { background: white; @include box-shadow(rgba(black, 0.2) 0 1 list-style: none; font-size: 14px; padding: 0 10px; > li { display: inline-block; position: relative; } } .menubar-item { color: black; display: block; padding: 10px 14px; text-decoration: none; &:hover { background: #29a7f5; color: white; } } .menu { @include box-shadow(rgba(black, 0.5) 0 5 @include border-radius(3px); @include border-top-left-radius(0); 2 bit.ly/menu-2 #refactorcss
  7. 23.

    <ul class="menubar"> <li class="menubar-item" > <a class="menubar-item-target" href="#">File</a> <ul class="menu"

    > <li class="menu-item" ><a class="menu-item-target" href="#">Open</a></li> <li class="menu-item" ><a class="menu-item-target" href="#">Save</a></li> <li class="menu-item" ><a class="menu-item-target" href="#">Save as...</a></li> <li class="menu-item" ><a class="menu-item-target" href="#">Close</a></li> <li class="menu-separator"></li> <li class="menu-item" ><a class= "menu-item-target" href="#">Exit</a></li> </ul> </li> ... </ul> .menubar { background: white; @include box-shadow(rgba(black, 0.2) 0 1 list-style: none; font-size: 14px; padding: 0 10px; } .menubar-item { display: inline-block; position: relative; } .menubar-item-target { color: black; display: block; padding: 10px 14px; text-decoration: none; &:hover { background: #29a7f5; color: white; } } 3 bit.ly/menu-3 #refactorcss
  8. 27.

    1.Techniques for abstraction 2.Techniques for breaking up code 3.Techniques for

    improving names #refactorcss http://en.wikipedia.org/wiki/Code_refactoring Refactoring Categories
  9. 28.
  10. 29.

    • Decomposing objects • Assembling larger components from several objects

    • Extracting Mixins and Functions • Removing duplication (DRY) #refactorcss 2. Breaking up code
  11. 30.

    • Simplify a selector (Remove ID or Element selectors) •

    Renaming objects, mixins, functions, variables • Move into superclass • Move into subclass • Refactor comment to mixin #refactorcss 3. Improving names
  12. 32.

    #content form button, #sidebar button { border: none; border-radius: 5px;

    background: $green; box-shadow: $dark-green -4px 0 0 inset; color: white; font: 100 18px/1.5 sans-serif; padding: 8px 25px 11px; } #refactorcss .button { border: none; border-radius: 5px; background: $green; box-shadow: $dark-green -4px 0 0 inset; color: white; font: 100 18px/1.5 sans-serif; padding: 8px 25px 11px; } Renaming a selector
  13. 34.

    .button { border: none; border-radius: 5px; background: $green; box-shadow: $dark-green

    -4px 0 0 inset; color: white; font: 100 18px/1.5 sans-serif; padding: 8px 25px 11px; } #refactorcss .button { border: none; border-radius: 5px; background: $gray; box-shadow: $dark-gray -4px 0 0 inset; color: white; font: 100 18px/1.5 sans-serif; padding: 8px 25px 11px; } ! .primary-button { background: $green; box-shadow: $dark-green 0 -4px 0 0 inset } ! Extracting a subclass
  14. 36.

    .info { color: $white; background: $blue; padding: 20px; } .success

    { color: $white; background: $green; padding: 20px; } .failure { color: $white; background: $red; padding: 20px; } #refactorcss .message { color: $white; padding: 20px; } .info-message { background: $blue; } .success-message { background: $green; } .failure-message { background: $red; } Extracting a superclass
  15. 38.

    .info { color: $white; background: $blue; padding: 20px; } .success

    { color: $white; background: $green; padding: 20px; } .failure { color: $white; background: $red; padding: 20px; } #refactorcss %message { color: $white; padding: 20px; } .info { @extend %message; background: $blue; } .success { @extend %message; background: $green; } .failure { @extend %message; background: $red; } Extracting a placeholder superclass .info, .success, .failure { color: $white; padding: 20px; } .info { background: $blue; } .success { background: $green; } .failure { background: $red; }
  16. 40.

    button.next { border: none; border-radius: 5px; background: $gray; box-shadow: $dark-gray

    -4px 0 0 inset; color: white; font: 100 18px/1.5 sans-serif; padding: 8px 25px 11px; ! &:after { @include icon(next); } } #refactorcss .button { border: none; border-radius: 5px; background: $gray; box-shadow: $dark-gray -4px 0 0 inset; color: white; font: 100 18px/1.5 sans-serif; padding: 8px 25px 11px; } .right-arrow-icon { @include icon(next); } Decomposing objects
  17. 42.

    .video { padding: 10px; border: $border-color; margin: 10px 0; min-width:

    400px; ! // Crazy IE5-6 min-width hack * html & { width: expression( document.body.clientWidth < 400 ? 400px : "auto" ) ; } #refactorcss @mixin crazy-ie-min-width-hack($width) { * html & { width: unquote( 'expression(' + 'document.body.clientWidth < ' + ($width + 1) + ' ? ' + $width + 'px : "auto")' ); } } ! .video { min-width: 400px; @include crazy-ie-min-width-hack(400); } Refactor to comment
  18. 43.

    .button { border: none; background: black; color: white; padding: 15px

    8px; } #refactorcss .legacy .button { border: none; background: black; color: white; padding: 15px 8px; } Namespacing styles
  19. 44.

    .button { border: none; background: black; color: white; padding: 15px

    8px; } #refactorcss .legacy-button { border: none; background: black; color: white; padding: 15px 8px; } Prefixing styles
  20. 47.

    A disciplined approach to changing code to make it easy

    to understand and cheaper to modify in the future
 without changing its observed behavior. #refactorcss Refactoring Based on Martin Fowler’s definition.
  21. 48.

    1. Don’t try to refactor AND add functionality at the

    same time. #refactorcss Taken from the book, “The Pragmatic Programmer”
  22. 49.

    2. Make sure you have good tests BEFORE refactoring #refactorcss

    Taken from the book, “The Pragmatic Programmer”
  23. 50.

    3. Take short deliberate steps AND test after each step

    #refactorcss Taken from the book, “The Pragmatic Programmer”
  24. 53.

    1. Manual testing • Paging through your site by hand

    • Example pages or Styleguides 2. Automated Testing • Regression testing (Phantom CSS, Wraith, CSSert) • Linting (CSS Lint, SCSS Lint) • Coverage (CSS Coverage for Firefox) #refactorcss Tools for testing CSS Visit www.csste.st for more test tools
  25. 56.

    Questions? #refactorcss Books • “Refactoring: Ruby Edition” — Martin Fowler

    • “The Pragmatic Programmer” — Dave Thomas & Andy Hunt
 More on Modular CSS • thesassway.com/modular-css
 Twitter • @thesassway • @johnwlong