I detest looking at code or mark-up that I’ve written in the past, which I don’t understand right off the bat. I’m surely no different from you in that I want to be able to come back years later, pick the code up, and understand exactly what is going on. I don’t want to dissect the simplest concepts, where the brackets are located, or even how the mark-up is indented. I have created habits to help me with rapid development, which have kept my sanity somewhat intact. I will be honest though, I have never given much thought to how I write and organize my CSS until recently, and that is what I am sharing today.
Introduction: Why Bother?
There are plenty of ways to do what I am suggesting with CSS. Let me be the first to say, don’t use anything that I am writing about today if your comfort level is not high with my concepts. Instead, think about the concepts, and improve on the solutions I am writing about. Share your own insights. I won’t argue with you if you think there is a better way to organize style sheets, as in the end there is no right or wrong way. However, I believe the more structure you add, the better off you are in the end when working with CSS.
“How easy is it for us, as developers, to rapidly find, understand, repair or add-on to a given code base? The easier that task is, the better the internal usability.”
There are a couple of concepts that I want to cover now in general to get the brain juices working. First, there is a concentration on usability with web development. We want the users of our websites to find things quicker, navigate more naturally, and overall intrinsically understand the concepts of our applications. That’s a very worthy use of time and energy. What is sometimes forgotten is the internal usability in all of the planning and discussions for our projects. How easy is it for us as developers, to rapidly find, understand, repair or add-on to a given code base? The easier that task is, the better the internal usability. In my opinion, that concept is as worthy of our time and thought as the front end usability.
Second, remember there is a C in CSS. It’s the cascading part. The method I use might fly in the face of some conventional thoughts, but when you back yourself into a corner for only using a certain aspects of CSS, you lose out on the power. When I am planning a large project, I think of the id selectors as “explain the entity”, class selectors as “describe the entity” and style attributes as “override what I just said”. I cascade the properties down to lessen the code, and give a little method to the madness. Again, there are no right or wrong ways, but when you have no plan, you are setting yourself up for a lot of extra work, not to mention extra overhead.
Finally, remember there are always tradeoffs in development. The most elegant ways of doing things aren’t always the most efficient.
Sometimes, the most efficient ways of doing things cost you down the road when you have to pick the code back up for support.
No one can make these choices for you, but you need to consider the tradeoffs while you write. Sometimes you have to bite the bullet just a little bit, perhaps to add an additional HTTP request to make the end result internally usable. Other times, you need to add a good comment to remind yourself of the choice that you made, and move on.
A Couple of Choices: Frameworks or The Wild West
Chances are, you are using either a framework to handle your CSS or you are adding your styles in a manner that you have grown accustomed to, but without much of a structure. Both have there upsides and downsides. Let’s look at a few CSS frameworks first, from the horse’s mouths:
Blue Print
YUI 2
Baseline
YAML
There are a numerous more, and just like a frameworks for your server side language of choice, each have their advantages over one another, and each have their drawbacks. I am not here to steer you away from a framework, as I have used them in the past and I believe in the concepts. I think when you are working on a large team, there is no better choice as it standardizes your styles and it lessons the voice of the individual developer and designer. That said, I do believe there are some drawbacks from using a CSS framework, as it adds to the overhead particularly with styles you aren’t using, and the learning curve is rather high. This can be a bit frustrating particularly with projects that have strict schedules. That said, the learning curve is just that, a curve, and over time you will master whichever project you deem best. The advantage of using a framework is that you now have improved your internal usability, as you are using a set method paradigm, although that method is something that is most likely outside of your control.
Wild West
The other solution is what I call the “Wild West” where anything goes. I’ll be honest and say there are many times I have just pushed something out the door without much thought to the future, or in the case of a very small project where the CSS is not very substantial. The learning curve here isn’t so bad, because you are writing your CSS as you go. You have complete control over your style’s destiny. Pretty cool so far! The problem is the internal usability. Come back to that project after it is no longer fresh in your mind, and there will be some problems. “Why the heck did I write this like this” or “I have no idea what I meant by this comment” or “Why is that input not changing styles” or “what is this big chunk of chum controlling” are common responses after the style sheet is no longer fresh in your mind.
My Choice: The Hybrid Solution
If I could put the framework solution on a sliding scale with the wild west solution on the other end, I think I would prefer something just in the middle. While one bed is too hard, and the other bed is too soft, I want to find the bed that is just right. That’s what I call the hybrid solution. It shares traits with both the wild west and frameworks. On the one hand, I have control over my styles, and with that the learning curve is rather low. On the other, I want to give a little structure to what I write, so that when I come back to it later, I have at least a familiarity of the structure because I build onto my methods which each project.
It’s a bit of a DIY project like in home improvement. You are trading the structure and cost of a professional for the convenience and familiarity of using your own hands to do the work. What you hope for in the end is the same finished project, but one without the learning curve or foreign ideas and concepts from the industrial strength version.
File Naming Convention
Thinking back on the choices that we have to make as developers, I make the choice of increasing the HTTP requests for a little better organization. I know I am costing myself a little bit of performance but what I get in the end is CSS that is easier to understand when I have to look at them next. You may make a different choice here, and you won’t get much argument from me. I just prefer smaller file sizes organized in a consistent manner over the one large CSS file or header in my HTML.
Here’s what works for me:
-
reset.css : A reset css is one that sets all or at least of the majority of browser styles to nullify. I use a reset css so that I can battle some differences with browsers, and I see the value when dealing with cross browser issues. It’s not Nirvana, and there are some that prefer no reset, or what I recently read, a soft reset. I prefer to reset everything, and I use the Eric Meyer flavor of resets.
-
forms.css: I segregate my form styles from the rest of my CSS. I want to know when I am working on forms, and they aren’t quite appearing as I wish exactly where to go.
-
global.css: My global css file is something that I use for each larger project that I write. What is contained in this small file are small classes which I might use over and over again in projects. My rule of thumb is, if there is a shortcut for the property, then it probably doesn’t belong in the global file. I wouldn’t use the font property. For instance:
/* Colors */ .red { color: red; background: inherit; } .blue { color: blue; background: inherit; } .highlight { color: black; background: yellow; } /* Lists */ .horizontal { list-style-type: none; display: inline; } .vertical { list-style-type: none; display: block; } /* Text */ .small { font-size: small; } .large { font-size: large; } .bold { font-weight: bold; }
Notice that these are very specific classes, that add to the cascading rules of styles. While none generally will be used as the only style for an element, they add to the description of the element that they class is applied.
-
style.css: My style.css is my main controller of my style. If you think in terms of OO for CSS, my style.css is my class, while the other files extend my class (somewhat anyway) and add to the inheritance of my main objects. I use my style.css to import my other files, and to define my local, project only, id selectors and classes.
ID and Class Selectors: Think a Little Differently
My hybrid method diverges here from most people, as my general rule with ids is merely to explain the element in question. ID Selectors are only used once per page (including GET processes), so I want these to be very specific in nature. In order to really maximize the reuse of code, any property outside of that explanation of an element, I really would prefer to use a class selector. Since this ID is unique to the page, I only want to use unique explanations for this selector.
For instance, my width would be somewhat unique. My padding and margin would be somewhat unique. My position would be somewhat unique. You could argue that the display for this selector would be somewhat unique. My color for the element; not really unique. My background, again not really unique. For the not really unique items, I think of these as “describe the element” for which I use class selectors.
Let’s illustrate this with a little code. For ease, I am using a recent tutorial by Jeffrey Way titled Quick Tip: Practical CSS Shapes. What if we took the original CSS:
#container { background: #666; margin: auto; width: 500px; height: 700px; padding-top: 30px; font-family: helvetica, arial, sans-serif; } h1 { background: #e3e3e3; background: -moz-linear-gradient(top, #e3e3e3, #c8c8c8); background: -webkit-gradient(linear, left top, left bottom, from(#e3e3e3), to(#c8c8c8)); padding: 10px 20px; margin-left: -20px; margin-top: 0; position: relative; width: 70%; -moz-box-shadow: 1px 1px 3px #292929; -webkit-box-shadow: 1px 1px 3px #292929; box-shadow: 1px 1px 3px #292929; color: #454545; text-shadow: 0 1px 0 white; }
and transformed to this:
#container { margin: auto; width: 500px; height: 700px; padding-top: 30px; font-family: helvetica, arial, sans-serif; } #heading-one { padding: 10px 20px; margin-left: -20px; margin-top: 0; position: relative; width: 70%; } .norm-background { color: #fff; background: #666; } .heading-fancy { background: #e3e3e3; background: -moz-linear-gradient(top, #e3e3e3, #c8c8c8); background: -webkit-gradient(linear, left top, left bottom, from(#e3e3e3), to(#c8c8c8)); -moz-box-shadow: 1px 1px 3px #292929; -webkit-box-shadow: 1px 1px 3px #292929; color: #454545; text-shadow: 0 1px 0 white; }
So far, all I have really done is added two new classes from the unique h1 selector and abstracted that h1 out to a unique ID. I haven’t gained anything for the moment, and in actuality I have added just a whee bit more overhead to my file. Where’s the advantage then?
If you think for a moment that you might reuse these descriptions somewhere else, perhaps for a sub-heading, then we have some code reuse. Let’s look to see what we can do now. Here’s how it originally looks:
and here is how it looks with a sub-heading:
I only added a new definition now:
#heading-two { padding: 10px 20px; margin-left: -20px; margin-top: 0; position: relative; width: 30%; }
Along with a little HTML:
<h1 id="heading-one" class="heading-fancy"> My Heading <span class="arrow"></span> </h1> <h2 id="heading-two" class="heading-fancy small"> My Sub-Heading <span class="arrow"></span> </h2>
We have code reuse, and we have a method which is consistent. If you take this method and apply it, you will reduce the number of styles (or objects if you prefer) that you write. Less code with a method means easier support at a later date. Really, nothing earth shattering here, but when you begin to explain your ID selectors but describe your classes it’s an easy method to add a little sanity to your code.
Style Attributes
I’m sure someone, somewhere, has told you to never use the style attribute. I am also sure that some of you will disagree with me, and that’s OK, I can take it. I am going to break that rule just a bit with a caveat. Never use it without a little thought to what you are doing. There are legitimate uses for the style attribute, particularly when working with complex applications using AJAX calls, but those uses come from your behavior layer.
When you should use the style attribute, is when you need to make a quick final call to override something in the cascade display for the element which wouldn’t make sense to add to your global.css file. For instance, you might need to override a style from your behavior layer based on an user action. It does add to the complexity just a bit, but it adds to the cascade. I wouldn’t use multiple properties, as this is a quick override, or rather, “forget what I just told you, do this instead”. It’s a cascade, and you should treat your CSS as such, in my opinion.
Indentation, Layout and Comments
We spend a lot of time putting emphasis on our indentation in our code and HTML, but I don’t often see the same emphasis in our CSS. It makes the world of difference. Let’s take our working example again:
<div id="container" class="norm-background"> <h1 id="heading-one" class="heading-fancy"> My Heading <span class="arrow"></span> </h1> <h2 id="heading-two" class="heading-fancy small"> My Sub-Heading <span class="arrow"></span> </h2> </div>
If we indent that in our markup, why not indent it the same way in our CSS:
#container { margin: auto; width: 500px; height: 700px; padding-top: 30px; font-family: helvetica, arial, sans-serif; } #heading-one { padding: 10px 20px; margin-left: -20px; margin-top: 0; position: relative; width: 70%; } #heading-two { padding: 10px 20px; margin-left: -20px; margin-top: 0; position: relative; width: 30%; }
It adds just a little more emphasis as to what is going on with these ID selectors. I understand now that they are children to the container div without comparing my mark-up.
When deciding on the layout of your style file, this is the rule of thumb that I use. You have to @import your additional CSS files first starting with the reset.css file, and then the rest. Define your elements next such as h1, anchors, etc. Next, define your ID selectors in your style.css. If you are working with multiple pages, comment the start of each new page within your indentation. For instance, #container is probably an element of the layout which is the container for each page, so start there with your indentation and work out commenting where you are using each element. Finally, define your classes. I don’t normally indent my classes, due to the fact that they are often reused, and the indentation doesn’t show where they are used.
Finally, and probably most importantly, comment your CSS just as you would your server side code. If there is any context that you can give to a class, such as elements that it is used, or ID that it matches, comment it. Any context that you give your future self is like having a time machine. Marty McFly might not have knocked that creepy guy out of the way of oncoming traffic if he had just read the Flux Capacitor comments first.
Conclusion
I am relatively sure my methods will not have a new dance move named after it, nor will it cure cancer. I am not even sure if they would be adapted by a single person outside of my immediate family. That said, I really hope you take the concepts away from this and build methods that work for you. Development usability is a goal that we should all be striving to achieve. When you create a methodology, you increase your internal usability exponentially as you are developing habits which you reuse and share with your team and others. It fixes development problems, increases productivity, and decreases the overall cost of development. It is one of those rare win / win propositions that you encounter in your daily development life.
Thanks for reading, and please share your ideas.