meyerweb.com

Skip to: site navigation/presentation
Skip to: Thoughts From Eric

Universal Child Replacement

The other day I hit a situation that pushed me to come up with a way to simulate the child selector in a way Internet Explorer could understand using two rules.  I doubt I’m the first to think of it, but I’d never seen it before, so I thought I’d document the solution here.

The deal was that I had a column of text featuring white background with some black flecks in it.  On top of that went some near-black text.  All fine, except where the text sat on top of a fleck, which made it next to impossible to read.

To counteract that effect, I decided to set the background of the various descendants of that div to be white, so they’d mask any flecks they were overlapping.  Thus I wrote:

#main * {background: #FFF;}

It worked great for about a second.  That’s when I realized that I had links in the column, and some of them were sitting inside table rows with a non-white background.  The rule I’d just written was giving the links white backgrounds, which had the visual effect of punching holes in the row backgrounds.  That was no good.

What I really needed was a way to just set white background on elements that were children of #main.  CSS has a child selection combinator (>) but neither version of Internet Explorer supports it.  After a few moments’ thought, I realized that I could add a rule that would make transparent the background of any element that was at least a grandchild, but not a child, and it would still work in Explorer.

#main * {background: #FFF;}
#main * * {background: transparent;}

The end result is that there is a way to simulate child selection without actually using the child combinator.  The general pattern is to use a normal descendant selection in your first rule, and then “undo” the first rule with a second that has a universal selector in the middle.  Suppose you want to boldface any p element that’s a child of a div, but no others.  The solution:

div p {font-weight: bold;}
div * p {font-weight: normal;}

It might not be something you use every day, but if it’s needed, there you go.

Update: Lachlan points out that you’ll need to watch out for specificity conflicts when using this technique.

