Taking CSS beyond a simple style library
Summary
CSS based design is really all about your HTML structure. We'll look at bad examples, then good examples. Finally, I'll point out some resources for generating stylable HTML in ASP.NET.
Ugly HTML, bad CSS
A lot of web developers haven't really gotten the point of CSS, so they're not getting the full benefit. They see CSS as a kind of global style constants file, in the same way they'd pack all their string constants into a resource or config file. Need a bold blue heading? Yep, I think I've got one of them... There it is:
.BigBlueText
{ color: #99f; font-size: 16px; }
No... that's not big enough. Time for BiggerBlueText!
.BiggerBlueText
{ color: #99f; font-size: 22px; }
The HTML reflects this mentality: ID's and Classes are assigned as necessary to apply the styles. There's often no rhyme or reason to them other than to map the styles to the HTML elements. Unfortunately, that completely misses the point. Although it's unfortunate that you aren't getting the maximum value out of CSS based styling, but the real crime is that those who want to restyle your work in the future don't have the hooks they need.
A classic example of that kind of unstylable HTML (impervious to CSS) is that returned by SQL Server Reporting Services. I've made some attempts to style SSRS and make it work cross-browser, but there are major limits to what can be done. Often parent elements have no class names assigned; other times class names are assigned but are re-used based on style. That makes it impossible to change the style of the class without destroying the entire page. Here's a short snippet (by far not the worst!) to show you what I mean - notice that the class "msrs-normal" has nothing to do with structure or content; it's only included to simplify styling the page.
<td valign="top" width="50%"><table width="100%" class="msrs-normal" cellpadding="0" cellspacing="0"> <tr> <td valign="top" width="50%"><table width="100%" class="msrs-normal" cellpadding="0" cellspacing="2"> <tr> <td valign="top" width="18px"> <a href="..."> <img src="..." height="16" width="16" alt="Report" border="0" /> </a> </td> <td valign="top"><a href="..." id="ui_a0">...</a></td> </tr> <tr> <td valign="top"><img src="..." height="2" width="1" border="0" /></td> </tr> </table> </td> </tr> <tr> <td valign="top" width="50%"><table width="100%" class="msrs-normal" cellpadding="0" cellspacing="2">
Once we talk about how this SHOULD work, the problem with doing it wrong will be more obvious.
Stylable pages don't mean you have to go nuts with classes
You might think that really stylable HTML needs classes all over the place. That's not true, thanks to descendant selectors, which let you target elements inside a parent element. For instance, descendant selectors will let you style all <a> elements which appear inside a <div> with and id of "nav":
div#nav a { font-weight:bold; }
This is great because we're able to target specific elements (only <a> tags inside <div id="nav">) without a lot of extra work or code.
CSS that's based on page structure
The classic example of great CSS is CSS Zen Garden. It's a beautiful example of what good designers can do with CSS, but most people don't consider the unsung hero: cleanly structured HTML. The page structure is designed for styling. Since the page is designed so that it can be styled via descendant selectors:
- The HTML is very simple, structured around the page's information rather than design
- It's got ID's assigned to all of the containers elements
So, now, let's look at a the structure of the HTML used in CSS Zen Garden.
<BODY id=css-zen-garden> <DIV id=container> <DIV id=intro> <DIV id=pageHeader> <H1>...</H1> <H2>...</H2> </DIV> <DIV id=quickSummary> <P>...</P> <P>...</P> </DIV> <DIV id=preamble> <H3>...</H3> <P>...</P> <P>...</P> <P>...</DIV> </DIV> <DIV id=supportingText> <DIV id=explanation> <H3>...</H3> <P>...</P> <P>...</P> </DIV> <DIV id=participation> <H3>...</H3> <P>...</P> <P>...</P> <P>...</P> </DIV> <!-- Okay, Jon, we get the point. You can skip the rest. --> </DIV> </DIV> </DIV> </BODY>
So, we've got a really simple page that's been restyled hundreds of times by a wide variety of cutting edge designers. It's all possible because the HTML was constructed in such a way as to expose the page elements as something like a design API (application programmer's interface). There are no ID's or classes titled "big text" or "red footnote" because they're not at all necessary for a CSS developer to get at the elements they need. For example, let's say we want to modify the heading inside the "participation" div. No problem:
div#participation h3 { margin-top: 2em; }
Writing CSS Friendly HTML in ASP.NET
The default rendering of ASP.NET controls isn't CSS Friendly, you can build CSS friendly sites in ASP.NET without too much effort. Take a look at the remix gallery for the VisitMix site, the most remix friendly ASP.NET site I'm aware of.
By far, the nicest thing you can do for your markup is to use the ASP.NET CSS Friendly Control Adapters. Scott Guthrie has a tutorial on them, as does Scott Mitchell. They're really easy to setup and use - you drop some files in your site, and your controls go from <span><table><tr><td><table><tr> parties to using stylable elements like <ul>'s. They went a little nuts with spraying classes on every single element (pretty redundant when you can do the same thing with descendant selectors), but it's a major improvement. Steve Harman and I used them on a project this past year, and it worked great.
When you start using Visual Studio 2008 (if you're not already), be sure to look at the greatly improved CSS editing features. You'll also want to abandon the GridView for the new ListView control, which gives you a lot more control over the HTML your page generates. Here's how Rick Strahl describes the ListView:
The ListView is a sort of hybrid between a DataGrid and Repeater that combines the free form templating of the Repeater with the editing features of the data grid. It looks interesting because it basically allows you much more control over the layout than a DataGrid does while still giving you many of the more advanced features of the data grid.
Note: ID's and Classes
An ID can only exist once on a page; a class can exist multiple times on a page. Generally, it's best to use a class rather than an ID if you're not sure. ID's are best used for structural containers like headers and footers, classes are used everywhere else. Every ASP.NET element is assigned an ID, but it may be munged a bit due to the effects of naming containers on nested controls. You can assign classes to any element you'd like - even the <body> tag - and ASP.NET won't touch them.
David Shea's gone with a lot more ID's than classes for the CSS Zen Garden HTML, which makes sense because this page is completely static. There will never be another "preamble" here, mostly to allow graphic designers to tune their look down to the pixel. We're not so lucky, though. The client always wants to add another "preamble", usually late Saturday night. For that reason, I stick with Classes over ID's most of the time.