CSS Architectures #1: Principles of Code Cleanup and the New Best Practices
All too often, the CSS for major (and minor) websites is a textbook case of code bloat and redundancy, with lines of code that boast unnecessary use of qualifier elements, overly specific selectors from unnecessarily long selector chains, overdependence on descendent selectors when other selectors would be more appropriate, and the inappropriate or unnecessary use of !important.
[caption id="attachment_75979" align="alignnone" width="550"] Box-Models in Real Life Can Come Over Complicated, too (Source)[/caption]
We can all institute several basic, solid CSS writing practices to vastly improve the maintainability of any organization’s stylesheets. Ultimately, however, what we should really shoot for is structuring a given site’s stylesheets to dramatically increase scalability.
Our approach, then, is two-fold. First, we must put in place several essential practices for writing clean and efficient CSS. Second, we need to learn about and institute the central methodologies of the increasingly popular scalable CSS architectures to take our sites’ stylesheets to another level.
I’ll explore both of these topics throughout this article, but before we get into making code scalable, let’s do a bit of CSS cleanup, starting with some of my favorite tricks.
A Few Helpful Techniques
Learning workflow tricks from other developers is often really helpful. Here are a few of my personal favorites.Targeting Styles
It’s a good idea to have a method for targeting the styles on your page. If you aren’t using a tool like the Internet Explorer Developer Toolbar, Mozilla’s Firebug or Chrome Developer Tools, this old-school method of adding the property outline can help you see and work with the element that you desire more quickly: .searchform > .searchsubmit {
width: 14%;
height: 25px;
background: transparent url(images/icon_magnify.png) 0 0 no-repeat;
outline: 1px solid red
}
The rationale behind using this property and values is that outline does not add to the dimensions of the element like border does. Even the use of red (or any other color name) is significant. When coding, use only hexadecimal, rgb(a) or hsl(a) color codes. Then you know that when you see a color name, it’s there solely for the purpose of troubleshooting. Be aware that outline is not supported by IE8 and lower.
Adding Test Styles
Another good practice when testing and troubleshooting is to indent the new trial styles..searchform > .searchsubmit {
width: 14%;
height: 25px;
background: transparent url(images/icon_magnify.png) 0 0 no-repeat;
margin: -2px 0 0 0;
}
With the indentation, you know for sure that the style is temporary, and it’s easy to scan and find later. When you decide that the style should stay, indent it as you would the rest of the permanent styles.
Disabling Styles
With a good way to add new styles, here’s a way to quickly disable them : “X” them out by placing an x- in front of either the style selector or the style rule:.social a {
-moz-transition: opacity 0.3s ease 0s;
x-display: block;
height: 35px;
opacity: 0.4;
}
This method is quicker than commenting out the style. It’s also easy to scan and find, and you have the style in place if you decide later that you want to keep it.
CSS Cleanup and Optimization Guidelines
Now that we’ve got those tricks out of the way, let’s turn our focus to some rules of thumb for writing clean, optimized code—or for when you’re cleaning up someone else’s CSS spaghetti. We’ll go from the macro to the micro level, first exploring how to improve the readability and semantics of the HTML, and then moving on to ways to better organize and cut down on the number of style declarations.Macro-Optimize
It’s easy to get focused on the style declarations themselves, but before you create selectors, you have to make the HTML and the stylesheets themselves reader-friendly.Provide Stylesheet Information and Indicate Structure
With really large stylesheets, I’m a fan of using a table of contents. For developers new to a given stylesheet, knowing what the sections are or which names to jump to when they need to find a group of styles is incredibly helpful. At the basic level, I recommend inserting the developer’s information (name and so on) and the last updated date in the stylesheet. This way, if any questions come up about what’s in the document, the current developer knows who to ask./* stylesheet information for XyZ Corp
File created date: 09.15.2010
Last modified date: 06.04.2012
By: [name]
*/
Also, I recommend putting in a preliminary table of contents so that other developers have an idea of the structure of the document and the different sections for styles.
/* Table of Contents
- Link Styles
- Other sitewide styles
- Actions
- Layout
- LOGO
- TOP NAV
- NAVBAR
- SUBNAV
*/
…
(later in the document…)
/* =Layout */ (etc.)
Note that including the equals sign (=) before the section name of the stylesheet is deliberate—it acts as a flag and a way to search through the document more easily.
Annotate and Nest
Annotating and nesting markup helps you keep track of the beginning and end of elements that contain other elements, and this enables you to identify the pieces faster. Annotate divs and other major layout elements that begin with <!-- #id or .class name -->
by using the markup <!-- /end #id or .class name -->
or <!-- / #id or .class name -->
.
Nesting may seem like an unnecessary step, but it’s useful from a visual perspective and, by clearly indicating visual levels, also makes it easier to find problems like block-level elements inside inline elements, as well as the improper closing and reopening of elements, which can create major layout issues—culprits that validation often doesn’t help you find that easily.
You can see the difference in the following example:
Before:
<body>
<div id="pagewrap">
<div id="header">
<h1>Website Title</h1>
<ul id="navigation">
<li><a href="#">Home</a></li>
<li><a href="#">About</a></li>
<li><a href="#">Contact</a></li>
</ul>
<div id="contentwrap">
<div id="maincontent">
<h2>Main Content Title</h2>
<p>Main content, which is so much more important than the secondary content that it makes one teary with emotion.</p>
</div>
<div id="secondarycontent">
<h3>Sidebar Title</h3>
<p>Sidebar content, which is not as important as the primary content (which is why it is in the sidebar)</p>
</div>
<div id="footer">
<p>standard copyright and footer information</p>
</div>
</body>
After:
<body>
<div id="pagewrap">
<div id="header">
<h1>Website Title</h1>
<ul id="navigation">
<li><a href="#">Home</a></li>
<li><a href="#">About</a></li>
<li><a href="#">Contact</a></li>
</ul>
</div><!-- end #header -->
<div id="contentwrap">
<div id="maincontent">
<h2>Main Content Title</h2>
<p>Main content, which is so much more important than the secondary content that it makes one teary with emotion.</p>
</div><!-- end #maincontent -->
<div id="secondarycontent">
<h3>Sidebar Title</h3>
<p>Sidebar content, which is not as important as the primary content (which is why it is in the sidebar)</p>
</div><!-- end #secondarycontent -->
</div><!-- end #contentwrap -->
<div id="footer">
<p>standard copyright and footer information</p>
</div><!-- end #footer -->
</div><!-- end #pagewrap -->
</body>
You can find more information and tips for organizing your stylesheets in “Creating Effective Semantic Markup.”
Micro-Optimize
Micro-optimization cuts down file size, speeds up page load time and encourages best practices. Here are some ways you can improve your CSS on a micro level.Alphabetize the Rule Order
Putting your CSS declarations in alphabetical order is a great way to set the stage for clean code and fewer problems. Why? Because your style declarations will be that much easier to target and locate. Example One: .login {
margin-top: 5px;
line-height: 1.5em;
padding-left: 5px;
float: right;
list-style-type: none;
width: 80px;
font-weight: bold;
border-left: 1px solid #69824d;
}
Example Two:
.login {
border-left: 1px solid #69824d;
float: right;
font-weight: bold;
line-height: 1.5em;
list-style-type: none;
margin-top: 5px;
padding-left: 5px;
width: 80px;
}
Up the Efficiency for Speed
Long chains of elements for selectors force the browser to search unnecessarily through the page’s DOM to make a match. Eliminating element qualifiers and ditching descendent selectors in favor of more direct ones helps speed things up. Preoptimization:div#wrapper div#maincontent div#sidebar {
background: #fff url(bg.png) repeat-x 0 0;
border: 1px solid #ff0;
font: normal 1.33em/1.33 Georgia, serif;
margin: 10px 20px;
padding: .1em;
}
Postoptimization:
#sidebar {
background: #fff url(bg.png) repeat-x 0 0;
border: 1px solid #ff0;
font: normal 1.33em/1.33 Georgia, serif;
margin: 10px 20px;
padding: .1em;
}
Read more about this topic at “Optimizations for Improving Page Load Times.”
KISS: Keep It Simple and Short
Less is more when it comes to style declarations and selectors. For style declarations, follow these rules:- Use shorthand properties whenever possible (and remember these items when using shorthand: the shorthand property syntax; property value order, if any; the default values and required property values)
- Condense values and units
- Avoid duplicate properties whenever possible
#sidebar {
background-color: #fff;
background-image: (bg.png);
background-position: 0 0;
background-repeat: repeat-x;
border-width: 1px;
border-style: solid;
border-color: #ffff00;
font-family: Georgia, serif;
font-size: 1.33em;
line-height: 1.33em;
font-weight: normal;
margin: 10px 20px 10px 20px;
padding: .1em;
}
After:
#sidebar {
background: #fff url(bg.png) repeat-x 0 0;
border: 1px solid #ff0;
font: normal 1.33em/1.33 Georgia, serif;
margin: 10px 20px;
padding: .1em;
}
Condense the Code
Finally, removing multiple lines and indenting also helps keep your site efficient and speedy. Using multiple lines, nesting and indenting are recommended while developing a CSS, but once a site is ready to go live, minifying the CSS is the best route. A couple of good tools that condense CSS are CSS Compressor and CSS Drive.Tools Can Lend a Helping, Uh…Hand
Keeping these rules in mind while you’re coding helps prevent you from making gaffes that could cost you time and frustration later. But don’t think you have to do it all yourself, as some great tools are available that help with cleaning up your code. I think CleanCSS and Code Beautifier are worth checking out. Use these tools to clean up your code even further while you learn to integrate some of the approaches I’ve described.Improve Code with the Latest Best Practices
As you are well aware, the world of front-end development has evolved a lot over the past several years, as fresh minds have devised new approaches to solving age-old problems. Here are some of the latest best practices for front-end coding that will help your stylesheets and HTML considerably.Reset with Normalize.css
CSS resets help establish a baseline from which all the styles are set. A reset effectively overrides the browsers’ default styles for certain elements (which can vary greatly). Despite the popularity of CSS resets over the past several years, many sites still don’t employ them, and these sites’ CSS scalability is suffering greatly for it. Instead of using the extremely popular CSS Reset by Eric Meyer (because it is too far-reaching) or making up a DIY reset, many people recommend using normalize.css. Normalize.css “normalizes” the code to a common baseline rather than resetting the base styling for elements across all browsers. Referring to the normalize.css project on Github, these are its advantages over a CSS reset:- Preserves useful defaults, unlike many CSS resets
- Normalizes styles for a wide range of HTML elements
- Corrects bugs and common browser inconsistencies
- Improves usability with subtle improvements
- Explains what code does using detailed comments
Get a Clear Fix on Clearing Floats
If you are still rockin’ the method shown here to clear floats in your documents, then we really need to talk:<div class="clear"></div>
.clear { clear: both; }
Other clearing methods are recommended over this one, which is one of the first float-clearing methods devised when CSS layouts with floats first started to be implemented roughly 10 years ago.
The Micro Clearfix, used in the HTML5 Boilerplate, employs the most up-to-date, tried-and-true, front-end coding best practices. The Micro Clearfix supports Firefox 3.5 and later versions, Safari 4 and later, Chrome, Opera 9 and later, and Internet Explorer 6 and later. Here’s an example:
/* For modern browsers */
.cf:before,
.cf:after {
content:"";
display:table;
}
.cf:after {
clear:both;
}
/* For IE 6/7 (triggers hasLayout) */
.cf {
*zoom:1;
}
The clearfix .cf class should be added to all elements that contain floats. In such a case, the old-school empty divider element with clear applied (<div class="clear"></div>
) can be permanently retired from your repertoire.
What About Overflow: Hidden?
Another popular technique for clearing floats is to use overflow: hidden, although the Micro Clearfix is more highly recommended because there are sometimes issues with the overflow: hidden method in Internet Explorer 7 and earlier versions. Although the use of overflow:hidden was almost everyone’s favorite float-clearing technique for a while, it raised problems such as these:- Hiding content and child elements with no scrollbars when the browser window is smaller than the container.
- Interference with margins, borders, outlines and absolutely positioned PNGs.
- Application of CSS3 properties, such as box-shadow, text-shadow and transforms.
hasLayout
in Internet Explorer and block-level elements:
.container {
overflow: hidden; /* Clearfix! */
zoom: 1; /* Triggers "hasLayout" in IE */
display: block; /* Element must be a block to wrap around contents. Unnecessary if only
/* using on elements that are block-level by default. */
}
Dividers
Speaking of incorrectly wielding empty divs. . . you’ve got to stop rockin’ the empty cleared<div>
with a border assigned to it as a page divider as well:
<div class="divider"></div>
div.divider {
border-top: 1px solid #ABAA9A;
clear: both;
}
Yes, I know this code does a fine job as a clearing visual page divider, but it is not semantic. Nicole Sullivan, CSS ninja and creatrix of object-oriented CSS (OOCSS), suggests using the <hr> element to divide sections of the page and adding the necessary styling to it.
So instead of the preceding code, you would use this:
<hr class="divider">
.divider {
border-top: 1px solid #ABAA9A;
clear: both;
}
Image Replacement
Front-end development has a long and illustrious history of CSS techniques for replacing text with images. In March 2012, Jeffrey Zeldman introduced a new kid on the block, deemed the Kellum Method. Instead of hiding the text off screen using the -9999px hack (and creating a huge invisible box in the process), his technique hides the text while leaving it accessible to screen readers..hide-text {
text-indent: 100%;
white-space: nowrap;
overflow: hidden;
}
Performance is improved, notably on tablets and smaller screened devices.
Use an Icon Element
You might be using<span></span>
as the way to put icons in your pages, like so:
<li class="favorite">
<span class="icon favorite"></span><span id="favorite-insert-point" class="favorite"></span>
</li>
If so, try this on for size: icons can be employed with an icon element, leveraging the <i>
tag. This approach is becoming increasingly popular following its employment in Twitter Bootstrap.
<p><i class="icon icon-comment"></i>23 comments</p>
...
.icon { background-image: url( sprites.png ); }
.icon-comments { background-position: 0 -30px; }
The use of <i>
is a bit more semantic than using a standard <span>
tag, and makes it easier to identify where the icons are in your pages.
Get on the CSS3 Train
Often, sites use images for elements where it just isn’t necessary and become image-heavy. Using CSS3 helps tremendously with eliminating those images while getting the site prepped for moving to responsive design practices. For most sites, CSS3 is a boon for any instances of rounded corners (border-radius
), drop shadows (box-shadow
), text drop shadows (text-shadow
), gradients and box-sizing
.
However, there are two downsides to CSS3: first, many parts of the CSS3 specification are still in flux, so even modern browsers require vendor prefixes for most of the properties. Second, CSS3 is not even partially supported by popular older browsers, and thus requires fallbacks or helper scripts.
CSS3 Compatibility
Unfortunately, the older versions of Internet Explorer have the most compatibility issues with CSS3. Currently, CSS3 is only partially supported by Internet Explorer 9 (most notably, the CSS3 selectors; see HTML5 and CSS3 Support for an up-to-date list), and is completely unsupported by Internet Explorer 6 through 8. If you plan to use any CSS3 properties, I recommend having the proper fallbacks installed for the audience using Internet Explorer 9, 8, or earlier versions. Luckily, there are scripts that help this. Support of CSS3 in Internet Explorer is aided by the following:- Ie9. js . There is a great explanation of which properties are affected by IE9.js and what problems are fixed as well.
- Selectivizr
- CSS3 Pie
- CSS Sandpaper
- Modernizr
Tools for CSS3
An overview of CSS3 and which properties are safe to use now could be the subject of a separate article. One of the most important steps with regard to CSS3 is to stay up to date with the changes to the specifications and the browsers’ adoption of them. Keeping track of all this can be a bit of a pain, so I suggest using the sites at http://css3please.com/ and http://html5please.com to keep up to date with the latest in the syntax changes and support. Many great CSS3 generators are available. For almost all of the properties, CSS3, Please! is a fantastic resource. For gradients, Ultimate CSS Gradient Generator is a great tool for generating gradient code with the proper syntax and fallbacks. If you’re feeling particularly lazy and don’t want to have to remember how to write out all of the vendor prefixes, Prefixr will add them for you to your code.Institute a Grid
If your site is currently without an established grid, you must “hie thee hence” and institute one. If your current code boasts a large number of instances of width, margin, and padding, with inconsistent dimensions between elements that are supposed to be the same size, then your site is long overdue for a grid. You can construct your own using the dimensions of your elements, or you can employ a premade CSS grid framework (of which there are dozens, even responsive ones).Use Box-Sizing
If you’re making your own grid, one incredibly useful CSS property to employ is box-sizing. Box-sizing can change how the browser calculates the size of an element’s box, and it is a god-send for dealing with dimensions, especially for layouts and grids. Box-sizing calculates the dimension of an element’s box according to what was known as the “IE box model”—that is, the padding was considered in the size of the box. That means that when an element’s width and padding were declared together, the box would equal the amount of the width, and not the amount of the width plus the padding. Figure 1 illustrates this idea. Figure 1 Comparison of the W3C Box-Model with the Internet Explorer Box-Model Usingbox-sizing: border-box
(as opposed to box-sizing: content-box
, which is the default based on the W3C box model) could be a real boon in making the calculations for layouts that much easier. The property box-sizing
does require vendor prefixes.
Make the Grid and Images Fluid
The final aspect of planning to institute a grid (if you are thinking ahead to be future-friendly) is to make the switch from a fixed pixels grid to that of percentages (or ems). The best way to determine the percentages for sizes is to use Ethan Marcotte’s responsive Web design golden formula: target=content/context. Thankfully, there are calculators that can help determine the RWD numbers for the grid. I recommend RWD Calculator. Also critical to being future-friendly is to have images that adapt and move with the size of their container. The main way to establish this is a simple line of code:img {
max-width: 100%;
height: auto;
}
The images will now shrink or grow within the fluid container.
And Don’t Forget HTML5
Finally, HTML5 is definitely critical moving forward for all websites in general. It is no longer a question of whether a given site decides to implement it but a question of when. There are several aspects of HTML5 that I feel will be useful for anyone to employ at some point to lay the foundation for responsive design, but the easiest place to start is with the HTML5 doctype. The HTML5 doctype is a quick change that you can make to your page templates immediately as a precursor to moving to HTML5 tags and document restructuring.<!DOCTYPE html>
Nothing else in yours documents need to be changed because the doctype is backward compatible, but if any HTML5 tags are introduced, they will work.
Speaking of tags, another aspect of HTML5 to leverage is to employ some of the new tags, which help the page semantics while setting a good foundation for creating code modules. However, as with CSS3, backward browser compatibility is a serious consideration. To support the recognition of the new tags, scripts have to be used on the pages to enable older browsers to render the HTML5 elements correctly.
The most common script is HTML5 Shiv, which allows the HTML5 elements to be recognized by Internet Explorer 6 through 8. The only disadvantage is that there is yet another script to add to the page load. But really, there is no need to wait to use HTML5, so dive in!
Nice, Clean and Ready for Some Major Restructuring
That wasn’t so bad, was it? By cleaning up the code on the macro level by giving it the proper structure, and then zooming down to organize your code on the micro level, you can do a lot to improve heinous CSS. Further replacing outdated solutions with more efficient best practices helps considerably as well. So now that we have the preliminary clean up out of the way, we’re ready to get down to some serious CSS restructuring. A site’s stylesheets can be taken to the next level of maintainability and efficiency by instituting some of the methodologies of the increasingly popular scalable CSS architectures. Hang tight; you’ll get an overview of the top-four approaches in the next article in this series.Denise R. Jacobs is an expert in Web design and is an industry veteran with more than 14 years of experience. She is now doing what she likes best: being a speaker + author + Web design consultant + creativity evangelist. Most appreciated on Twitter as @denisejacobs for her “great resources,” Denise is the author of The CSS Detective Guide, the premier book on troubleshooting CSS code, and coauthor of Interact with Web Standards and Smashing Book #3: Redesign the Web. Her latest pet project is to encourage more people from underrepresented groups to Rawk the Web by becoming visible Web experts. You can reach her at [email protected] and see more at DeniseJacobs.com.
I’m all up for clean, tidy (and tiny) code. It’s nice to find even more ways to do it. Thanks!
Hey Denise,
This is a really great post.
For the last few months since I have started picking up CSS, I stumbled from one bad coding practice to another, often sabotaging my own project because of my bad coding practices, and I had to take a long time to correct these mistakes.
This post really hits the sweet spot.
Of all of these, I learnt about using x- infront to disable styles and to indent new trial styles. These opinions are extremely valuable and I’ll treasure them.
Thanks!
Hi Denise,
That really was a great article. I don’t think I can choose my favourite tip as there are so many good ones…I have no doubt my day off will now be spent going over my site implementing them. I’m not sure my wife will be so happy.
Thanks again,
Nick