35 Responses»

    • #1
    • Comment
    • Thu 9 Jun 2005
    • 1835
    Dave S. wrote in to say...

    Holy crap! Awesome!

    • #2
    • Comment
    • Thu 9 Jun 2005
    • 1846
    Dean Edwards wrote in to say...

    It’s so neat it needs a ribbon tied round it.

    • #3
    • Comment
    • Thu 9 Jun 2005
    • 1904
    Oliver wrote in to say...

    Wow that’s very intuitive. It would definitely help a lot in terms of box layouts with a hierchy-like structure.

    • #4
    • Comment
    • Thu 9 Jun 2005
    • 1918
    Chriztian Steinmeier wrote in to say...

    You know, I think that’s absolutely brilliant…

    • #5
    • Comment
    • Thu 9 Jun 2005
    • 1924
    Geoffrey Sneddon wrote in to say...

    This is something I’ve been using for a while but never really thought about it, just thought it was just another CSS thing, and thus never blogged it myself.

    That said, however, I have never really looked into any depth, just used it, I suppose.

    Hope your having a great time in London, and (probably not) see you there on Sunday :P

    • #6
    • Comment
    • Thu 9 Jun 2005
    • 2002
    Daniel Sheppard wrote in to say...

    When using this technique, you must remember that this is that “undoing” rules can be very difficult when you have more than one rule that may be applying to your elements. CSS has no way to tell an element “ignore any other changes to this property”.

    If you have the following markup:

    <div id=”monkey”>
    <div class=”ape”>
    <p>Monkey Paragraph</p>
    <div>
    <p>Monkey Nested Paragraph</p>
    </div>
    </div>
    </div>
    <div>
    <div class=”ape”>
    <p>Normal Paragraph</p>
    <div>
    <p>Normal Nested Paragraph</p>
    </div>
    </div>
    </div>

    The CSS:

    #monkey { font-weight: bold }
    div > p { font-weight: bold }

    Will not be equivalent to:

    #monkey { font-weight: bold }
    div p { font-weight: bold }
    div * p { font-weight: normal }

    Normally, it’s easy enough to pump in enough extra rules to make it work, but don’t expect it to work like a real child selector.

    • #7
    • Comment
    • Thu 9 Jun 2005
    • 2015
    Angus Turnbull wrote in to say...

    I did a similar thing when wrangling the CSS layout for a menu system built from UL/LI tags (outermost ). Basically:

    .menu, .menu ul { /* All menus absolutely positioned */ }
    .menu li { /* Float horizontally */ }
    .menu ul { /* Offset vertically */ }
    .menu ul li { /* Stack vertically */ }
    .menu ul ul { /* Offset horizontally */ }

    It’s an easy first-level horizontal menu with dropdowns underneath, and all subsequent levels consist of vertically stacked items in menus offset to the right, like a standard OS menubar.

    P.S. I’ve revised my PNG fix script, it didn’t correctly handle PNG images from imported stylesheets before, so if you want to try it again with S5 feel free :).

    • #8
    • Comment
    • Thu 9 Jun 2005
    • 2056
    Eric Meyer wrote in to say...

    Daniel: good point; these aren’t precisely equivalent, although I suspect that in 99% of cases, they’re close enough to be satisfactory.

    However, in the example that you give, I wouldn’t use a child selector at all, let alone try to replace it with the technique I described. Instead I would use a plain descendant selector (div p) since it more efficiently meets the given case.

    • #9
    • Comment
    • Thu 9 Jun 2005
    • 2103
    Conann wrote in to say...

    That is cool! and I know I am going to need it very soon THX

    • #10
    • Comment
    • Fri 10 Jun 2005
    • 0351
    Chriztian Steinmeier wrote in to say...

    Uh-oh, Eric – what very misleading title for a post that has nothing to do with universally replacing your children, which by the way, no-one should ever be searching Google for anyways :-)

    • #11
    • Comment
    • Fri 10 Jun 2005
    • 0804
    Lachlan Hunt wrote in to say...

    I thought that was always the obvious solution, I’ve used it several times before. However, it does get annoying because it can have unintended side-effects, thanks the the specificity of ‘the undo rule’, which may unintentionally override the styles of any descendant element.

    • #12
    • Comment
    • Fri 10 Jun 2005
    • 1138
    Eric Meyer wrote in to say...

    Could you explain what you mean, Lachlan? The specificity of the first rule and the second are precisely identical, which is why they’re written in that order (something I probably should have clarified in the post). So I’m being a bit dim, perhaps, but I’m not sure what you’re saying.

    • #13
    • Comment
    • Fri 10 Jun 2005
    • 1229
    Mark Priestap wrote in to say...

    @Chriztian lol! I was thinking along those lines.

    • #14
    • Comment
    • Fri 10 Jun 2005
    • 2125
    Lachlan Hunt wrote in to say...

    Eric,
    Say, for example, you have another rule in your stylesheet that sets the background and color of all <a> elements, together with your rules from above, like this:

    #main * {background: #FFF;}
    #main * * {background: transparent;}
    a { background-color: green; color: white; }

    Assume that were applied to this markup:

    <div id="main">
    <p>This is a <a href="#">test</a>.</p>
    </div>

    Because the specificity of the #main * * rule you provided is higher than that of this rule, any a element within that section will end up with a transparent background and white text. That also illustrates why it’s vitally important to always set a color whenever you set background-color.

    The easy way to fix this is to either increase the specificity of the problematic rules, or use !important. However, this result does not occur when using the child combinator like #main>* for the same purpose.

    • #15
    • Comment
    • Sat 11 Jun 2005
    • 0025
    Eric Meyer wrote in to say...

    Ah, I see. Thanks for the clarification. That’s definitely something to keep in mind when using this technique.

    • #16
    • Comment
    • Sat 11 Jun 2005
    • 1339
    Faruk Ateş wrote in to say...

    Eric, a great solution to a tricky problem. With Lachlan’s warning, I’m sure a lot of people will find good use for this technique.

    Top notch!

    • #17
    • Comment
    • Sat 11 Jun 2005
    • 1402
    Jens Meiert wrote in to say...

    In fact an uncommon solution, so it’s good that you documented it.

    • #18
    • Comment
    • Mon 13 Jun 2005
    • 2110
    Jeremy Arnold wrote in to say...

    This is along the lines of a problem I have been working on for the last few months.

    Basicly, I wan’t to be able to set the base font size for an entire CMS based website using EM’s … I’m already using percentage font sizes on body to make fontsizes the same across multiple browsers.

    The rule
    p, td, th, div, span { font-size:0.8em }
    would seem to fit untill you relise that em’s are relative, so
    <div>Correct size <p>0.8 x correct size (aka Tiny!)</p></div>

    Hopefully I should be able to use this psudo child selector to actually get this to work.

    Something like adding
    p *, td *, th *, div *, span * { font-size:inherit }
    Though, I know that isnt going to work right….

    • #19
    • Comment
    • Mon 13 Jun 2005
    • 2218
    Mike Purvis wrote in to say...

    Would it work/be better to use inherit in place of transparent?

    In the case of text, it’s usually going to be transparent, but last thing you’d want to do is cause frustration down the road when you’re trying to do a 37signals highlight and the css is overriding the yellow. (or whatever, that’s just a random example)

    • #20
    • Comment
    • Tue 14 Jun 2005
    • 1257
    Joël Kuiper wrote in to say...

    Damn why didn’t I think of that. Good work!

    • #21
    • Comment
    • Wed 15 Jun 2005
    • 0133
    Paul Noone wrote in to say...

    Like Jeremy Arnold above I recently decided to make the same conversion from fixed and percentage widths to EMs. I, too, have had a hard time trying to set a standard font-size across my site using EMs. So what is the correct markup for this?

    Surely something so essential MUST have a common solution. Or should we perhaps be using EXs?

    I know there are many schools of thought in this regard but surely the experts must all agree on a few basic requirements.

    • #22
    • Comment
    • Fri 17 Jun 2005
    • 0801
    Jim wrote in to say...

    Jeremy, you don’t have to specify a font size for each and every element type. If you want to specify an overall font size, set it for body and that is all you need to do.

    Speaking as a user, why do you want to reduce overall font size anyway? I’ve got a perfectly good font size configured in my browser, if you mess with it, you make things less readable for me.

    • #23
    • Comment
    • Fri 17 Jun 2005
    • 0804
    Jim wrote in to say...

    Paul:

    body { font-size: [put your font size here]; }

    That is all you need, unless you want to mess with the font size of form elements, in which case also use something like:

    * { font-size: inherit; }

    Like I said above though, the most user-friendly approach is simply to leave the base font size alone and just specify the relative sizes of elements like headings.

    • #24
    • Comment
    • Fri 24 Jun 2005
    • 1710
    Joe Kwon wrote in to say...

    Took me a while, but I get it. This is pretty clever.

    • #25
    • Comment
    • Mon 27 Jun 2005
    • 0632
    Tim Jones wrote in to say...

    One thing – beware of the use of the universal selector on constrained devices as they can cause significant performance problems to the UE – not much of an issue on a monster desktop gaming machine but germane for mobile & portable devices.

    • #26
    • Comment
    • Thu 30 Jun 2005
    • 1102
    Jeff wrote in to say...

    Eric,

    I read this when you first posted it, and today found myself needing this solution, as Firefox was working beautifully but only because I was using child selectors.

    Wait a minute, I thought….Eric wrote a solution to this recently. And sure enough, it worked out great.

    Thanks!

    • #27
    • Comment
    • Wed 26 Oct 2005
    • 0922
    pecus wrote in to say...

    this is an interesting behaviour. However, it does not replace the child selector in cases where you need to reach the first element after another, in the same container.
    i.e, styling ul when after h2:

    <div id="#content">
    <h2>title</h2>
    <ul>
    <li>item</li>
    </ul>
    </div>

    • #28
    • Comment
    • Wed 26 Oct 2005
    • 0936
    pecus wrote in to say...

    Sorry, I had in mind adjacent sibling selectors (+) and mistakengly searched for a workaround in IE for child selectors. Eric, if you manage to devise a workaround for sibling selectors, we’d all be most grateful!

    • #29
    • Pingback
    • Thu 24 Nov 2005
    • 1157
    Received from deFUNKT blog » Small CSS tips you may already know (2)

    […] ont-weight: bold;} div * p {font-weight: normal;} I saw this trick for the first time on Meyerweb, so that’s where the credit […]

    • #30
    • Comment
    • Sun 11 Dec 2005
    • 0333
    nikko wrote in to say...

    Amazing! You saved me hours. =)

    • #31
    • Pingback
    • Sun 1 Jan 2006
    • 1607
    Received from Max Design - standards based web design, development and training » Blog Archive » Some links for light reading (13/6/05)

    […] t reading (13/6/05)

    June 13th, 2005
    The ways to style visited links Universal Child Replacement Scrolling drop shadows Building a page te […]

    • #32
    • Comment
    • Tue 11 Jul 2006
    • 0932
    Vladimir wrote in to say...

    hi eric,
    may be you know how to solve a problem with one child and many daddies

    can you reduce this?
    #thistory .subnav A, #whistory .subnav A

    • #33
    • Comment
    • Wed 10 Sep 2008
    • 1726
    AaronNGray wrote in to say...

    AFAICS This does not deal with tree controls. Well only to a certain depth :(

    I wrote a tree control that only works on FF, Opera, Safari, and Google. But to find it did not work on IE ! :(

    Have to rewrite and refactor the JavaScript !

    • #34
    • Pingback
    • Fri 6 Mar 2009
    • 0307
    Received from six03 » CSS Notes - Vol. 1

    […] I have been referring myself to Eric Meyer’s Universal Child Replacement Technique. […]

    • #35
    • Comment
    • Wed 19 May 2010
    • 1323
    Kevin wrote in to say...

    Eric,

    I’ve documented a few other methods for emulating child selectors (not universally) here: http://craftycode.wordpress.com/2010/05/19/emulating-css-child-selectors-in-ie6/

    This includes a little trick to deal with nested classes, too.

Leave a Comment

Line and paragraph breaks automatic, e-mail address required but never displayed, HTML allowed: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>



Remember to encode character entities if you're posting markup examples! Management reserves the right to edit or remove any comment—especially those that are abusive, irrelevant to the topic at hand, or made by anonymous posters—although honestly, most edits are a matter of fixing mangled markup. Thus the note about encoding your entities. If you're satisfied with what you've written, then go ahead...


May 2005
SMTWTFS
April June
1234567
891011121314
15161718192021
22232425262728
293031  

Sidestep

Feeds

Extras