CSS isolation: there has got to be a better way

(c) Bertrand Le Roy 2003 CSS can be a tricky thing. I’m trying to do something that I think should be pretty simple. Let’s say a page contains a section (e.g. an admin panel) that must be styled independently from the rest of the page, but consistently and predictably. The DOM and CSS for the main part of the page is undetermined (e.g. because it’s part of a user-defined theme). Of course, you could use iframes, which are about the only isolation mechanism in HTML but we can’t do this here because iframes are quite rigid in shape (they are rectangles), they make scripting the DOM more difficult and they pretty much require an additional round-trip to the server to serve their contents.

The real problem to solve here is that if the main CSS for the page defines very general styles that for example target all elements with a given tag name, and those styles are going to bleed into our specialized region unless we find a way to block that CSS from cascading down. Ideally, you’d have an attribute on the tag, something like inheritcss=”false”, but no such thing exists.

So the only way I’ve found to solve this problem is to write a stylesheet that explicitly resets the defaults for all properties and all elements. Here is an excerpt from the CssIsolation.css file:

.isolate *
{
    background: white none repeat scroll 0% 0%;
    border: 0px none black;
    border-collapse: separate;
    border-spacing: 0px;
[...] z-index: auto; } .isolate p { display:block; margin-top: 16px; margin-bottom: 16px; } .isolate strong, .isolate b { font-weight: bold; } .isolate h1 { display: block; font-size: xx-large; font-weight: bold; margin-top: 21px; margin-bottom: 21px; }

This is lame for a number of reasons:

  • Defaults might vary from browser to browser (this is particularly true of fonts and sizes).
  • Some styles can’t be reset to defaults, such as default button styles (at least, not without using browser-specific styles that aren’t consistently available):
    Default button styles can't be reproduced.
  • An exhaustive list of tags and style properties is sure to be wrong now or in the future (I did CSS 2, so it’s already outdated by CSS3).

Still, imperfect as it is, this is a solution that works reasonably well and can be improved as problems are found. The equivalent of that inheritcss=”false” attribute, using my isolation stylesheet, is to set class=”isolate” on the parent element of the section of the page you want to isolate. None of the styles defined for the rest of the page (which is defined just as usual, with no difference whatsoever) should bleed then.

Here a snapshot of my test page, where you can see, side-by-side, unstyled HTML and HTML with reset styles:

Comparison of contents, unstyled and with reset applied.

Differences exist but are quite subtle.

The HTML for an isolated section is defined like this:

<div class="isolate" id="isolated1">
    Isolated 1...
</div>

If for example the main style sheet defines the style of lists like follows, this style won’t bleed into any element that has the isolate class (on the right on the next screenshot), just because we set the “isolate” class on the parent element.

ul li 
{
    list-style-type: square;
}
ol li 
{
    list-style-type: upper-roman;
}

Main CSS doesn't bleed into isolated section.

You can then style each of these sections independently by just qualifying each of the style selectors with the ID of the parent element. In other words, just paste “#isolated1” in front of each selector of the local stylesheet, if the id of the parent element is “isolated1”:

#isolated1 p
{
    color: Green;
    border: solid 1px black;
}

This style will override the isolation CSS because it is qualified by id, which always wins over styles that are only qualified by class:

Local isolated CSS

I really wish one of you will tell me how stupid I am for not knowing about feature/hack X that is way simpler and gets you to the same place… There has got to be a better way.

The code for the isolation stylesheet, as well as the test pages, can be found here:
http://weblogs.asp.net/blogs/bleroy/Samples/CssIsolation.zip

