I have been heavily relying on CSS for a website that I am working on. Right now, all the CSS styles are being applied on a per tag basis, and so now I am trying to move it to more of an external styling to help with any future changes.
But now the problem is that I have noticed I am getting a "CSS Explosion". It is becoming difficult for me to decide how to best organize and abstract data within the CSS file.
I am using a large number of div
tags within the website, moving from a heavily table-based website. So I'm getting a lot of CSS selectors that look like this:
div.title {
background-color: blue;
color: white;
text-align: center;
}
div.footer {
/* Styles Here */
}
div.body {
/* Styles Here */
}
/* And many more */
It's not too bad yet, but as I am a beginner, I was wondering if recommendations could be made on how best to organize the various parts of a CSS file. I don't want to have a separate CSS attribute for every element on my website, and I always want the CSS file to be fairly intuitive and easy to read.
My ultimate goal is to make it easy to use the CSS files and demonstrate their power to increase the speed of web development. This way, other individuals that may work on this site in the future will also get into the practice of using good coding practices, rather than having to pick it up the way I did.
This is a very good question. Everywhere I look, CSS files tend to get out of control after a while - especially, but not only, when working in a team.
The following are the rules I am myself trying to adhere to (not that I always manage to.)
Refactor early, refactor often. Frequently clean up CSS files, fuse together multiple definitions of the same class. Remove obsolete definitions immediately.
When adding CSS during fixing bugs, leave a comment as to what the change does ("This is to make sure the box is left aligned in IE < 7")
Avoid redundancies, e.g. defining the same thing in
.classname
and.classname:hover
.Use comments
/** Head **/
to build a clear structure.Use a prettifier tool that helps maintain a constant style. I use Polystyle, with which I'm quite happy (costs $15 but is money well spent). I'm sure there are free ones around as well (Update: like for example Code Beautifier based on CSS Tidy, an open-source tool I've not used myself yet but looks very interesting.)
Build sensible classes. See below for a few notes on this.
Use semantics, avoid DIV soup - use
<ul>
s for menus, for example.Define everything on as low a level as possible (e.g. a default font family, colour and size in the
body
) and useinherit
where possibleIf you have very complex CSS, maybe a CSS pre-compiler helps. I'm planning to look into xCSS for the very same reason soon. There are several others around.
If working in a team, highlight the necessity of quality and standards for CSS files as well. Everybody's big on coding standards in their programming language(s), but there is little awareness that this is necessary for CSS too.
If working in a team, do consider using Version Control. It makes things that much easier to track, and editing conflicts that much easier to solve. It's really worth it, even if you're "just" into HTML and CSS.
Do not work with
!important
. Not only because IE =< 7 can't deal with it. In a complex structure, the use of !important is often tempting to change a behaviour whose source can't be found, but it's poison for long-term maintenance.Building sensible classes
This is how I like to build sensible classes.
I apply global settings first:
Then, I identify the main sections of the page's layout - e.g. the top area, the menu, the content, and the footer. If I wrote good markup, these areas will be identical with the HTML structure.
Then, I start building CSS classes, specifying as much ancestry as possible and sensible, and grouping related classes as closely as possible.
Think of the whole CSS structure as a tree with increasingly specific definitions the further away from the root you are. You want to keep the number of classes as low as possible, and you want to repeat yourself as seldom as possible.
For example, let's say you have three levels of navigational menus. These three menus look different, but they also share certain characteristics. For example, they are all
<ul>
, they all have the same font size, and the items are all next to each other (as opposed to the default rendering of anul
). Also, none of the menus has any bullet points (list-style-type
).First, define the common characteristics into a class named
menu
:then, define the specific characteristics of each of the three menus. Level 1 is 40 pixels tall; levels 2 and 3 20 pixels.
Note: you could also use multiple classes for this but Internet Explorer 6 has problems with multiple classes, so this example uses
id
s.The markup for the menu will look like this:
If you have semantically similar elements on the page - like these three menus - try to work out the commonalities first and put them into a class; then, work out the specific properties and apply them to classes or, if you have to support Internet Explorer 6, ID's.
Miscellaneous HTML tips
If possible, give every page's body a unique class:
<body class='contactpage'>
this makes it very easy to add page-specific tweaks to the style sheet:When building menus automatically, add as much CSS context as possible to allow extensive styling later. For example:
This way, every menu item can be accessed for styling according to its semantic context: Whether it's the first or last item in the list; Whether it's the currently active item; and by number.
The core principles for sensible CSS, extracted from CSS Refactoring: From append-only to modular CSS
My answer is high-level to address the high-level concerns you've raised in your question. There may be low-level organizational tricks and tweak you can do to make it prettier, but none of those can fix methodological deficiencies. There are several things that affect CSS explosion. Obviously the overall complexity of the site, but also things like naming semantics, CSS performance, CSS file organization, and testability/acceptability.
You seem to be on the right path with naming semantics, but it can be taken a step further. Sections of HTML that appear repeatedly on the site without structural modification (known as "modules") can be considered selector roots, and from there you can scope the internal layout relative to that root. This is the basic tenet of object-oriented CSS, and you can read/watch more about it in this talk by a Yahoo engineer.
It's important to note that this clean approach can run opposite of the concern of performance, which favors short selectors based either on id or tag name. Finding that balance is up to you, but unless you have a massive site, this should just be a guide in the back of your head reminding you to keep your selectors short. More about performance here.
Lastly, are you going to have a single CSS file for your entire site, or multiple files (a single base file used with per-page or -section files)? The single file is better for performance, but might be harder to understand/maintain with multiple team members, and might be harder to test. For testing, I recommend you have a single CSS-test page that includes every supported CSS module to test collisions and unintended cascading.
Alternatively you can have a multiple file approach, to scope the CSS rules to a page or a section. This requires the browser to download multiple files which is a performance issue. You can use server-side programming to specify and aggregate (and minify) the CSS files into a single file dynamically. But since these files are separate and the testing for them would be separate, you introduce the possibility of inconsistent look and feel across pages/sections. Thus testing becomes harder.
It's up to you to analyze the customer's specific needs, balance these concerns accordingly.
Don't write headings in CSS
Just split sections into files. Any CSS comments, should be just that, comments.
Use a script to combine them into one; if necessary. You can even have a nice directory structure as well, and just have your script recursively scan for
.css
files.If you must write headings, have a TOC at the start of the file
The headings in the TOC should be perfectly equal to headings you write later. It's a pain to search for headings. To add to the problem, how exactly is anyone suppose to know you have another header after your first header? ps. don't add doc-like * (star) at the start of each line when writing TOCs, it just makes it more annoying to select the text.
Write comments with or within the rules, not outside the block
First off, when you edit the script there is a 50/50 chance you'll pay attention to what is outside the rule block (particularly if it's a big glob of text ;) ). Secondly there is (almost) no case where you would need a "comment" outside. If it is outside, it is 99% of the time a title, so keep it like that.
Split the page into components
Components should have
position:relative
, nopadding
and nomargin
, most of the time. This simplifies % rules a lot, as well as allowing for much simplerabsolute:position
'ing of elements, since if there's a absolute positioned container the absolute positioned element will use the container when computingtop
,right
,bottom
,left
properties.Most DIVs in a HTML5 document are usually a component.
A component is also something that can be considered a independent unit on the page. In laymen's terms treat something like a component if it makes sense to treat something like a blackbox.
Going with the QA page example again:
By splitting the page into components, you split your work into manageable units.
Put rules with a cumulative effect on the same line.
For example
border
,margin
andpadding
(but notoutline
) all add to the dimensions and size of the element you are styling.If they are just not that readable on one line, at least put them in close proximity:
Use shorthand when possible:
Never repeat a selector
If you have more instances of the same selector, there's a good chance you'll inevitable end up with multiple instances of the same rules. For example:
Avoid using TAGs as selectors, when you can use id/classes
First off the DIV and SPAN tags are the exception: you should never use them, ever! ;) Only use them to attach a class/id.
This...
Should be written like this:
Because the extra dangling DIVs there add nothing to the selector. They also force a unnecessary tag-rule. If you were to change, for example,
.answer
from adiv
to aarticle
your style would break.Or if you prefer more clarity:
The reason being the
border-collapse
property is a special property that only makes sense when applied to atable
. If.statistics
is not atable
it should not apply.Generic rules are evil!
They don't save you time, they make your head explode; as well as make maintenance a nightmare. When you're writing the rule, you may know where they apply, however that has no guarantee your rule won't mess with you later on.
To add to this generic rules are confusing and hard to read, even if you have some idea of the document you're styling. This is not to say you shouldn't write generic rules, just don't use them unless you truly intend for them to be generic, and even them add as much scope information into the selector as you can.
Stuff like this...
...has the same problem as using global variables in a programing language. You need to give them scope!
Basically that reads as:
I like using IDs whenever a component I know is a singleton on a page; your needs may be different.
Note: Ideally, you should write just enough. Mentioning more components in the selector however is the more forgiving mistake, compared to mentioning less components.
Lets assume you have a
pagination
component. You use it in many places across your site. This would be a good example of when you would be writing a generic rule. Lets say youdisplay:block
the individual page number links and give them a dark gray background. For them to be visible you have to have rules like this:Now lets say you use your pagination for a list of answers, you may encounter something like this
This will make your white links black, which you don't want.
The incorrect way to fix it is:
The correct way to fix it is:
Complex "logic" comments don't work :)
If you write something like: "this value is dependent on blah-blah combined with height of blah-blah", it's just inevitable you'll make a mistake and it will all fall down like a house of cards.
Keep your comments simple; if you need "logical operations" consider one of those CSS templating languages like SASS or LESS.
How do you do I write a color pallet?
Leave this for the end. Have a file for your entire color pallet. With out this file your style should still have some usable color-pallet in the rules. Your color pallet should overwrite. You chain selectors using a very high level parent component (eg.
#page
) and then write your style as a self sufficient rule block. It can be just color or something more.eg.
The idea is simple, your color pallet is a stylesheet independent of the base style, which you cascade into.
Less names, requires less memory, making the code easier to read
Using fewer names is better. Ideally use very simple (and short!) words: text, body, header.
I also find combination of simple words is easier to understand then having a soup of long "appropriate" words: postbody, posthead, userinfo, etc.
Keep the vocabulary small, this way even if some stranger coming in to read your style-soup (like yourself after a few weeks ;)) only needs to understand where words are used rather where every selector is used. For example I use
.this
whenever a element is supposedly "the selected item" or "the current item", etc.Clean up after yourself
Writing CSS is like eating, sometimes you leave a mess behind. Make sure you clean up that mess, or the garbage code will just pile up. Remove classes/ids you don't use. Remove CSS rules you don't use. Make sure everything is nice a tight and you don't have conflicting or duplicated rules.
If you, as I suggested, treated some containers as black-boxes (components) in your style, used those components in your selectors, and kept everything in one dedicated file (or properly split a file with a TOC and headers), then your work is substantially easier...
You can use a tool such as the firefox extension Dust-Me Selectors (tip: point it to your sitemap.xml) to help you find some of the junk hidden in your css nukes and carnies.
Keep a
unsorted.css
fileSay you are styling a QA site, and you already have a stylesheet for the "answers page", which we will call
answers.css
. If you now need to add a lot of new css, add it to theunsorted.css
stylesheet then refactor into youranswers.css
stylesheet.Several reasons for this:
A lot of times I will see individuals break the file out into sections, with a heading comment between sections.
Something like
It works pretty well and can make it easy to go back later and find what you are working on.
Here are just 4 examples:
On all 4 my answer has included the advice to download and read Natalie Downe's PDF CSS Systems. (The PDF includes tons of notes not in the slides, so read the PDF!). Take note of her suggestions for organization.
EDIT (2014/02/05) four years later, I'd say: