CSS for the hierarchically minded

Inasmuch as both HTML and XML markup – being descended from SGML – support a nested, hierarchical structure and as CSS allows, even promotes, a stream-of-consciousness style of coding, there can be a tension between the two approaches.

To put it another way:

  • If you want different styles in a couple of contexts that depend on the type of several levels of ancestor, then you get to put all those ancestors in the CSS selectors for each of those styles;
  • If you want to use the same colour in multiple different styles, then, by golly, you get to enter the same color value in each of them (and if you want to change it later, you get to find them all again to do it); and
  • If you want to use the same set of styles in multiple contexts – say, use rounded corners multiple places and with bigger radii on the outermost corners – then you get to repeat the same set of styles while jiggering their values every place that you want them.

The CSS soon gets to the point that only a machine can reliably work out the cascading and so we require tools such as Firebug to make sense of it and present it to us in ways that we can understand.

I have previously implemented a system for a client where the template CSS file is wrapped in an XML element and contains empty elements for each of the values of color properties so the all-XML processing system can ‘skin’ the stylesheet by substituting the preferred color values and outputting proper CSS on the way to making the HTML, but that was adding complexity, not taking it away.

Enter LESS (http://www.lesscss.org/), the “dynamic stylesheet language”. LESS is pretty much CSS as it should have been, since it elegantly solves the gripes listed above, and more besides.

LESS is available as a JavaScript library for client-side translation of .less stylesheets linked from your HTML with the link’s rel attribute set to “stylesheet/less” into CSS on the fly and server-side for use with Node. It’s also available as a command-line program that simply converts LESS to CSS that you can save and serve statically.

There are good and succinct examples on the LESS website. Just to be different, here’s an example from my GitHub project for an XML Summer School skin for S5.

Here’s a subset of an old version borrowing what was originally Norman Walsh’s CSS for his project for producing XHTML slides for XML Summer School:

.footer {
    background-color: #fffc84;
    position: relative;
    background-image: url(../images/cc-1024.png);
    background-repeat: no-repeat;
    background-position: 3 3;
    margin-top: -48px; /* negative value of footer height */
    height: 48px;
    bottom: 0px;
    padding-left: 100px;
    clear: both;
}

.footer .content {
    padding-left: 400px;
    height: 0px;
}

.footer .license {
    padding-top: 8px;
    padding-left: 30px;
    font-size: 10pt;
    height: 0px;
}

.footer .foilnumber {
    text-align: right;
    padding-right: 30px;
    padding-top: 14px;
    font-size: 10pt;
    height: 0px;
}

pre {
    font-family: Courier New, Courier, monospaced;
    font-weight: bold;
    border: 1px solid black;
    padding: 10px;
}

.xml {
    background-color: #E6E6E6;
}

.xslt {
    background-color: #FFFDCE;
}

.schema {
    background-color: #E5E7FE;
}

.other {
    background-color: #C7FFFF;
    color: #9E0000;
}

.xml .pi {
    color: #8C35C7;
}

.xml .el {
    color: #001A94;
}

.xml .att {
    color: #FC7F4C;
}

.xml .attval {
    color: #9E2E00;
}

.xml .ent {
    color: #979315;
}

.xml .xslt {
    color: #006AC6;
}

pre .p {
    color: #9E0000;
}

pre .kw {
    color: #001A94;
}

pre .str {
    color: #595837;
}

pre .re {
    color: #FC7F4C;
}

And here’s a old but LESSified version of the same excerpt:

@yellow: #fffc84;

.footer {
    background-color: @yellow;
    position: relative;
    background-image: url(../images/cc-1024.png);
    background-repeat: no-repeat;
    background-position: 3 3;
    margin-top: -48px; /* negative value of footer height */
    height: 48px;
    bottom: 0px;
    padding-left: 100px;
    clear: both;

    .content {
	padding-left: 400px;
	height: 0px;
    }

    .license {
	padding-top: 8px;
	padding-left: 30px;
	font-size: 10pt;
	height: 0px;
    }

    .foilnumber {
	text-align: right;
	padding-right: 30px;
	padding-top: 14px;
	font-size: 10pt;
	height: 0px;
    }
}

pre {
    font-family: Courier New, Courier, monospaced;
    font-weight: bold;
    border: 1px solid black;
    padding: 10px;

    &.xml {
	background-color: #E6E6E6;

	.pi {
	    color: #8C35C7;
	}

	.el {
	    color: #001A94;
	}

	.att {
	    color: #FC7F4C;
	}

	.attval {
	    color: #9E2E00;
	}

	.ent {
	    color: #979315;
	}

	&.xslt {
	    color: #006AC6;
	}
    }

    &.xslt {
	background-color: #FFFDCE;
    }

    &.schema {
	background-color: #E5E7FE;
    }

    &.other {
	background-color: #C7FFFF;
    }

    .p {
	color: #9E0000;
    }

    .kw {
	color: #001A94;
    }

    .str {
	color: #595837;
    }

    .re {
	color: #FC7F4C;
    }
}

Note that:

  • The colour @yellow is also used elsewhere in the stylesheet, but I didn’t want to repeat the whole stylesheet here.
  • The & combinator concatenates a nested selector to its parent selector instead of the selector acting as a descendent. As the LESS website notes, this is especially important for pseudo-classes like :hover and :focus.
  • Code samples in the slides are represented with the <pre> element with a different background colour depending on the code type..
  • The class names for styling parts of XML markup in samples are common to both XML and XSLT samples. Since my project includes a stylesheet for translating Norm’s XHTML slide markup to S5-style XHTML, the class names are unchanged from the original and thus there’s a necessity for markup such as <pre class="xml xslt"> for getting the right colour for elements and attributes, etc., in XSLT code samples. If it weren’t for that, it would have been more sensible to use a LESS mixin to handle the repetition between the XML and XSLT code sample styles.

My only gripe with LESS so far is that I’ve yet to get it and the JavaScript from S5 to play nicely together, so I had to back out the use of LESS for the S5 project, which to date was my only publicly visible project to use LESS.

Arguably CSS1 could have introduced something more LESS (you just knew I’d been wanting to write that, didn’t you?) since <div> – the definitive expression of hierarchy in HTML content – was introduced in the HTML 3.0 drafts and CSS 1 refers to HTML 4.0. Hindsight, being the only perfect science, would indicate that is should have been possible, but I really don’t know whether it was technically or politically feasible once there was an installed base of CSS1 engines and web pages that used CSS1 as we knew it. If LESS does now catch on enough that it gets baked into browsers, this ‘native’ LESS would probably require a different, registered rel value or a well-known MIME-type so there’s no conflict on the web pages that currently use LESS stylesheets with the LESS JavaScript library.