views:

917

answers:

7

Firstly, I know that CSS expressions are defunct and wrong in so many ways, and also to avoid using !important where possible. This is for a special case stylesheet.

In Short

My question is... Is there any way for a CSS expression to set the !important flag?

E.g. this doesn't work:

a { color:expression('red !important'); }

[Edit: thanks to MarmaladeToday's comment below]. This also doesn't work:

a { color:expression('red') !important; }

Can this be done some other way?


In Detail

What I'm actually trying to do is mimic the inherit value in IE6 & 7. This works:

color:expression(
    this.parentNode.currentStyle ?
        this.parentNode.currentStyle.color: 'red'
    );

But I also want to set the !important flag, and this doesn't work:

color:expression(
  (
    this.parentNode.currentStyle ?
        this.parentNode.currentStyle.color: 'red'
  ) + ' !important');

I'm aware that, in JavaScript, it isn't possible to set !important via an element's style object. E.g. this won't work:

element.style.color = 'red !important';

However, it is possible to set !important via the element's style attribute:

element.setAttribute('style', 'color:red !important;');

So... are CSS expressions limited to interacting with the style object, and therefore, what I want to achieve is impossible - or is there any way for an expression to affect an element's attributes, or pass !important in some other way?


Starting a Bounty

No solid answers so far, so I'm starting a bounty.

Ideally, I'm looking for a CSS-based solution for mimicking inherit !important in IE6 and IE7, either with or without CSS expressions. (Please do verify that your suggestions work before posting).

At least, a link to some authoritative reference telling me that this is impossible would mean I could lay this train of thought to rest - I've not seen anything mentioning the use of CSS expressions with the !important rule.

+2  A: 

Hi Prem, try:

color:expression('red') !important;
MarmaladeToday
Sorry - I meant to include that in the original description. No, this doesn't work either.
Premasagar
(Unless you have a working example).
Premasagar
Thought I had, but nope. Figured trying the obvious worthwhile as it's often overlooked.Have you seen this: http://meyerweb.com/eric/thoughts/2007/04/23/inherit-expression-for-ie/ might be food for thought.Annoying I can't comment on other answers here.... Nate is almost correct in that IE6 sometimes doesn't recognise !important apparently, one of the reasons it was used as a hack once upon a time. But I guess it's for over-riding instances like that which your special case style sheet is for.
MarmaladeToday
Yes, that Eric Meyer post was one of things that got us started on expressions as a possible way out of our inheritance hole - but it looks like perhaps they can save us after all.
Premasagar
A: 

Hi Aidann, we tried this already (or something very similar) - !important was ignored because it isn't part of the expression. Have you seen this working?

Ramblinollie
Hint: this is not a forum. Also, if the OP finds a solution he should mark an answer as accepted (or at least make a comment somewhere).
DisgruntledGoat
@DisgruntledGoat - This was a slight confusion - RamblinOllie was replying to MarmaladeToday, but mistakenly created a new comment. No answers yet solve the problem.
Premasagar
A: 

It's been my understanding that !important is largely these days as a hack... specifically because IE does NOT recognize it.

Nate Wagar
Hi Nate. No, `!important` isn't a hack. It's primarily designed to be used in user stylesheets to override the specified styles on the page.It is also supported in IE6+, although in IE6 there is a bug where, if a block of rules contains a particular property that has `!important`, and then the same property is set within the same block without `!important`, the latter will prevail. No doubt IE has some other quirky bugs too, but essentially it works.The problem that I am coming up against is that IE6 and IE7 don't properly support the `inherit` value.
Premasagar
Important is clearly in the CSS2 spec: http://www.w3.org/TR/CSS2/cascade.html#important-rules
Eli
+1  A: 

This sounds sick and evil, but:

color: expression((function (_this) {
    window.setTimeout(function () {
        _this.setAttribute("style", "color:" +
            (_this.parentNode.currentStyle ?
                _this.parentNode.currentStyle.color : 'red') + " !important";
    }, 0);
    return _this.parentNode.currentStyle ?
        _this.parentNode.currentStyle.color : 'red';
})(this));

In other words, this:

  1. Returns "red" (or the parent color) immediately.
  2. Sets a timeout that will set "red !important" (or whatever) immediately after.

Keep in mind that this could end up hosing your browser though. I didn't test it, and stuff involving CSS expressions tends to go terribly wrong.

Anthony Mills
Thanks for the suggestion, Anthony. Out of interest, why do you use a `setTimout`, instead of directly calling `setAttribute`? We had previously tried `setAttribute`, but not with `setTimeout`. Neither way seems to work, though. The attribute is not set and !important is not applied.
Premasagar
+2  A: 

You could try the behavior property, it's a lot more versatile than expressions.

Try this,

inherit.htc :

<SCRIPT language="JScript">
    //add your own inheritance logic here, you can use element.parentNode etc.
    var prop = element.currentStyle.behaviorProp;//specified in stylesheet
    var val = element.currentStyle.behaviorValue;//specified in stylesheet
    element.style[prop] = val;//set as inline style, you can also use setAttribute here.
</SCRIPT>

css:

body #div1 {
    color:blue;
}

#div1 {
    color:red;/*stays blue, because 'body #div1' is more specific*/
    behaviorProp:color;/*specify styleproperty for the .htc*/
    behaviorValue:green;/*WILL become green, because the .htc sets it as an inline style, which has priority.*/
    behavior:url(inherit.htc);
}
I.devries
Thanks for the suggestion, Vatos. Would you like to give an example of how you'd use it in this case?
Premasagar
updated my post
I.devries
Premasagar
+1  A: 

