http://bit.ly/cya-refactoring
Please fill out this short survey before we get started!
We just want to get an idea of where you're at before we begin. Nothing's required but any information you're willing to share helps us tailor this adventure to you!
[give about 5-10]
github.com/jina/refactoring
Choose your own Refactoring Adventure
A workshop at SassConf 2014
by Elyse Holladay & Jina Bolton
@elyseholladay
Dev/Designer, Instructor, MakerSquare
@jina
Senior Product Designer, Salesforce UX
“I always code perfectly the first time!”
—Some Liar
Clarity · Maintainability · Efficiency · DRY
We generally aim for a few standards in our code: clarity, maintainability, efficiency, and DRYness.
We want our CSS to be clear, easy to read, easy to maintain; efficient to debug and to write, and to be DRY. Refactoring should improve upon one of those goals, if not all of them at once.
For example: if your CSS (sass or not!) matches your markup too much, you want to remove or consolidate your nesting or chained classes: refactor. If it may be cleaner and easier to use placeholder extend for a class you aren't using in HTML: refactor. If you have a bunch of classnames that should be a group but aren't: refactor.
Clarity
Code should be clear, well-commented, and follow consistent rules. A developer new to the project should be able to understand it.
Maintainability
Code should be easy to update & maintain, not requiring hacks or over-specific styles. It should be clear where files and styles belong.
Efficiency
It should be easy for a developer to find where styles live, write new styles, fix bugs, or find documentation and instructions.
DRY
Don't repeat yourself! Code should be reusable, have efficient selectors, and not be overly repetitive or nested.
But what if
we didn’t write it perfectly the first time
lack of clarity
hard to maintain
new requirements
design or UI needs to change
duplication or bloat
code smells
So in the case we DON'T have those 4 things perfect, or in any of these other cases [read examples from slide], we refactor.
Refactoring
changes the structure of existing code without changing its behavior
Refactoring
supports the process of change
Refactoring
makes code easier to modify and maintain in the future
getting everyone on the same page
In many ways, refactoring is like exercise and eating a proper diet. Many of us know that we ought to exercise more and eat a more balanced diet. Some of us live in cultures that highly encourage this. Some of us can get by, for a while, without doing this, perhaps even without visible effects. We can always make excuses for not doing this. But, we are only fooling ourselves if we continue to ignore it. Some of us are motivated by near term benefits of exercise and eating a proper diet, such as high(er) energy levels, greater flexibility, higher self-esteem and other benefits. Nearly all of us know that these near term benefits are very real. Many - but not all - of us make at least sporadic efforts in these areas. Others, however, aren't sufficiently motivated to "do something" until they reach a crisis point.
Source: http://st-www.cs.illinois.edu/users/opdyke/wfo.990201.refac.html
Why we Don’t refactor
your team doesn’t understand how
long-term benefits aren’t worth immediate effort
overhead; you’re paid to write new features
it might break something
Why Sass helps with refactoring
Systems, not Pages
Jina (YEAH YOU!), in her Sass presentations, says "create systems, not pages." We used to do this—about page, home page, etc etc—but now as our apps and projects have gotten significantly more complex, that's a particularly bad plan.
How can you make a framework of code that is reusable and modular and separate from individual pages? Instead of "style the homepage", style the modules that are on the homepage.
Your code should be reusable in as many places as possible, which makes it more efficient to write and debug.
Sass helps you—or forces you—to do that. When you have the powerful tools of Sass available to you, instead of going to use the color picker to grab a shade of grey from your mockup, you know you can just write $grey. It allows you to write reusable code with very little effort.
separation of concerns
importing files, folder structure
variables
mixins and extends
nesting and namespacing
Make refactoring a regular part of your workflow.
“Sass is not a replacement for CSS, it’s more like having a CSS assistant who will help you write your code.”
— Tom Genoni
Tom Genoni wrote a blog post about switching to Sass, in which he says that the best way to learn Sass without getting the insane output is to not use the crazy functionality in Sass.
"Sass is not a replacement for CSS, it’s more like having a CSS assistant who will help you write your code. So when you’re ready to really put it to work I recommend occasional sanity checks on the resulting CSS to see if this “assistant” has created too much repeated code or if the selectors are getting too complicated. Refactoring your Sass will help keep your code clean and you’ll start learning how you can make the best use of it."
I personally think using variables and mixins for obvious things you will reuse (like css3, clearfix, etc) is helpful, but if you are unsure about some of the extend or nesting or functions, don't use them--keep an eye on your code. This is an authoring tool and it's supposed to make your life BETTER, not harder.
http://atomeye.com/sass-and-compass.html
Installation & Apps
Goal: Determine the best way to use Sass in your project.
The tools of using Sass—how to install it, what apps and options there are.
I have to use the command line!?
Yes, to install Sass you MAY have to install it via Rails in the command line. The really long and difficult command you have to write is as follows:
sass --watch /path/style.scss:/path/style.css
When to use terminal: small personal projects that don't require many other tasks done, if you want to learn and get comfortable in Terminal, to quickly compile one file and look at output. Knowing how to use this is a handy skill in your arsenal even if you don't use it as your primary compilation option.
CodeKit helpfully compiles your stylesheets for you into regular or minified CSS, expanded or collapsed, and has LiveReload. It also now does LiveReload in multiple browsers/devices, creates source maps, and easily allows you to add plugins like Foundation, Compass, via Bower. It also does other types of processing, like Haml or Coffeescript.
When to use CodeKit: if you prefer a GUI/apps, you want simple compilation AND livereload w/o using a tool like Grunt, you want to use/play with plugins without manual install.
More: http://css-tricks.com/codekit-2-0/, https://incident57.com/codekit/help.html#sass
Libsass is a compiler for Sass that does not rely on Ruby to generate the CSS. It’s blazingly fast. You have to compile it (in C), if you are using the original version. You can install and compile it yourself with the C compiler, but there are other ways to access libsass' speed.
10× speed improvement
2.5 seconds down to 0.2 seconds
This speed benchmark by Jo Liss http://www.solitr.com/blog/2014/01/css-preprocessor-benchmark/ tested Libsass as providing a massive (>10x) speed improvement over the original Sass compiled in Ruby, dropping processing time from 2.5 seconds to 0.2 seconds.
She says, "The speed of your CSS preprocessor is important for developer/designer ergonomics. The preprocessing time measured by this benchmark will typically incur as a delay every time you edit the stylesheet sources and hit reload in the browser. Delays below 0.2 to 0.5 seconds tend to be perceived by the human brain as near-instantaneous. The higher the delay, the higher the mental overhead."
So—we want to be able to use libsass, that's awesome. But I don't feel like trying to deal with a C compiler. Luckily...
Node-sass is a library that provides binding for Node.js to libsass.
This is great if you are using Node, or other JS apps.. or Grunt. Or the Foundation libsass option. They all use the nodesass bind to libsass to compile.
More: http://benfrain.com/lightning-fast-sass-compiling-with-libsass-node-sass-and-grunt-sass/
LIES!
And no.. libsass does not yet support Sass 3.3, so it does not support maps. This is probably the biggest complaint we hear about libsass. So if you use the Foundation libsass version, you can't use maps, or plugins like Susy that require Sass 3.3
On screen is a color-guide that Una Kravets made, and it's using the maps functionality to do so. When I try to copy this into my Foundation-with-libsass project, I get the following error:
More: http://unakravets.tumblr.com/post/67057158293/use-sass-3-3-maps-to-make-on-the-fly-color-guides, http://sassmeister.com/gist/7479693, https://github.com/ericam/susy/issues/285, http://benfrain.com/libsass-lightning-fast-sass-compiler-ready-prime-time/
Sooo... Grunt, Gulp, Broccoli, whatever it is nowadays! When I first started getting in to these, I'd ask what they did and people go, "Oh, they're task runners!" Which I think has become one of those non-answers. It's TRUE but I don't think particularly explanatory if you have never used them or don't know what a task being run might even mean.
Tasks are things like compiling sass, concat/minify js and css, run a local server, live reload, optimize images. Instead of using an app like CodeKit to do that, if we are writing a JS or Rails app, we can write JS to define these tasks, and run them in the Terminal.
If you are using Grunt or Gulp, and don't need Sass 3.3 features like maps, you can use the grunt-sass plugin—not to be confused with grunt-contrib-sass, the ruby version grunt plugin. grunt-sass compiles with libsass and should be very quick in comparison.
Source: http://24ways.org/2013/grunt-is-not-weird-and-hard/
➼ /examples/sample-grunt-config.json
➼ /examples/useful-grunt-plugins.md
In plain English: you write some JavaScript/JSON and define some tasks that need to be done. Here we make a task to compile sass and watch for changes, connect to a server and open it. Then, in Terminal, you can run those tasks with a command like "grunt server", and it would connect to a local server, open it in the browser for you, compile files and watch for changes and livereload...
If using Zurb Foundation, you can install and use the Sass version. This allows you to edit the settings and variables, rather than override their complex code. You can also pick and choose which parts of Foundation you want to import.
You install it with the Foundation command line interface, which uses npm and Bower.
Then you can choose one of two ways to create a project with Foundation: with Compass as the compiler (which is quite slow), and one with Grunt using the libsass compiler. Obviously the Compass one has Compass included, so you have their styles and mixins available to you automatically, but I prefer the Grunt and libsass version. I find it significantly faster. Neither of these came with livereload, though, or running a server, so you'd have to edit the own grunt file to include it. More on that and libsass later.
more: http://foundation.zurb.com/docs/sass.html
If you are prototyping, I love Foundation for this. I think it's valuable to use the Sass version, throw in your variables, colors, type, etc, and super-quickly have a sandbox where you can get a working wireframe up. I know a lot of companies that do this, whether its with Foundation, or like Happy Cog, using Compass and the Susy grid.
.scss
or .sass
?
Goal: Choose a syntax for your project.
Steps to switch to .scss
change all your .css
files to .scss
compile your code
Open your site in a browser
Sass has two syntaxes
* the language name! It’s not an acronym!
SCSS* or “Sassy CSS”
Looks just like CSS.
Every .css
file is a valid .scss
file.
.widget {
color: #fff; /* CSS works here */
background: $backgroundColor; /* but so do Sass variables */
margin: 20px;
padding: 20px;
}
* it's an acronym!
.scss is a much easier place to begin, though, since it's a lot more forgiving and accepts all regular CSS.
If you are switching from .css, or have a lot of devs/people on your project that are not as familiar with CSS, this is probably a good option. It can also be more convenient if you are pulling in lots of vendor or framework code.
.sass
syntax uses indentation rather than brackets to indicate nesting of selectors, and newlines rather than semicolons to separate properties.
.widget /* look ma, no brackets or semicolons! */
color: #fff
background: $backgroundColor
margin: 20px
padding: 20px
// you can use shorthand includes
=large-text // instead of @mixin large-text
font-size: 20px
color: #ff0000
h1
+large-text // instead of @include large-text
also highlightjs syntax highlighting totally doesnt work with sass syntax lulz
I personally like the .sass syntax; I find it forces me to be more cautious about nesting, and I love not typing brackets or semicolons.
It's a good choice for those familiar with things like HAML, or who like significant whitespace, or like me, are lazy. It's also less to type if you use the oldschool syntax. Instead of writing @mixin, you can use the character =; instead of writing @include, you can use the character +
Converting .(s)css
to .sass
/* SCSS using indentation as relationship */
.nav {
styles: go here;
}
.nav-item {generic: styles;} // indented under .nav but NOT nested
// .sass syntax uses indentation as nesting
.nav
styles: go here
.nav-item // now will output as .nav .nav-item
generic: styles // now are possibly not generic anymore
It can be difficult to switch from .scss to .sass if you use indentation in .scss to denote relationships. If you do that in .sass, it will be nested. You have to take the time when switching to make sure your code isn't all crazy nested (and therefore potentially broken).
in the above example, let's imagine that the .nav-item styles apply to .nav and also to .footer-nav; in the .sass syntax case that would no longer be true, and your styles would be broken.
Importing
Goal: Choose how to import and organize your code.
Create a manifest file.
application.scss
The first thing you can do is to import everything thru your compiled Sass file; create an application.scss/sass file and link to it from your app. If you're linking to multiple CSS files, import them from your manifest instead.
@import [framework or vendor css]
@import styles.scss
Maybe this is all you have right now—but you've created a manifest that you can add files to as you go.
break up existing files & import them
Break out related sections of code, e.g. errors/messages, buttons, icons, nav, etc.
Make a new file for each with a comment explaining what is in the file.
Keep files small and readable.
Here we are still aiming to have no (or at least very little) visual change on the site. By doing this we just want to group our files, NOT start changing our CSS, classnames, etc.
This isn't about creating modules, which may edit your output or HTML, or require HTML cleanup. This is just about taking your existing CSS and dumping it into smaller, grouped files. Keep it as simple as you can. A big part of refactoring is choosing small battles; if you try to do it all at once you will always give up.
import without altering existing CSS output order
This is something you just have to do manually and slowly. Presumably, in your CSS, you'll have sections. If you have a section, you can copy it wholesale into a new file and import it. If you import them in the same order as they were in the CSS file, you shouldn't have any errors. Obviously this is not foolproof!
As you create new modules later, you can write your code in ways that make it less fragile to output order (namespacing, etc).
Re/organize files & folders
If you already have imported files via a manifest, you may just need to reorganize or regroup them. Remember that you can group into as many folders as you need to make sense of your files. We'll talk more about folder org, architecture, and creating modules later.
Creating Variables
Goal: Create simple, new variables that don’t alter output.
Switching to variables
cmd(+opt)+F
in Sublime Text is your new BFF.
Color variables will make you more consistent both visually and in your CSS, and you'll never have to search for a hex color code in your CSS ever again.
Make a new file: variables.scss
Make a new variable: $white: #ffffff;
Search for all the #ffffff
, #fff
, #FFF
, white
, maybe even #f9f9f9
.
Replace them with $white
Now do the rest!
Now is a really good time to take a little inventory of the UI of your app. What _should_ be white but is actually a super light grey? Do you have two VERY similar colors of blue? Can you consolidate some of your colors as you go to make things more efficient?
Import variables.scss
into your manifest first.
Now you can import this file into your manifest; of course it has to go first. Now is a good time to do a visual runthrough and make sure you aren't seeing anything that doesn't work. Maybe your #f9f9f9 really did need to be that, and not white. Just check. This is harder on a larger project, but whether you're checking visually or in your codebase (e.g. did you make an element w/ the bg and color both $white) you should take the time. If you already have something like visual diff testing set up, that'd be another great way to test.
Use color operations for variations.
$dark-purple: darken($purple, 20%);
$light-purple: transparentize($purple, 20%);
Use Sass' built in color operations to make a light grey that is just a lighter version of our dark grey, rather than defining a new hex value. I'm also using transparentize to make an rgba color for transparent text, rather than defining another rgba color.
Sass has a ton of these: lighten, darken, saturate, desaturate, invert, complement, adjust hue, alpha (returns alpha value), opacify/transparentize (not kidding, real names- makes more or less opaque), even "change-color" to change any property of a color: red, green, blue values, hue, saturation, lightness, and alpha.
http://sass-lang.com/docs/yardoc/Sass/Script/Functions.html
Typography Variables
$font-headline: "Proxima Nova Bold", "Calibri", Arial, sans-serif;
$font-body: "Calluna", "Cambria", Georgia, sans-serif;
body {
font-family: $font-body
}
h1, h2, h3, h4, h5 {
font-family: $font-headline;
}
Here I've defined a headline font, a body font, and a "secondary" font, in case we ever wanted to use that. Like colors, this allows us to change everything in only one place.
So here I am pointing our body font to $fontBody, and our headlines to $fontHeadline. Note that it's possible to point the $fontBody variable or vice versa in your variable declarations, if you only wanted one font. I'd still define 2 variables, and use them appropriately: for an h2, I'd use $fontHeadline; if it was in the body or a paragraph declaration, I'd use $fontBody. Even though $fontBody points to $fontHeadline, let's imagine change it later. If you used $fontHeadline in the body declaration, and changed the $fontBody variable, your body font wouldn't change.
➼ /examples/alpha-font-sizing.scss
Harry Roberts of CSS Wizardry wrote an article called "Pragmatic, practical font sizing in CSS" and in it he came up with this greek lettering method of naming font sizes. Instead of ONLY defining your font sizes on h1, h2, h3, etc, we also define it on classes alpha, beta, etc. "So now .alpha can carry the style information of a h1 wherever you wish; it doesn’t depend on location or a type of element."
I took that one step further with Sass, and used the new placeholder extend functionality. Now I don't have to have classnames in my HTML, but I can extend them in my Sass, like this:
Just @extend %delta, and you'll get 18px, without having to put the classname in your HTML. Additionally, from the content in the typography.sass file, h4 is output, but %delta itself isn't. You could take that one step further and eliminate the h1-6 selectors and ONLY use the placeholders, if you wanted. This works really well for me at work, because in our complex app, we prefer to use unique classnames over HTML selectors, to eliminate cascade issues. For clarity, I also like to not have non-informational classnames in my HTML, like, .delta. If you are working on your own blog or something smaller, it probably isn't as necessary to either eliminate this much CSS output, or avoid the classnames, but whether or not you use placeholder or classes, this is still a very valuable organization technique.
You should be able to do this without really changing much of your output CSS. If you go through the places in your codebase that you have font-size declarations, the same as we did for color variables, and replace with @extend .delta (whether that's a class or placeholder), you'll get the exact same output. If you are adding line-height to your typography.scss file you might have to be a bit more careful. Now you also have consistency going forward.
Variable Abstraction
Goal: Clarify variable names, create themes, named media queries.
Say you need a variable for text color in your project. You could call it $text-color, or should you call it $color-text? How do you decide? Choosing one at random can contribute to a lack of structure as the number of variables in your project increases. As experience shows, we often forget exactly how we named variables for particular projects.
http://webdesign.tutsplus.com/articles/quick-tip-name-your-sass-variables-modularly--webdesign-13364
Shared Name First
// by shades... // better: by shared name
$blue; $blue;
$medium-blue; $blue-medium;
$dark-blue; $blue-dark;
$darkest-blue; $blue-darkest;
$light-blue; $blue-light;
$lightest-blue; $blue-pale;
A better way to name these variables would be to start with the generic word they all share in common: blue. Then we can get more specific from left to right:
This not only helps in recollection, but will allow a text editor (such as Sublime Text, Coda etc.) to easily suggest colors. This way you don't have to memorize exactly how you named your variables. Rather, you can start generically and get more specific as the text editor auto-suggests variable names. All you have to remember is you want a color of blue. So you begin typing $blue and you can get a list of all the different blues you've created!
Abstracted Variable Names
➼ /examples/abstracted-var-names.md
Creating Simple Themes
➼ /examples/simple-theming/
Using a consistent naming convention, we can create a colors (or vars) .scss file and put in our colors, typography, etc.
Then we can create theme files; a default, a dark, a light, etc, using the color vars against more abstracted var names like primary, secondary, button-bg, etc.
Named Media Queries
➼ /examples/named-media-queries.scss
Media queries in Sass behave the same as in CSS, except they can be nested inside a CSS rule.
"@media directives in Sass behave just like they do in plain CSS, with one extra capability: they can be nested in CSS rules. If a @media directive appears within a CSS rule, it will be bubbled up to the top level of the stylesheet, putting all the selectors on the way inside the rule. This makes it easy to add media-specific styles without having to repeat selectors or break the flow of the stylesheet."
This is a much nicer way to author mediaqueries; it makes it easy to see what styles are related to what MQ size, you never have to write the #s again, or go searching through 2 different files to debug styles.
Organize Files & Folders
Goal: Keep style, vendor, and helper code separate; make files easy to find and not cluttered.
config: settings, variables
themes, if you have any
helpers: mixins, JS state classes, CSS3
frameworks: foundation, bootstrap, grids
components: icons, buttons, page components like header/footer
modules/base: your semantic HTML - page content, not elements like buttons
IE or responsive if you keep it separate
vendor: third party libraries, JS
Configuration Files
A simple theme is a nice way to separate out colors, if you need it, but you can take it one step further and break things out into a config.
This config is then called into the app manifest; you can call different configs, or change it based on what's required for the project/theme.
This also helps with keeping functions/helpers out of style code
Then we have the ability to change out the theme we are using pretty much on the fly, by picking which file we import.
➼ moourl.com/junk
➼ moourl.com/junkvid
➼ /examples/architecture-examples/dale-sande.md
Dale Sande gave a great talk called Clean out your Sass junk drawer, and he goes way in depth on some ways to do this.
"While part of a team developing an enterprise CMS, our process was to decompose a site's UI to it's lowest common elements. From those elements we could then build modules and then finally assemble the view templates. Each step building on the previous. Although my stylesheet management techniques weren't perfect, my concept of UI abstraction was solid.
Working with a new team, sans a CMS, I went into the project with the same conceptual understanding, but the outcome was drastically different. The code became increasingly harder to reuse and making simple edits resulted in the reengineering of HTML as well as CSS. Post launch, I sat down and analyzed the code I wrote. I came to the realization that we were engineering our UI (CSS and HTML) from entirely the wrong perspective. We were approaching our development from the full page perspective. Engineering all our visual elements from the outside-in and scoped to a specific view.
I started thinking back to the processes I pioneered with the CMS. Patterns established in the framework dictated we start from the elemental perspective; type, colors, forms, basic UI chrome (borders, shadows, icons, etc) all coded first. Once those element styles were completed, it was a matter of applying the skin to the CMS modules. The modules then in-turn were used to assemble the view. It worked quickly and seamlessly. Building the UIs from the inside-out was clearly the solution."
His mantra is "code the element, create the module and assemble the layout."
Elemental partials is where we get to work. Here we write Sass rules that will create your UI foundational layer. _buttons.scss, _forms.scss, _global_design.scss, _reset.scss and _typography.scss all contain Sass rules that will process into CSS. While they will import other partials, mixins and silent placeholder rules, it is important to remember that these files are engineered only to output CSS.
Taking buttons as an example; between gradients, :hover and :active states, one could go a little mad over the complexities in styling. It is important to keep your Sass logic out of these files and focus purely on the rules that will produce CSS for your selector.
Keeping functional Sass separate from presentational Sass is important in order to maintain readability, search-ability and scaleability of your code. Patterns like placing mixins in the same file as presentational Sass leads to overly complex files to scan and opportunities for accidental pollution of your processed CSS.
Mina Markham’s Sassy Starter
➼ moourl.com/sassystarter
➼ /examples/architecture-examples/sassy-starter.md
Mina Markham wrote a GREAT starter toolkit based on Scalable and Modular Architecture for CSS SMACSS for Sass (SCSS) projects. Styles are broken down into the following groups: Base, Layout, Modules, States, Themes
If you are starting a project and want some guidance on organization, I think this is an awesome, super simple place to start. Unlike a framework that provides all this code for you, Mina's starter is just placeholder docs.. the files are created, but empty, ready for YOUR code!
Link: https://github.com/minamarkham/sassy-starter
Creating Modules
Goal: determine what modules your project has & how to group them
What modules do you have?
How do you determine in your old code what is the same and what is different?
Print your website out!
No but srsly. At Bazaarvoice we had 3 separate codebases, one for Reviews, one for AA, one for Stories. We wanted to consolidate the CSS, but it was too big of an undertaking to refactor all the HTML and UI components.
So what we did is we printed out every page/area of our software. Then we took them in groups and with colored pencils, boxed out what sections were the same.
All primary buttons got one color, secondary another. Common form elements got one; headers another. After that we boxed out larger page modules, like "comment" and "comment form" and larger than that, "comment area".
This helped us determine what our modules were. Even though we couldn't change our HTML, when we were writing our Sass (ok, LESS) templates, we could group all the relevant CSS classnames together in one declaration, rather than having multiple redundant files.
Namespacing Modules
Which need a parent to have a style change under (namespacing); WHERE they are and which should be the same.
&
parent selector
➼ /examples/parent-selector.scss
Some other tips for eliminating extra output—other than not matching your HTML in your Sass—are things like the parent selector, placeholder extend, and using them to namespace modules. Not only can this help eliminate extra output, but it can also make AUTHORING a lot easier.
In Sass, the ampersand (&) symbol is used to reference the parent selector in a nested rule.
The & can also be placed after a selector to reverse the nesting order
This comes in really handy for things like Modernizr
"Have you used Modernizr? What about the google web-font loader? At the very least you’ve used the trick from HTML5 Boilerplate to target versions of IE with some well-placed conditional comments? What do all of these have in common? They all dynamically, in one form or another, add classes to the root html class. In Modernizr’s case it tells you what features you can hook into within your CSS. In Google’s web-font loader it will update some classes in to tell us if and when our typefaces are loading or have loaded. This is where that ampersand has made things easier for me."
http://www.joeloliveira.com/2011/06/28/the-ampersand-a-killer-sass-feature/
State Classes
➼ /examples/state-classes.scss
I like SMACSS style state classes; you can use nesting and the ampersand to namespace them so you can use something like .is-active in a lot of different styles and locations.
Namespacing Modules
➼ /examples/simple-namespacing.scss
Nesting CAN be used to namespace modules, and it can be VERY helpful in this regard. But THINK about what you are namespacing.
Here's a simple example; you want the header nav colors to be different than the footer nav colors, but nothing else—margin, padding, etc, should all be the same.
So here, you style the nav that will all be the same...
And then you can namespace inside the header and footer
@include
duplicates CSS
use when you need to alter variables
@extend
comma-delineates selectors
reuse code with no extra output
@extend is an easy way for one selector to share the styles of another selector, without duplicating the lines of CSS in your output
%placeholder
%placeholder
extend takes this one step further, and eliminates the output for the original ruleset.
Sometimes you’ll write styles for a class that you only ever want to @extend, and never want to use directly in your HTML. For our box styles, if that's visual only and the class .box never appears in our HTML, why output it into our CSS if it will never get applied? If you use normal classes and use @extend for this, you end up creating a lot of extra CSS when the stylesheets are generated.
where do you put new modules?
It's okay to refactor your folder structure as your project grows.
Most of us don't start our projects with a fully fledged, totally built out folder and file structure. Start with what you know you need—and if that's no folders, fine. if it's a components folder for vars and helpers and a modules folder for your page stuff? fine. but as your project grows, don't be afraid to move stuff around.
You get bloated output when you write bad CSS, when you nest when you don't need to, or when you over-use mixins or extends that aren't necessary. Read your output! YOU as an author are responsible for the output of your code, the exact same way as you are when you write plain CSS.
Also, in terms of performance and reducing size to the browser, you'll do FAR more by reducing your JS and images than you will reducing your CSS selectors.
"As a general rule, your average stylesheet will increase by ~3k for every 100 lines of uncompressed code. The single ~700-line Sass-generated CSS file for this site — warts and all (i.e., repeated code blocks) — is ~22k uncompressed; minified and compressed: 4k. Even if I inadvertently added another 1300 lines of wasted code on top of this, bringing the file to 2000 lines, the minified and compressed version would still only be about 5k." http://atomeye.com/sass-and-compass.html
Steps to Refactor
Goal: take your modules and do the actual refactor work!
Our files are a bit easier to read now, but what's in those files may still be clunky and messy. We'll still be getting the bugs we were before, have classnames that need to be cleaned up, etc. So let's talk about refactoring that actually changes your CSS, and maybe even HTML.
Chris Eppstein, “Refactor My Stylesheets: The Digg.com Edition”
Chris Eppstein did a refactor of Digg's Feedback/voting stylesheet to see how they could benefit from Sass. This was in 2010—and he mentions a few features Sass didn't have then, like placeholder extend, that they do now that could improve on this even more.
We've taken his notes and process from that and expanded on it.
link
1. Extract partial
2. Find repeating patterns
3. Create/Extract Base Class/Extend
4. Apply/Remove Nesting
5. Edit HTML Classes
6. Apply Variables
7. Create Mixins
I hope it's obvious that these are general rules that you can apply to most projects or modules. These rules start from pure CSS and go thru turning it into Sass, but should apply to a Sass refactor, too, although you may skip or edit steps, or do things like pull in variables much sooner than you would if you were switching from CSS. Take these as guidelines!
1. Extract Partial
Find all the different places in your CSS that you have code for this module. Create a new `.scss` file—lets call it `[MODULENAME]-original.scss` and dump all that CSS into it. Import that from your manifest. Now check and make sure you didn't break anything! Sometimes import order can cause specificity problems, so it's worth taking some time to look at all the places you know this module exists on your site/app to see if it's still working. Yes, that's tedious, but it'll save you a lot of headache later.
2. Find Repeating Patterns
Repeating Patterns
selector duplication that implies inheritance relationship
repeating patterns relating to colors, typography, etc
complex nesting or selector chaining
Repeating Patterns
a CSS class that can function as a consistent base class
plain ol' duplicated CSS of any type
states (active, disabled, etc) that should be combined
IDs or classes for JavaScript that may also have styles
3. Create/Extract Base Class/Extend
First, extract a base class. Determine what a shared classname might be and copy over all the repeated styles that you might want all buttons to share.
For now we're going to add that base class to some/all of the places this module exists in our HTML. This is a test step, to make sure everything applies OK. We'll clean this up even more going forward.
If that's looking good, let's change our base class from a class to a placeholder extend.
If you have individual classes (for example, generic button base class versus unique button classes), apply the `@extend %[MODULE]` on all of them. Compile and check it out—should be exactly the same.
You can now add unique styles to each module that requires it—colors, backgrounds, icons text colors, etc, to each class so that they look the same as they did before.
4. Apply/Remove Nesting
Figure out what you can nest inside the parent `%MODULE`—or under each individual button class. For clickable elements, `:hover` and `:active` states should be pretty obvious.
For some modules, you may need to remove nesting—if you're editing Sass, perhaps things are nested in so far you want to refactor that out .
Use the & parent selector to nest, and don't forget you can do it three ways, depending on a) what output you want and b) what makes for the most understandable code
5. Edit HTML Classes
We have made a lot of good progress toward reusability and modularity, so even if the classes of the actual individual modules are all inconsistent, we have done a lot. But some good search-and-replace can get us to a modular setup that will help in the future, when we want to add even more of the same module.
Determine what naming convention works best for this module. Write out the naming convention and then create classes for it. Now edit the HTML of the buttons to use the new classes; make sure you make any other HTML edits that might be necessary while you're at it! Add the new classes into your CSS and you should have some much prettier code now.
6. Apply Variables
Now that we know our refactored classnames, how our `%extend` is working, and the unique styles are applied, let's do a pass to see what those unique styles—colors, backgrounds, icons, fonts, etc—actually are.
Your module may just use existing variables from `variables.scss` or your grid or what not.
It might also be worthwhile to create variables strictly for your module.
Now is a good time to fix up things like inconsistent background colors or hover colors, highlighting, borders, etc. Visual errors are much easier to fix up now, when you can automate how they change.
7. Create Mixins
In this—optional—step we're going to take all the redundant code in our unique classes and make a mixin to do the hard work for us. Some modules really benefit from this; in others, there's really no point. You have to determine for yourself if it's valuable to you.
If you're rewriting CSS properties for multiple unique versions of a module—such as color, background-color, borders or box-shadows, hover states, etc—you might want to make a mixin, so you can change all those styles in _one line_?
Results?
125 lines to 85 lines
In Chris' refactor—which again is from before placeholder extend—"85 lines of code... down from 125 lines of code and providing the exact same output... a 32% reduction!"
"But the biggest win is that adding a new kind of feedback requires only 1 or 2 points of edit instead of the 5-7 that would have been required before. This is, without a doubt, more maintainable...
Then he says,"Additionally, we fixed six bugs without trying." "the defect rate in this tested, in-production stylesheet is evidence of how hard it is for even great front-end developers to maintain semantic CSS."
"But the biggest win is that adding a new kind of feedback requires only 1 or 2 points of edit instead of the 5-7 that would have been required before. This is, without a doubt, more maintainable..."
— Chris Eppstein
1. Extract partial
2. Find repeating patterns
3. Create/Extract Base Class/Extend
4. Apply/Remove Nesting
5. Edit HTML Classes
6. Apply Variables
7. Create Mixins
Naming Conventions
Goal: Choose a naming convention that works for you.
Whatever you do, be consistent:
.section
, .section-item
, .section-item-thingy
Organizing Properties
alphabetical, by property type, camelcase vs underscore vs dashes
Living Style Guides
Goal: Keep your styles maintainable, consistent, & visible
Style Guides are all the rage
…and they have come a long way.
PDFs are a pain to maintain.
Online is easier to update.
Living on your app is better.
Automated is even better.
Design & Brand Standards
Front-end Development Standards
Keeping Style Guides Current & Useful
The key is
“Current & Useful”
Once the style guide is not up-to-date, it is no longer useful.
Sass + Style Guides = Awesome!
What if a color gets added?
You need to update the style guide, too.
Automated Style Guides
KSS
StyleDocco
Kalei
…etc.
These are pretty great for quickly getting docs up & running.
Manual Creation
gives you flexibility
…but you have to stay on top of it.
I like a hybrid approach.
Documentation & /* Commenting */
Goal: have a consistent comment style and use it!
Comment each file to explain what is in it
Comment every large section of CSS
Comment individual items that need clarification
Be consistent
Imagine the next person who inherits your codebase. Your comments should be a guide for them through your CSS. Especially with potentially confusing Sass variables and mixins, it's not enough to have a comment that says "This is a mixin for a CSS3 gradient with eighteen arguments". Better to also add instructions on how to use. If you have a style guide or wiki docs, reference that page/section as well!
inline comment documentation
keep it up to date when you change your code.
// Single-line JS-style comments don't need a closing tag,
// and they are hidden from your compiled output! This is
// great for inline documentation about the styles themselves
// and how they should be used, mentioning hacks, or TODOs.
/* CSS style comments can be multi-line with a closing tag
and they appear in your compiled output. This is great for
section documentation and headers/dividers! */
In Sass, the JS style single-line comments with the two slashes are hidden from your output, which is great, because you can do a ton of commenting without anything showing up.
However, there are occasions where you may WANT your comments to show up in your compiled CSS—recently I was trying to do this so that I could see where imported files began and ended in my output. Helpfully, the CSS style slash-asterisk comments DO show up in output! Handy!
Write instructions in comments.
➼ /examples/comment-instructions.scss
documentation/instructions
if you make or change a mixin or helper, explain it, write instructions
instructions for using mixins and extends—imagine a new developer on the project
Testing
Goal: Don’t be breaking shit.
DiffUX, Wraith, Huxley
Visual regression testing
https://github.com/diffux/diffux
https://github.com/BBC-News/wraith
https://github.com/facebook/huxley
Keep refactors small so they don’t break things
…or simply overwhelm you.
What’s right for my project?
how to tell what works for you
naming conventions - why one would work better than another FOR your project
organization of files/folders
using elements vs classnames, BEM, OOCSS, etc
using frameworks or not
Thank You!
@elyseholladay + @jina