Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Refactoring CSS - Programming Principles for Designers

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

John W. Long

October 14, 2014
Tweet

More Decks by John W. Long

Other Decks in Design

Transcript

  1. “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. 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. 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. 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
  5. <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
  6. <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
  7. 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
  8. • Decomposing objects • Assembling larger components from several objects

    • Extracting Mixins and Functions • Removing duplication (DRY) #refactorcss 2. Breaking up code
  9. • 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
  10. #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
  11. .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
  12. .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
  13. .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; }
  14. 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
  15. .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
  16. .button { border: none; background: black; color: white; padding: 15px

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

    8px; } #refactorcss .legacy-button { border: none; background: black; color: white; padding: 15px 8px; } Prefixing styles
  18. 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.
  19. 1. Don’t try to refactor AND add functionality at the

    same time. #refactorcss Taken from the book, “The Pragmatic Programmer”
  20. 2. Make sure you have good tests BEFORE refactoring #refactorcss

    Taken from the book, “The Pragmatic Programmer”
  21. 3. Take short deliberate steps AND test after each step

    #refactorcss Taken from the book, “The Pragmatic Programmer”
  22. 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
  23. 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