Case-sensitive attribute selectors in CSS

Published

I recently came across an odd problem in CSS. The default styling of the <ol> element can’t always be replicated by a stylesheet. This means you might want to be careful with ‘reset’ styling that you won’t later be able to override.

The problem comes when you use the type attribute, which indicates what kind of numbering to use for the list items. You can set it to “1” for the default decimal numbering, or “a” to use letters instead (a, b, c, …), or “i” for roman numerals (i, ii, iii, …).

<ol>
  <li>Item 1
    <ol type=A>
      <li>Item 1.A</li>
      <li>Item 1.B
        <ol type=i>
          <li>Item 1.B.i</li>
          <li>Item 1.B.ii</li>
          <li>Item 1.B.iii</li>
          <li>Item 1.B.iv</li>
          ...

This isn’t purely presentational information. You might have text which refers to list items (“see item 1.B.iv above” or similar) and it will only make sense if the list items are numbered using the right system. So if you change your CSS to use roman numerals for stylistic reasons it’s conceivable that you could be changing the meaning of your content.

You can set the presentation of list numbering in CSS, with the list-style-type property. For example to use lowercase roman numerals:

ol { list-style-type: lower-roman }

But if you want to reset the styling to use the default numbering system based on the type attribute, it won’t work. You’ll have something like this in your CSS:

ol[type="a"] { list-style-type: lower-alpha }
ol[type="A"] { list-style-type: upper-alpha }

ol[type="i"] { list-style-type: lower-roman }
ol[type="I"] { list-style-type: upper-roman }

Unfortunately that won’t work. Well, it will work if you’re serving XHTML with the proper MIME type, because in that case CSS selectors will be case sensitive by default. Usually though HTML and CSS are case insensitive by default, so the rules above which distinguish numbering style based on the case of the type attribute’s value will clash (the second of each pair will override the first).

There is an obscure feature in CSS attribute selectors to change the default, but it only works one way: changing the default for XHTML from case sensitive to case insensitive. You add an “i” after the attribute matching part:

p[class="foo" i] { color: red }

But so far there's no way to go the other way and make the selector case sensitive.

I realize this is about the most who-cares issue in CSS styling. I only came across it when writing a JavaScript demo to show what the different numbering styles of <ol> look like. I had trouble using CSS to style the example output correctly because we’d reset the list-style-type property in our site-wide CSS. In the end I had to kludge it with a style attribute. It’s a rather obscure requirement, but in our upcoming redesign of the Web Design Academy’s websites I’ll try to make sure we don’t over-reset the styling for <ol>.