Categories:

In-CSS hacks

One of the drawbacks of conditional comments is that they require changes to the HTML source. Unfortunately, there is no equivalent to conditional comments in CSS. Instead, if you must use in-CSS hacks, you must use some other much less reliable techniques, often involving the exploitation of browser bugs.

Easy selectors

Most in-CSS hacks deal with selector bugs. The following is a list of browser version ranges and the beginnings of selectors that are known to select elements in them. Note that because these hacks rely on browser bugs or missing features, results may vary in some lesser-known or future browsers. All of these selectors use valid CSS.

IE 6 and below
* html {}
IE 7 and below
*:first-child+html {} * html {}
IE 7 only
*:first-child+html {}
IE 7 and modern browsers only
html>body {}
Modern browsers only (not IE 7)
html>/**/body {}
Recent Opera versions 9 and below
html:first-child {}

Note that the hack for IE 7 and below is actually two separate selectors: one for IE 7 and one for IE 6 and below. The rest of the desired selector must be added to both parts of the hack. The two parts cannot be combined with a comma, because IE 6 and below will fail to correctly parse the selector and won't be targetted.

The above selectors will select either the html or body element. This should be used as the start of your full selector. For example, if your desired selector is #foo .bar and you want it to apply only to IE 7, your resulting selector will be *:first-child+html #foo .bar.

Warning: Due to the nature of the Opera-specific selector and Internet Explorer 7's incorrect handling of :first-child, it is very possible that the html:first-child selector may also select in a future version of Internet Explorer, so be careful when using it. This selector also relies on a bug, so it may be fixed in a future version of Opera. This page also describes an alternative method that is more of an issue to implement but may be somewhat more dependable considering the likely priorities of bug fixing.

Minimized attribute selectors

These hacks are based on differences in handling of attributes in minimized form. If a tag is written <input disabled>, input[disabled="disabled"] {} should select it. However, most browsers get this wrong and in different ways.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
	<head>
		<title>Test</title>
	</head>
	<body>
		<input type="hidden" disabled id="attrhack">
		<p>Test</p>
	</body>
</html>

For the above markup, here are the selectors various browsers recognize to select the p element:

#attrhack[disabled=""]+p {}
Firefox 1.5 and below, possibly future versions
Safari 2.0 and below, possibly future versions
Konqueror 3.5 and below, possibly future versions
#attrhack[disabled="true"]+p {}
Opera 9 and below, possibly future versions

Note that neither of these selects Internet Explorer 7. Although it supports attribute selectors and adjacent sibling combinators, it doesn't seem to recognize a string value for attributes in minimized form.

Notice: Minimized attribute form is allowed in HTML but not in XHTML. This hack will not work in XHTML documents.

!important

Internet Explorer 6 and below had a problem with the !important identifier that caused it to be ignored if another declaration of the same property appeared later in the same style declaration block. This can be used to feed Internet Explorer 6 and below special property values that are ignored by other browsers. Internet Explorer 7 fixed this issue.

Here is an example of this technique in use:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
	<head>
		<title>Test</title>
		<style type="text/css">
			p
			{
				background: green !important; /* Major browsers other than IE 6 and below respect the importance immediately */
				background: red; /* IE 6 and below use this value instead, even though the above was marked as important */
			}
		</style>
	</head>
	<body class="page-body">
		<p>Test</p>
	</body>
</html>

@import "non-ie.css" all;

Internet Explorer 7 and below don't support media selectors on @import rules, instead ignoring the entire rule when they are present. Therefore, you can create an entire stylesheet for non-IE browsers and import it into your main stylesheet by adding @import "non-ie.css" all;.

Future versions of Internet Explorer may support the @import rule correctly.

@import "stylesheet.css" all; imports the stylesheet in all major browsers except IE 7 and below. It may or may not work in future versions of IE.

body[class|="page-body"]

The CSS 2.1 specification isn't clear about whether or not a hyphen can be included in the value of a hyphen-separated attribute selector. Most browsers, including Firefox and Internet Explorer 7, Allow the body[class|="page-body"] selector to select an element whose start tag looks like this: <body class="page-body">. However, Opera interprets the specification differently in this regard. It splits up the attribute value by hyphens and only checks the first piece against the attribute selector value. Obviously, if the attribute was split by hyphens, the first piece won't have any hyphens in it, so Opera treats this selector as a non-match. Therefore, when the proper class is applied to the body element, this selector matches Internet Explorer 7 and most modern browsers except Opera. Opera may change their behavior to match other browsers in the future, but this technique is known to work for Opera 8 and 9.

Here is an example of this technique in use:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
	<head>
		<title>Test</title>
		<style type="text/css">
			p
			{
				background: red; /* Applies to all major browsers */
			}

			body[class|="page-body"] p
			{
				background: green; /* Applies to IE 7 and most modern browsers except Opera */
			}
		</style>
	</head>
	<body class="page-body">
		<p>Test</p>
	</body>
</html>

body[class|="page-body"] {} selects the body element with the class page-body in IE 7 and all modern browsers except Opera 9 and below. It may or may not work in future versions.