14 Comments

  • YUI Library CSS Tools at http://developer.yahoo.com/yui/ contains a CSS to RESET browser's default styles and apply some consistent cross browser BASE style.

    Rules in YUI CSS applies to ALL elements, but it can be modified to define .isolate class.

    It is an not an easier way, it is the same approach, but it is already tested and used.

  • You're not the only one who wants it:
    http://www.mail-archive.com/whatwg@lists.whatwg.org/msg03931.html :)

  • Thanks all for the great links and feedback, which showed me the extent of my ignorance :)
    To summarize the whatwg discussions, XBL has an attribute for components that enable them to be style-isolated, but we can't use that right now because it's not available in all current browsers. The proposal to have a reset CSS property, HTML attribute or element seems to be taken seriously and it's reasonably likely that it will make it into a future version of CSS but again that doesn't help us right now.
    I did know about the CSS reset work from Yahoo! and Meyer, but they're doing something quite different, which is to level the CSS playing field and bring the default from all browsers to common values so that styling can be done in a more predictable way.
    Two of you mentioned that they were using a modified version of those stylesheets along the lines of what I'm doing here, but that only resets those few styles that happen to be different across browsers.

  • The way I handle this is put a container around the main content then define the styles as context specific e.g.

    div id=mycontainer

    #mycontiner p { color: red; }

    then have a separate container for the admin portion and specify those as context selectors too

    div id=myAdminPanel

    to place the admin panel there are several options which may or may not restrict older browsers supported

    #myAdminPanel p {color: blue; }
    to contain the variances between browsers I use YUI's reset-font-grid css as others here have mentioned

  • @Jeff, right, but if you have no control over the main stylesheet, that doesn't work.

  • What's wrong with creating unique classes for every element that you are using in a widget from a separate server? It should work no matter what the browser since you are sort hard-coding your style in the parent website.

    As I understand the reset.css that YUI is working on levels the playing field for all website developers who are developing an actual webpage.

    If you are developing widgets and the such that cross domains then you need a separate solution.

  • @Hector: you seem to be assuming you're the widget author and have control over its markup. Or are you saying that you want to slap those classes on every single element after including the widget?
    In any case, having a style on an element is not going to prevent and style that you are not setting explicitly to bleed through from the main CSS for the page. This is the problem we're trying to solve here.

  • whats it called when you have the structure within the css? I.e. #Main .Content span {color: #000;}
    instead of span {color: #000;}

    I know why, just can't thing what's the official term for it!

    Thanks,
    James

  • Wishful thinking.

    @scope #adminpanel {
    /*
    Styles that are scoped to the admin panel area.
    The equivalent of having
    in the markup of the #adminpanel div.
    */

    h1 {color: red; font-weight: bold;}
    .panel { width: 400px; height: 300px; overflow:scroll; }
    form { margin:0; }
    input{float: left;}
    label {float: right;}

    } /* end scope */


    it would also be nice if we could have something like in the markup but without having to write the css in the markup:



    ....

    ...

  • I think you're looking at the problem from the wrong perspective.

    Inheritability is what you WANT and not what you need to stop.

    Instead of writing many general css selectors (like p {}) limit your css per-section.

    If you need completely different style rules for a section of content, keep it separated from the section styled differently. Or write rules that negate what you've written before.

    That's what priority is made for, and that's why priority is (simplifying) established as heavier for longer selectors: to be more specific as you write rules for deeper parts of the page.

    Maybe you problem is not with css, but with the structure you apply css on.

  • @Marco: I'm afraid you did not understand the problem correctly. The problem is when you don't control the css for the rest of the page (and I'm sorry but you don't get to tell me what I want). When you say "keep it separated from the section styled differently", I can't because I have no knowledge of it. "write rules that negate what you've written before": *I* have not written that, I have no control over it so I can't write a rule that negates it. That's the whole point.

  • I see that CssIsolation.zip lacks a license file. Can you clarify what its terms are? I see on you about page 'All content is provided "AS IS" with no warranties, and confers no rights. Use code samples at your own risk.', which isn't super helpful.

  • @Jrd: public domain. If you need me to license it to you under a license of your choice, I can do that as well.

  • Check out OOCSS. Instead of targeting, a h1 for example, like this: h1 {}, you have h1.h1 {} or h1.hlevel1 {}
    You then apply the class where you want that style to go. This way if you don't want your headings to look a certain way in your admin panel, don't put the class on them. OOCSS is amazing and has so many more important reasons to use it, but you could use that technique to mitigate some of the problems. Somethings should cascade, and you shouldn't fight it though. Just target the area and do your default or reset styles.

Comments have been disabled for this content.