Controlling JS From CSS

Separation of content and presentation is an important principle of modern web design. It is generally accomplished by styling semantic HTML or XML (content) with CSS (presentation). However, there are some occasions where CSS is unable to provide the presentational effect required, and one is forced to fall back on scripting. Adding curved corners to boxes is one example of something which usually cannot be done cross-browser without extra markup or scripting.

Recently I was thinking about accesskeys, and decided that accesskey underlining, while very desirable, was arguably also presentation – after all, you don’t need the underlining on a printed copy of the document. So putting <u> tags in HTML is a violation of the separation. Also, if your web application is localisable, you don’t want to be scattering <u> tags through your strings file either.

CSS doesn’t provide a facility which would allow me to underline individual letters without adding extra markup, so I wrote a JavaScript library, the Accesskey Underlining Library, to dynamically underline the correct key. Using the principles of unobtrusive JavaScript, all you have to do to use it is include the script in your page. However, there still isn’t a clean separation because there’s no way to turn the script’s effect on or off using CSS.

So (and this is the new bit; thanks for keeping reading), I came up with the idea of using CSS to style the script element itself, and having the script check that styling when deciding whether to run. This allows control of the script’s function from the presentation layer. Styling the script element itself avoids creating a dependency on having any other particular markup in the page, and you can style almost anything you like about it because it’s invisible.

So, the upshot of all that is that if you are using AUL, you can turn the accesskey underlining effect off by putting the following in your print stylesheet:

#accesskeyUnderline {
visibility: hidden;
}

Check out the code.

16 thoughts on “Controlling JS From CSS

  1. Interesting idea. Would this actually work across browsers? Checking for styles only works if the styles are set as attributes or added by javascript. You would have to check the css file, but I belive that IE doesn’t support that.

    What I usually do on my pages is to use classNames’s to contol everything. So from

    foo

    the javascript would create

    foo

    and then in css

    .accesskeyUnderline{text-decoration:underline;}

    This also makes it easy to do element specific styles, like

    a .accesskeyUnderline{font-weight:bold}

    The only difficulty with this is that javascript doesn’t understand multiple classnames by default, but 1) that shouldn’t matter in this case and 2) fixing that problem is trivial.

  2. Woop, sorry I couldn’t edit the post, and I forgot about the entities, the two foo’s should become:

    <label accesskey=’f’>foo</label>

    <label accesskey=’f’><span class=’accesskeyUnderline’>f</span>oo</label>

    respectively

  3. Gerv,

    You are currently iterating over all elements in a page although you really only want button|label|legend. Why not make the loop into a helper function, then do document.getElementsByTagName for each of the elements you want, then pass the array to the helper function? Much faster on most pages I would think.

    bc

  4. Alan Trick’s idea was also the first thing I thought of. It seems to me that you could achieve this by changing the line:
    innerH.replace(attr.value, “<u>” + attr.value + “</u>”);
    to:
    innerH.replace(attr.value, “<span class=’access-key’>” + attr.value + “</span>”);
    Then in the CSS file you could say;
    .access-key {
    text-decoration:underline;
    }

  5. Also, it looks like I should have mentioned this line too:
    elem.innerHTML = innerH + ” (<u<” + attr.value + “</u<)”;

  6. This is all fine and dandy as long as you don’t care about validation. Then you’re stuck, because the script element doesn’t allow an id (or class) attribute:

    http://www.w3.org/TR/REC-html40/interact/scripts.html#h-18.2.1

    I picked up this little fact when reading through DevEdge’s article on ESPN’s standards redesign, which mentioned that one of the very few problems remaining was the result of id attributes on script elements (for use by ESPN’s advertisers).

    (Of course, there’s nothing saying you couldn’t do this the non-CSS way and just have it done automatically, but the point of the post was to highlight user-modifiable behavior here.)

  7. Alan: I wouldn’t have done it if it didn’t work across browsers. IE does support checking the current style, although not the W3C way. Check the code :-)

    bc: you are probably right. I’ll do that in version 0.2.

    Brian: in this particular simple scenario, that might work. In more complicated page-modification scenarios, it might not. As I said, this is just a demonstration.

    Jeff: oh, drat. I didn’t realise that. Hmm. I could change it to getElementsByTagName(“script”) and check the src attributes for “accesskey.js”. Do you think that would be OK?

    Daniel: so when IE supports it, I’ll use it. :-)

  8. If you want the accesskey displayed after the text of the link (eg if you use only numbers for accesskeys) you only need CSS, eg:

    a[accesskey]:after {
    content: " [" attr(accesskey) "]";
    font-weight: 100;
    background: inherit;
    color: gray;
    }

    Oh, and Gecko, or Opera, or… well, not IE. I suppose it’s not that much help for you then, really. :-(

  9. So to make it validate, could I remove the “id=” from the script tag and just have:

    <span id="accesskeyUnderline"></span>
    

    next to it? That’s less neat, of course…

    Why on earth can’t a <script> tag take an ID? What if I want to remove it from the DOM, for example?

  10. I was looking at the XHTML 1.1 spec, and for a moment I thought it said scripts can have IDs. Then I realised it was noscript. :/
    This is odd to me though, I thought all elements were allowed IDs… especially since the ID attribute is used for more than just CSS…

  11. Jeff: oh, drat. I didn’t realise that. Hmm. I could change it to getElementsByTagName(“script”) and check the src attributes for “accesskey.js”. Do you think that would be OK?

    Presumably so. It would be perhaps unnecessarily fragile, but aside from that I can’t see why it wouldn’t be valid code.