In her Our Best Practices Are Killing Us presentation at An Event Apart in Minneapolis MN, Nicole Sullivan walked through common CSS best practices that have outlived their usefulness and what we can do instead to improve CSS performance and maintenance long term. Here's my notes from her talk:
Problems with CSS
- Performance is an important part of the Web experience, with poor performance people engage less, use the site less, etc. CSS on many sites is responsible for poor performance.
- Facebook had 706 CSS files, they declared the Facebook blue color 261 times, used 548 unique hex values for colors, had 6498 declarations of color. Salesforce.com had 3,669 padding declarations.
- You can use GREP, regular expressions to analyze CSS files to find matches like this.
- Looking at the Alexa top 1,000 sites revealed some interesting data. One site had 518 declarations of !important. One had 733 declared float elements. One had 889 font-size declarations. All this makes it hard for a new or existing developer to work with the CSS code. This is a Web-wide problem.
- Even though we think each project will be "different", our existing best practices mean these problems keep coming up.
- It's time to rethink our best practices and do things differently. CSS will allow us to do anything no matter how stupid. But just because we can doesn't mean we should.
Pixel Based Sites
- Myth: pixel based sites are bad. Why did we stop using pixels for layout? Internet Explorer 6 wouldn't allow fonts to be resized when specced in pixels. As a result, we had to use percentages and ems.
- Today browsers use page zoom and resize everything (pixels, ems, and percentages) on the page (IE 7+). So fonts declared in pixels can be resized.
- Nested percentages and ems are not predictable.
- Pixel based fonts can be resized on all modern browsers with page zoom. Check how many users are still on IE6.
- If you must use percentages/ems, only change font-size on the body and leaf nodes, nowhere in between.
- Myth: don't add any extra mark-up.
- A predictable box structure allows you to debug more easily. A module body plays an important role: Trapping margin collapse, Trapping floats, Creating a new formatting context.
- When you cross lines between elements solving different problems you have problems.
- Separation of concerns: process of separating a computer program into distinct features that overlap in functionality as little as possible.
- Solve one problem at a time (isolate into mark-up) but add mark-up judiciously. Don't go nuts with extra HTML but know that bugs can come up when you try to have modules do too much.
- Myth: more semantic the better.
- Class names and IDs are not read by search engines, accessibility devices, or users (except other developers). So let's make sure that our class names & IDs work for other developers.
- Very semantic class names can prevent re-use. More semantic is not always better.
- CSS can be too tightly coupled to content. Repeatable patterns are likely better for CSS maintenance and performance. DRY: don't repeat yourself.
- Find common elements and presentation, and abstract them out into separate code. Look at what things are known and common amongst a set of modules and what differs.
- A new formatting context says "I'm a box, nothing comes out of me." This is very useful for managing floats and varying content.
- Facebook reduced file size by finding a common abstraction for all the items in their news feed: cut average CSS bytes per page by 19% (after gzip) and HTML bytes per page by 44% (before gzip).
- This is great for performance but the savings in work and maintenance can be more important. Repetition, Duplication, and Legacy Code make it really hard to work on Web sites. It can snowball out of control.
- Find a middle ground with abstracted styles and semantic enhancements where they are applicable.
- Choose good semantic elements: headings, lists, paragraphs
- The CSS shouldn’t be tightly coupled with the display or with the content.
- Myth: Some people believe IDs are better than classes but they can be overly specific but specificity is much more dangerous for duplication than extra classes.
- Specificity can be limiting for re-use. When we use descendent selectors, specificity can get complex quickly. Specificity grows over time and it becomes difficult to know which rules will take precedence.
- The order of classes does not guarantee which one will be applied first. The last property value pair in a CSS declaration is the one that applies. The order of style sheets also matters. The last style sheet wins.
- CSS inheritance: properties are inherited by child elements. For example, paragraphs inherit the font-size of the body.
- IDs win over classes. Inline styles win over external style sheets. !important wins even over inline styles.
- A hostile work environment can develop when it's too difficult to tell which styles will take precedence. The only way you can code is with Firebug and eventually it becomes impossible to get the look and feel you want.
- We want semantically styled elements but styled the way we need.
- Separate visual semantics from element semantics.
- Classes are far more flexible & reusable
- Keep specificity low: avoid ID, inline and !important when styling elements.
- Avoid the descendent selector
- Add classes to the element you wish to change rather than a parent node.
- Great developers can create great things is we move our worst best practices out of the way. CSS is fine but we've been trying too hard to follow practices that lead us into painful maintenance situations and overly complex code.