Invasion of the Body Switchers

by James Edwards, Andy Clarke

88 Reader Comments

Back to the Article
  1. A very welcome return for ALA and Zeldman.com
    … Great tutorial, as ever.

    You were missed by us all!

    Copy & paste the code below to embed this comment.
  2. It is great to see another article on ALA.

    I hate to be a killjoy but aren’t style switchers better done server side? I can’t really see the point of doing it with JS when is so easy in PHP.

    Oh well thanks for the great article!

    Copy & paste the code below to embed this comment.
  3. @ Mark Wubben: Driving today huh? ;) There will be updates to memory leak soon on either Cake’s site (http://www.brothercake.com) or/and my own (http://www.stuffandnonsense.co.uk). Plus there is also an update for when you don’t wish to include the switcher controls on every page (as on my company site (http://www.malarkey.co.uk)

    @ Paul “the tree” Carpenter: Personally I feel that style-switchers are profoundly client-side solutions, but look out for a PHP and ASP version in the next few weeks. ;)

    Copy & paste the code below to embed this comment.
  4. >Sorry but you’re missing a point here – If
    >you have a standard naming convention then
    >you can put them what you want; but I (as the
    > script) have no idea what your page looks
    >like. I can’t put them just anywhere – I can
    >only put them where you tell me

    Pretty much agreed.  I would however, use a small custom script per project in this case.

    You are correct in saying the script has no idea what the page has.  However, the page, and markup should really have nothing to do with, or knowledge of the scripts in use other than a reference to them (or a few key variables defined at page level at worst).

    As I said before, its a fine line :).  How many ways can you skin a cat?

    If I add this script do i have to change the header section of my site, or the body content and header section of each individual page?

    I’m glad the crap IE specific stuff is not required.  It erks me that it was ever invented/implemented.

    Copy & paste the code below to embed this comment.
  5. Very good article!

    We’re nearing the day when display content and style will be user preference and less server dependent.  As feed standards like RSS and Atom evolve and ontologies like RDF and OWL gain acceptance, the web will be a much more fluid experience combining knowledge, content and stype at the desktop.

    Copy & paste the code below to embed this comment.
  6. Great technique – thanks for the article.

    (Brian – you need to print the page and view the page in a browser with a projection to see the effect of the second and third dropdowns.)

    Copy & paste the code below to embed this comment.
  7. As everyone else I’m very happy to se ALA back in business. And what a great article :)

    Your technique (slightly modified) will save a project I’ve been working on (on and off) for the last year. The project is almost finished except for a couple of strange bugs in Safari we havn’t been able to solve. But you have. Thank you for that.

    I will need to create a variant that loads several css-files to make it work. The main reason for this is as someone else stated, maintainance problems on small sites that grow big. As a principle we also organise small sites the same way as big ones.

    And great of you to provide a garbage collector. Its easy to write one but if you’re not familiar with the concept as most web-programmers seems not to be its easy to walk into a prorietary-code-trap.

    So, great job and if you beat me on the multifile thing I’ll probably use your stuff for that to.

    Copy & paste the code below to embed this comment.
  8. @ Rasmus: A multi-file option, along with a raft of other enhancements are on there way.

    @ All: I personally would be very interested to see how/if this thing is being used in the wild. If anyone has examples, would you post them or send me a link?

    Have fun

    Copy & paste the code below to embed this comment.
  9. I Like it although I’m a little troubled by 2 things. (nothing to do with the code or the mark up of course :-)). 1). It lets the browser designers off the hook in coaxing them to adopt the ‘built into the browser’ style sheet switching that works so elegantly when done right. 2). It also means that you have to have form elements on your page where you might not want them. It still represents a move forward though..

    Robert

    Copy & paste the code below to embed this comment.
  10. Good article, I may use it/

    Copy & paste the code below to embed this comment.
  11. This is a great technique, even better (or so it seems) than the original switcher idea. Thank you so much…

    …but is it possible to make it even more flexible?

    What I want to do, is set this up so that the first selector sets a “theme” for a page (with the page changing ala Zen Garden) and a second that sets “visibility” for menus and content (changing text size and backgrounds perhaps).

    Maybe the second selector would alter the value of an “interior DIV”, so that statements in the CSS might be something like…

      body.theme1 {

      body.theme1 largeText{

      body.theme1 highContrast{

      body.theme2 {

      body.theme2 largeText{

    …and the second and third values would only be applied if the second selector was set to “largeText” or “highContrast”.

    I’m still a beginner with CSS, so I’m not quite cluey enough work out the syntax, but I can see the possibilities. What a great way to make websites more flexible and accessible!

    Copy & paste the code below to embed this comment.
  12. I was reviewing previous comments and noticed that some people were worried about huge and unwieldy CSS files if ALL the coding is placed into one file.

    I wanted to see if it had to or not, as well. I’m about to reconstruct several sites of mine into one big homesite, and wanted to keep the styles I’d developed so that users could pick any style they wanted. I didn’t want to put all the coding into one CSS file either.

    However, the following is quite simple and seems to work on my browser (Maxthon, an IE overlay). In the HTML page, change the style links to something like:

    <style type=“text/css”>@import url(theme1.css);</style>
    <style type=“text/css”>@import url(theme2.css);</style>

    Then, in theme1.css you have coding like…

    @media screen {
    body.theme1 {…}
    body.theme1 a { color : #fff;}.
    .
    .
    .
    }

    …and in theme2.css you have something like…

    @media screen {
    body.theme2 {…}
    body.theme2 a { color : #000;}.
    .
    .
    .
    }

    …and that’s it. See, all the code can be kept as separate as you want.

    Copy & paste the code below to embed this comment.
  13. Even with your solution, Laura, the user still ends up loading all the styles that they may never use… imagine if you went to the zengarden and downloaded hundreds of stylesheets before the default one appeared! Obviously, there it’s a server-side solution, not a javascript trick, but the idea remains: only download the content the user wants.

    Although this is cool, I still maintain that it has no real place outside of a nifty effect on portfolio blogs. Yes, Wired does it, but I don’t think corporate sites are suddenly going to be jumping on the bandwagon with on-page font controls.

    As above, this has the most potential as a way to control something like colours or ‘what to print’ on a page. For example, an on-page tickbox could switch all text to black in the print-stylesheet, making for a much higher quality output.

    Copy & paste the code below to embed this comment.
  14. I can see now that you’re right, in that the technique is best used for small variations, rather than major ones, and swapping in whole stylesheets is better done using the original switcher.

    Thinking about the problem this morning I realised that there might be another way of doing this. On reflection, the advantage of using the original technique is that all the definition of which styles are used, and how the list is presented, is kept in the one javascript file, and not in the actual webpages, where they’d have to be updated manually. So only one or two files are altered, instead of who knows how many.

    Why not have the javascript just reset which stylesheet file is loaded (or reloaded with the refreshed page)? After all, if the whole switcher box code is generated from javascript on the fly, couldn’t the style declaration also be? That way, you only have one stylesheet loaded at any one time.

    Copy & paste the code below to embed this comment.
  15. “Pretty much agreed. I would however, use a small custom script per project in this case.”

    Not worth it. Consider the weight of that vs the customization of adding a simple, empty <div >.

    As for examples in the wild… mayhaps soon. This done mused me good. :)

    Copy & paste the code below to embed this comment.
  16. While re-reading the comments, Laura’s in particular, I was struck by an idea that might work, can’t you have a main css file to use this technique, and then

    @media screen {
    import url(“style1.css”);
    }

    @media screen {
    import url(“style2.css”);
    }

    If you want to offer multiple CSS files. The only draw back is these CSS files still need the classes that must be appended to make this script work, or can this script be reworked so that it disables the styles from one style-sheet when the new one is enabled? If that were possible, then it would also be usefull to then include the other pages as alternate style sheets for UAs like Mozilla and Opera that offer the ability to change the style.

    Hmm, this may not be as usefull as I originally thought it might be…

    Copy & paste the code below to embed this comment.
  17. >> Pretty much agreed. I would however, use a
    >> small custom script per project in this case.

    > Not worth it. Consider the weight of that vs > the customization of adding a simple, empty <div >.

    Of course its worth it.  Simple concepts of programming are seperation of business logic from content from layout.

    If you put the divs in the page you are semi merging business logic and layout and content all into the html. BAD BAD BAD.  Sure its “easier” short term.

    What happens if you have 4500 pages in an intranet, perhaps using 100 or so templates.
    What happens if I need to add another div?

    What happens if I want to update my script on 2 projects that both have 4500 pages, and a few hundered templates?

    Thats a lot files to change to add, modify or remove the solution, rather than a 1 program script, and 1 program insertion script.

    Remember the KISS principle.  If you enforce seperation … then everything “theoretically” should be simple (and is 9/10 times).  The important thing is to keep architecture ideas simple.  Nitty gritty, and specific implementation can be complicated, but stick to the basic concepts.

    Copy & paste the code below to embed this comment.
  18. (It doesnt have to be an intranet.. not sure why i put that as the example above, especially since… bandwidth is generally a lot more generous, and browsers are more controlled in those environments.  It could be any site, a large corporate with a few thousand pages whatever :)).

    I have some rather strong opinions on these types of things (which may well blind my common sense, but im not sure :)) because iv spent the last 2 years “rearchitecting” solutions to be more manageable/upgradeable (on all tiers).

    It’d be great to be able to write something new :).. ill have to bug my employer =]

    Copy & paste the code below to embed this comment.
  19. Works fine in Safari 1.2.3. When Javascript is switched off, the text “To see the effects of print media switching…” is visible even when the dropdown menu does not exist. This is of course the test page only, but maybe you could add a “[removed]” for adding text and other related things that make sense only when Javascript is available, so they would not be rendered at all when JS is off.

    Copy & paste the code below to embed this comment.
  20. found an example of a switcher used by one of Australias largest news papers.

    http://www.theage.com.au

    It works for me :)

    Im not a fan of the specific implementation (hard coding in the controls), but the functionality is there.

    Copy & paste the code below to embed this comment.
  21. Updates to Invasion of the Body Switchers are now available and new developments will be posted at,

    http://www.stuffandnonsense.co.uk/resources/iotbs.html
    and
    http://www.brothercake.com/site/resources/scripts/iotbs/

    Copy & paste the code below to embed this comment.
  22. I’m a week or so late in saying this, but it’s good to see ALA is back in town, baby.

    Copy & paste the code below to embed this comment.
  23. @Mike Purvis – well it is kind of a niche thing at the moment, but there are lots of uses beyond straight design switching.  There are the print controls you mentioned; there could be buttons for changing screen fonts, or controlling the output and layout of a web mail interface; there could be projection media options that turn a website into a slideshow at various formats. These are the kind of things I ultimately had in mind, but whether any of them will become mainstream things, I don’t know …

    @Laura, Seth and Brian—I think there is mileage in that idea.  The first step would be restricting the include format to <link> elements, one for each media or switcher control, and named by the same naming convention, something like this:

    <link id=“link-screen-switcher” media=“screen” href=“screen-switcher-default.css” type=“text/css” />
    <link id=“link-print-switcher” media=“print” href=“print-switcher-default.css” type=“text/css” />

    Then the script can dynamically reload the stylesheet in each link as its changed – so the option “high-visibility” equates to a stylesheet called “screen-switcher-high-visibility.css”

    Now whether the BODY classname paradigm would still be required … I’m not sure, possibly not. Find out when I try it …

    The bottom line is – yes, multi-sheet loading capability is absolutely necessary, and will be forthcoming.  I’ll post a prototype on this thread before release, if that would helpful? So you can see if it meets your expectations.

    @Ned—I don’t understand what the big problem is with these empty divs.  You don’t have to have them.  They’re optional – not required.  All you need is an element into which to append the switcher control, but that can be anything – it can be an element that’s already there.

    Copy & paste the code below to embed this comment.
  24. It’s a shame you’ve abandoned the one thing that made the original switcher such a great piece of work – the standards upon which the switcher was built.

    The original switcher can be adapted to fix many of the problems you have highlighted such as using A tags, see http://jon.dowland.name/ for an example.

    Copy & paste the code below to embed this comment.
  25. > The original switcher can be adapted
    > to fix many of the problems you have
    > highlighted

    It can’t be adapted to support multi-media capability, because the semantics have no scope for it, and that’s why we had to abandon it. 

    If there is a way to acheive this without abandoning those semantics, I’m very happy to hear about it ..

    Nonetheless, the multi-sheet version that’s coming next will have the capability to use alternate stylesheet semantics for one chosen media type, if you wish.

    Copy & paste the code below to embed this comment.
  26. @James: What I’m trying to say is that addition of the script to a large project would be tedious UNLESS you were creating the containers on the fly.  At the moment, you backout if they dont exist.

    These could be created with a custom “insertion” script that says, “ok, regardless of the markup, I’m going to add these controls to the page in the “such n such” container” (and if the container doesnt exist, you make one on the fly).

    Do not depend on markup.

    Copy & paste the code below to embed this comment.
  27. @James: i guess im being pedantic :| appologies.

    I think what u’v done is great.

    Copy & paste the code below to embed this comment.
  28. gives me something to play with over the weekend :)

    Copy & paste the code below to embed this comment.
  29. @ Ned Collyer: Ned, the latest version of the script posted at the links above may resolve your issues.

    As we have implemented it at http://www.malarkey.co.uk, we have the switcher controls on only one ‘customise this site’ page. Then, we included just the script on the other pages (no switching controls) and voila.

    Copy & paste the code below to embed this comment.
  30. And it may well be me …. but it’s like this:

    When you create an element in the DOM you have to append it somewhere.  Where do you append it, if not to an element with a named ID?

    Copy & paste the code below to embed this comment.
  31. Thats the “custom insertion script” (per project) :)
    (Different locations for different markup = custom script for the project to determine location, or which div, where needs to be appended).

    Currently, the implementation is IN the source file. The implementation also depends on the markup.  Hence, the JS source depends on the markup.

    The implementation should be seperated from your source (different file), so that either can be modified in isolation.

    Copy & paste the code below to embed this comment.
  32. Nice article … but I still do prefer CSS-only (no-JS) solutions, since I can’t see any reason for not including alternate styles in the HTML markup.

    RE: Firefox…
    The @media=print style can be seen, if you change the choice in the drop down and then choose File Print Preview.

    Nice to have ALA back :-)

    Copy & paste the code below to embed this comment.
  33. @Ned – no, the implementation does not depend on the markup.  The JS has a single variable (an argument passed to the object) by which you specify where to put the switcher control.  If you want that value determined by the result of another process, that’s up to you, but the script itself is fine.

    @Fritz – because there’s no way to select those alternate styles for more than one media indendently.

    Copy & paste the code below to embed this comment.
  34. Sorry, because my last comment reads a little pissy.

    What I mean is that, although the script does have a dependence to the structure of the markup – it wants there to be an element with a named ID, or not, with no in between judgement – that’s as good as a generic script can ever be. 

    If you want to modify it for your needs to make structural judgements, that’s cool, but it’s way beyond the scope of the core script – it would take a ridiculous amount of code, almost a whole meta-language, just to describe how it makes these judgements, and it would still get it wrong most of the time.

    As I’m sure you appreciate, writing scripts for other people to use is completely different from writing something for your own site.  You can second-guess yourself, but I can’t second guess everybody.

    Ultimately, there has to be a point of distillation – a place where you tell the script what to do for a certain decision it can’t make itself. There’s no way around that … and this is (one reason) why elements can have ID attributes at all.

    Copy & paste the code below to embed this comment.
  35. The “new bodySwitcher” directives that create the controls don’t have to be in the same script – you can put them somewhere else if you want.

    Copy & paste the code below to embed this comment.
  36. great article. after the first style switcher article, i used the same approach to implement color palette switching for a number of my projects. with a single click, the sites’ entire color scheme can change from half-a-dozen options. many thanks, ala. you help us not-so-creative people become more creative.

    Copy & paste the code below to embed this comment.
  37. I’m with you, Ned, I am. But I feel like you’re blinded by something here, not sure what… ;) But considering your comments:

    “What happens if you have 4500 pages in an intranet, perhaps using 100 or so templates.
    What happens if I need to add another div?

    What happens if I want to update my script on 2 projects that both have 4500 pages, and a few hundered templates?”

    That sounds like a job solved by some smart template architecture, and a global include. :) Yes, that of course doesn’t account for the situation where you spend two years salvaging a monster, but nothing is going to be easy in that situation! You’re fixing what makes slick implementations like this bothersome.

    Besides, somebody made a point about how you’d determine where to create these in the absence of the <div>s… yes, you could do it programmatically, but then I think it goes beyond the scope of many ALA readers and developers in today’s world(myself included) which means it makes implementation more hunt-and-peck than plug-and-play. :)

    But believe me, I’m with you. I’m also learning to better realize how to make compromises for the greater good, and I think this is an example of that.

    Copy & paste the code below to embed this comment.
  38. Thanks for the clarification Malarkey… I haven’t tried using non-screen media types yet and so hadn’t experiend the limitations of the previous switcher.

    I look forward to a future revision which recaptures the LINK tags :)

    Copy & paste the code below to embed this comment.