The venerable ppk of quirksmode has done some work on CSS, JavaScript and the !important keyword. (Note that for test in Firefox or any other non-IE browsers, use cssRules instead of rules below.

Here's the link: W3C DOM Compatibility

You can apparently read whether a style rule in a stylesheet is important by doing this (this would get the importance level of the color property in the 2nd css rule in the 2nd stylesheet, IN ALL BROWSERS EXCEPT MICROSOFT INTERNET EXPLORER. How's that for a bummer.

document.styleSheets[1].rules[1].style.getPropertyPriority('color')
//Returns important when the style is marked !important.
//Returns an empty string otherwise.

Now, his research reveals yet another way to set !important, unfortunately this also apparently only works in non-Internet Explorer browsers

// where x is a DOM element
x.style.setProperty('color','#00cc00','!important');
// Set the color of x or the second rule in the second style sheet to green.
document.styleSheets[1].rules[1].style.setProperty('color','#00cc00','!important');

Apparently this strange syntax, if you are not setting things as !important, requires setting the third parameter to null:

// where x is a DOM element
x.style.setProperty('color','#00cc00',null);
// Set the color of x or the second rule in the second style sheet to green.
document.styleSheets[1].rules[1].style.setProperty('color','#00cc00',null);

Now, MSDN has a property called "cssText" that dangles off the style object of a DOM element. It even indicates that CSS expressions are okay. The usage is:

x.style.cssText = 'color: #00cc00 !important';

Now, this may be important (heh), the MSDN page says (emphasis mine):

DHTML expressions can be used in place of the preceding value(s). As of Internet Explorer 8, expressions are not supported in IE8 mode. For more information, see About Dynamic Properties.

It may be worthwhile to check out ppk's tests of cssText as well.

I unfortunately don't have the relevant versions of Windows Microsoft Internet Explorer available on this laptop, but perhaps this is of some use. I'm curious to how this shakes out, it's something I'd run into (setting !important in JavaScript) but found other ways to get around it, typically just shifting around classes or applying specificity by using an ID in the relevant selectors.

Best of luck on an interesting question!

artlung
Hi artlung. Thanks a lot for this thoughtful answer. What you describe is a way to interact with the `!important` rule via JavaScript. Actually that can be done most simply by setting a `style` attribute on the element, as I mentioned in my question - like this: `element.setAttribute('style', 'color:red !important;');`. What I'm looking for, though, is a way to set `!important` from within the CSS stylesheet.
Premasagar
+2  A: 

The reason those CSS expressions don't work is because IE only evaluates the expression for the last property in the cascade.

E.g. if you have an HTML document with a link inside it and the following "CSS",

a {
    color: expression(function(e){
        alert('success');
        e.runtimeStyle.color = 'blue';
    }(this));
}
a { color: red; }

you will never see that alert (nevermind the style change), because the CSS expression is never evaluated. So no, you can't use an expression to set the !important flag.

That is to say, not when you try to set it on the same property. You can cheat. But that does make the expression a bit more complicated:

a {
    filter: expression(function(e){
        e.runtimeStyle.color = 'blue';
        alert('success');
        e.style.filter = '';
    }(this));
}
a { color: red; }

There are a few things to note here.

If you simply use another CSS property, you can be sure that the expression will be evaluated. Or at least, a little more sure, because if there's another rule further down the cascade that uses the same property already, you're still out of luck.

Secondly, you have to use runtimeStyle instead of currentStyle. If you used currentStyle here, the second rule would still end up overwriting it. runtimeStyle overrides all other CSS (except !important declarations). So it's the JScript equivalent of !important.

Also note that I'm resetting the filter property itself as well. That prevents the expression from being continuously re-evaluated. But as much as that may reduce performance, I don't think it's super critical. The main reason I put it in here is because I added alert()s in those expressions, and you definitely don't want to have those pop up forever.

It is in fact also possible to use any other property you make up. This works too:

a {
    bogus: expression(function(e){
        e.runtimeStyle.color = 'blue';
    }(this));
}

However, since the bogus property doesn't actually exist, you can't reset it using Javascript, so this will be re-evaluated continuously.

mercator
Wow. Thanks, Mercator. You clearly understand IE's expressions well. I may want to ask you more q's if they arise (by email?). Your response most directly answers my question, because it uses CSS expressions to mimic inheritance in IE6/7. I like the fact that it doesn't require external scripting files. Maybe we should use something like `bogus`, so that the rule doesn't get overwritten. And I guess we do want to continuously execute the expression, since the value to be inherited may change. (Please do let me know if you're interested in contributing this to the CleanSlateCSS stylesheet).
Premasagar
I e-mailed you. Whether I can actually answer any of your questions is another matter.
mercator
Thanks, Mercator.
Premasagar