28 June 2009

CSS inheritance and selector specificity for max-width

While finding it easier to read text using narrower columns using my custom CSS definition, I noticed that it didn't work on pages that use table rows for grouping sections, such as the following structure:

table
  tbody
    tr
      td
        <headings>
        p …

Here's the CSS definition I was using:


@namespace url(http://www.w3.org/1999/xhtml);

@-moz-document domain(java.sun.com)
{
  body {
    max-width : 35em;
  }
}

It appears that the max-width property defined in the <body> element property isn't inherited by the <p> elements within the <table>. My first fix was to select all the elements in the path between <body> and <p> and make them inherit the max-width property:


…
  table, tbody, tr, td {
    max-width : inherit;
  }

This isn't a nice solution because I would have to specify all the possible types (or elements) that could be in a table cell. It would be better the use the CSS universal selector, *, instead:


…
  * {
    max-width : inherit;
  }

Now the definition is even applied to some elements that we don't really want to limit in size. Elements that are naturally wider than max-width, such as images in <img> tags, are now squashed, while preformatted text in <pre> elements are displayed in boxes with horizontal scrollbars.

If the max-width property is set to none, then the width of an element is not limited. The solution is to have two rules, a universal selector and a type selector, and we have a CSS definition that limits the width of all elements except for <div>, <img> and <pre>:


@namespace url(http://www.w3.org/1999/xhtml);

@-moz-document domain(java.sun.com)
{
  body {
    max-width : 35em;
  }
  * {
    max-width : inherit;
  }
  div, img, pre {
    max-width : none;
  }
}

This definition works because the universal selector is a less specific than a type selector, so the rules for <div>, <img> and <pre> override the universal selector's rule.

As usual when hacking code, I now realise that there's no longer any need to use inherit and I can simplify my CSS definition by specifying the max-width of every type using the universal selector.


@namespace url(http://www.w3.org/1999/xhtml);

@-moz-document domain(java.sun.com)
{
  * {
    max-width : 35em;
  }
  div, img, pre {
    max-width : none;
  }
}

To see the effects of the different definitions, add the style to your Stylish add-in, visit this Sun Java page and observe what happens to the width of the navigation bar on the top of the page and the sequence diagram images.