Tales from the Evil Empire

Bertrand Le Roy's blog

News


Bertrand Le Roy

BoudinFatal's Gamercard

Tales from the Evil Empire - Blogged

Blogs I read

My other stuff

Archives

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

Posted: Apr 14 2009, 12:26 AM by Bertrand Le Roy | with 14 comment(s)
Filed under: ,

Comments

bcardiff said:

YUI Library CSS Tools at 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.

# April 14, 2009 9:22 AM

helephant said:

You're not the only one who wants it:

www.mail-archive.com/.../msg03931.html :)

# April 14, 2009 11:38 AM

Bertrand Le Roy said:

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.

# April 14, 2009 2:27 PM

Jeff K said:

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

# April 26, 2009 11:08 AM

Bertrand Le Roy said:

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

# April 27, 2009 12:04 PM

Hector said:

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.

# June 5, 2009 3:48 PM

Bertrand Le Roy said:

@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.

# June 5, 2009 3:58 PM

James Radford said:

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

# January 14, 2011 12:43 PM

thinsoldier said:

Wishful thinking.

@scope #adminpanel {

/*

Styles that are scoped to the admin panel area.

The equivalent of having <style scoped=scoped>

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 <style scoped> in the markup but without having to write the css in the markup:

<div id="adminpanel">

<link scoped=scoped rel="stylesheet" type="text/CSS" href="adminoverlays.css">

<p>....</p>

<form>...</form>

</div>

# July 16, 2011 12:54 PM

Marco said:

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.

# November 10, 2011 9:28 AM

Bertrand Le Roy said:

@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.

# November 10, 2011 3:27 PM

Jrd said:

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.

# April 20, 2012 2:50 PM

Bertrand Le Roy said:

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

# April 20, 2012 9:15 PM

Tim said:

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.

# September 5, 2012 4:03 AM