Per Site User Stylesheets

Browser configurable user stylesheets have been around for years but are rarely used because it is nearly impossible to have a single global stylesheet for the whole web. Recent discussion on Eric Meyer’s weblog and some follow on discussion at Photo Matt has me thinking of ways that we might be able to make user stylesheets more useable.

Update!

Eric has proposed a system where authors are responsible for giving each page’s <body> element an id attribute unique to the site:

<body id="www-meyerweb-com">

This lets me write rules in my User Stylesheet like the following, which causes all level 1 headings to be rendered in a 600pt font but only for Eric’s site:

body#www-meyerweb-com h1 {
  font-size:  600pt;
}

That works but requires each site to adopt this convention on every page they produce. Simon Willison makes the following comment at Photo Matt:

Global user stylesheets are a poor idea, because so much of the web is built in crazy ways that mean a user stylesheet could easily result in unreadable sites. Custom styles on a per-site basis (as enabled by Eric’s CSS signatures) are much, much more useful but they need to be a browser supported feature rather than relying on the site author adding a unique ID. I’d love to be able to change the default typeface on Slashdot for example.

I wonder if it might be possible to provide browser extensions that do what Eric proposes automatically. JavaScript to add a signature based on the current URL is trivial:

<script language="JavaScript">
function addStyleSignature() 
{
  // get the hostname from the URL and replace dots by dashes.
  var sig = window.location.host.replace(/\\./g, '-')
  
  // set body/@id = sig
  var body = document.getElementByTagName('body').item(0);
  body.setAttribute('id', sig)
}
</script>

This test calls an embedded version of the addStyleSignature function and then checks that it was set properly (tested w/ Firefox 0.9 and Konqueror 3.2). I’ve also added a css rule that should make the background color go green after the signature is applied.

The tricky part is getting this script to execute for every page we visit and this will vary from browser to browser. I’ve worked out a solution under Firefox 0.9 that should work on older versions and other Mozilla based browsers (Netscape, Galleon, Epiphany, etc). You will need to add the following snippet to your userContent.css file:

body {
  -moz-binding: url(http://naeblis.cx/static/xbl/sitecss.xml#sitecss)
}

This tells the browser to use this XBL binding for body elements. Here is the content of sitecss.xml:

<?xml version="1.0"?>
<bindings
  xmlns="http://www.mozilla.org/xbl"
  xmlns:html="http://www.w3.org/1999/xhtml"
>
  <binding id="sitecss">
    <content><children/></content>
    <implementation>
      <constructor>
      <![CDATA[
      var sig = window.location.host.replace(/\./g, '-');
      this.setAttribute('id', sig);
      ]]>
      </constructor>
    </implementation>
  </binding>
</bindings>

As you can see, this is just the same script from before but wrapped up in XBL. Any time a body tag is encountered the site’s CSS signature will automatically be placed in the id attribute of the <body> tag. Cool, eh?

Update 2004-07-15

Simon Willison points out a few problems with the XBL approach. I’m considering updating the sitecss.xml to accommodate for sites with existing id attributes (the XBL breaks Gmail for instance) but forget all that because I found something even better.

The URIid Extension does the exact same thing as the XBL hack but is packaged into a nice extension. This gets around all kinds of problems–not the least of which is that sitecss.xml is now getting more hits than anything else on my site <sigh>. Unfortunately, the description of the URIid Extension on the mozdev site is so poor that I don’t think anyone realized what it was. Some of the comments on the Extension imply that it doesn’t work reliably but after using it for an hour or so I can say that it is at least as stable as the XBL hack.

**I highly recommend that you remove the XBL hack from your

userContent.css

file and install this extension in its stead.**

One thing I can contribute that might be of some use is the following bookmarklet that can be used to determine the id that is set on the page you are looking at. This is useful because, as Simon mentioned, some sites will already have an id attribute. The bookmarklet tells you what’s in there whether it was generated by the extension or specified by the site so you don’t have to guess or hunt through the source:

Site Signature Bookmarklet (Right Click -> Bookmark This Link)

Also, I just noticed MyOwnCSS, another Mozilla/Firefox extension that serves a similar purpose and has significant potential in other areas. Your Per Site User Stylesheets are stored on the MyOwnCSS server. With time and help this could become del.icio.us for User CSS. How cool would that be? Imagine going to slashdot and seeing 50 alternate stylesheets… The possibilities are pretty endless, I might have to dedicate a whole entry to this at some point.