Liz Castro <lcastro@cookwood.com> wrote: > This is a simplified form of Tantek Celik's box model hack, right? Yep, that's the plan. It seems to work just as well, but it hasn't been nearly as widely implemented as the original, so there may be kinks I've overlooked somewhere. > I see that [Tantek's] works, but I don't quite understand why... CSS has its own 'escaping' scheme to allow out-of-bound characters to be included in strings and identifiers. For example, <div id="foo.bar"> is valid, but to style it you wouldn't be able to say 'div#foo.bar', as the dot is taken as being part of a class selector. Instead you have to write 'div#foo\.bar'. The backslash removes any special meaning from the character after it. Any character can be escaped this way, even characters that do not need to be escaped, like '\w'. (However, '0' to '9' and 'a' to 'f' have a different interpretation, they are taken as hex charcter codes.) The important point is that some browsers do not understand CSS escapes, and it is possible to exploit their misinterpretation of what a backslash means to present them with different styles. The BMH aims to give a different 'width' property to IE5/Win, which both (a) doesn't understand CSS escapes, and (b) misinterprets the 'width' property. The BMH ======= div.content { width: 400px; voice-family: "\"}\""; The above line is interpreted by a correct CSS parser as being the same as: voice-family: '"}"'; which is an odd name for a voice-family but not an invalid one. It then goes on to the next property: voice-family: inherit; which just sets it back to what it would have been before. Any property that accepts a quoted value could be used to do this, there is nothing special about voice-family. Anyway, the correct parser then sees the final property: width: 300px; } which makes the div thinner to make room for its padding. On the other hand, a browser whose implementors never heard of CSS escapes will read: div.content { width:400px; voice-family: "\"}\""; and this time the line above will be interpreted as if the blackslashes were not special characters at all: voice-family: "/" } /""; so it'll set the voice-family to a backslash(*) and end the rule immediately, leaving the wider width setting in place. It then comes across some quotes, a semicolon, 'voice-family: inherit;', 'width: 300px;' and a '}', but since these occur outside a rule and aren't valid selectors they'll probably be ignored, until the start of the next rule. (* this is the reason 'voice-family' was chosen for the hack - the older graphical browsers we are targeting with it don't support Aural CSS anyway, so it doesn't matter if the voice gets left with a weird value.) Being nice to Opera =================== One kink in this strategy is that there are browsers (Opera, before version 6, and I think some others) that get the box model right, but still don't understand CSS escapes. For this reason, the above rule tends to have this one somewhere after it: body>div.content { width: 300px; } which gives the correct width to browsers that understand the child selector '>' as well as those that support escapes. IE understands neither, so it keeps its 'wrong' width to compensate for its bugs. Simplified BMH ============== The SBMH seeks to reduce the ugliness a little by applying CSS escapes to the property name instead of the value of a property like 'voice-family'. It is unusual to use CSS escapes in property names because no property name has any characters in it that need escaping, but it's perfectly valid. div.content { width: 400px; } /* wrong value */ div.content { w\idth: 300px; } /* for standards browsers */ Browsers that do not understand escapes will see the second property name as something weird with a symbol in it, and will ignore it. It fact they are likely to ignore the entire rule. They will stick with the wider setting in the previous rule. Browsers that do understand it see 'w\idth' as being exactly the same as 'width', and override the first version with the narrower, correct one. This suffers from the same problem as the original BMH regarding browsers that get the box model right but don't support escapes. The SBMH gets around this by noting that although IE5/Win doesn't support escapes, it will happily ignore any backslashes that occur before the start of a token. Other browsers that don't support escapes won't allow this. So we add a third rule: div.content { width: 300px; } /* for browsers with no escapes at all */ div.content { \width: 400px; } /* for IE5/Win */ div.content { w\idth: 300px; } /* for good browsers */ simplistic browsers understand only the first rule. Standards browsers understand them all, so use the third. Stuck in the middle is IE, whom we catch as serve a different style. One can do the same thing with other properties too, eg. height \height he\ight 'h\eight' is no good as the 'e' is taken as part of a hexadecimal escape. Indeed the only properties one can't use the this to hack for IE5/Win are those than begin with letters 'a'-'f'. Caveats ======= This applies to both the original BMH and the SBMH. First, you must use a Standards-mode DOCTYPE in your HTML. IE6 supports CSS escapes properly, but it will only use the correct box model in Standards. In Quirks mode it would read the 'correct' value from the CSS but use it in the same 'wrong' way as IE5 did. Secondly, using CSS escapes at all with confuse Netscape 4 to the point of making it ignore the *entire* stylesheet. Other stylesheets linked to the page are still used OK. If you are withholding styles from N4, or using a separate stylesheet, that's obviously not an issue. But if N4 compatibility is required, it's better to use the alternative workaround of simply not specifying an element with width and non-zero padding at the same time. The same effect can usually be achieved by putting the padding on a second div inside the one with set width anyway. Erm, does that answer your question? What was it again? ;-)