Taking CSS beyond a simple style library


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:


{ color: #99f; font-size: 16px; }

No... that's not big enough. Time for 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

CSS Zen GardenThe 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.


  • Great post... CSS (and semantic markup) is one of my biggest passions: http://www.singingeels.com/Articles/How_To_Pure_CSS_Design.aspx

  • I have been pushing for clean semantic HTML for years, but for some reason all the designers I work with just don't get it.

    They have to create some sort of design with jacked up shadows and gradients that make it impossible to construct with out using tables, which just makes me mad.

    I hope one of these days I can find a designer that realizes HTML is not Photoshop and will actually design for the web.

  • jon, nice post.

    I'm not a fan of CSS Adapters though - it's just one of those extra things that seems to make asp.net "heavier". we just shouldn't need adapters at all.

  • Jon, the ID selector approach gets a little kinked quite a bit by ASP.NET's injection of ClientIDs in my experience. Unless you don't use containers it's gets pretty tough to get at individual elements at times...

  • @kevin - I agree that we shouldn't need the CSS Adapters, but I think we do. The alternatives are terrible HTML from the current web controls, or throwing out the web controls and doing things manually. I'm not a fan of ditching the web controls.

  • @Rick Strahl - Yes, I agree. I did mention the munging effects of naming containers a bit, but it bears repeating. Classes are usually a better option in most cases, anyhow.

    Funny that as you were leaving a comment on my post, I was adding your quote about the ListView.

  • I am using the CSS Friendly control Adapters for a while also on my portal Tech Head Brothers (www.techheadbrothers.com)! It is great ! And I would like to add as an info that this project is now hosted on http://www.codeplex.com/cssfriendly and open to community, that would add to your excellent post.

  • @kevin and everyone else: ASP.NET is not the trouble with bad design, it's WebForms. Give a look at Monorail.

  • @SimoneB - you're just getting a little picky now, no?

    ASP.NET is webforms. Yes, MonoRail is the Rails of asp.net (so is promesh.net) and both decouples the need for webforms. But we're not talking about MonoRails or ProMesh.Net here.

    We're discussing ASP.NET and as far as I'm concerned that means WebForms.

    MonoRail or ProMesh.net is a tough sell for most employerrs because of the additional learning curve to bring the team up to speed, to migrate old apps, and to educate new team members, support, etc.

    But once MS comes out with it's own MVC design, I expect by the end of the year, then we can start getting excited about freedom from webforms. And being that this new MVC model will be a MS supported solution, it will be an easier sell to employers.

    Kinda sad, but true.

  • Yes, I'm a little picky ;)

    Btw, ASP.NET is not WebForms. You already know it, many don't, so it's always worth repeating. The bad design lies in anything that inherits from the Control class, not modules, handlers, session...

  • @SimoneB - that's a pretty good point actually. nod to you sir.

Comments have been disabled for this content.