Design & UX
By Chris Sealey

Better Semantics with CSS Combinators & Selectors

By Chris Sealey

I’m going to begin with a provocative claim: I believe CSS is one of the most difficult-to-master computer languages we have. It doesn’t have a complex syntax and you certainly don’t need a doctorate in IT to understand it. However, it’s one of the only popular languages that isn’t “logical”—and I mean that in the most literal sense.

Unlike other familiar web development languages such as JavaScript, PHP or even SQL, problems aren’t worked out via common logic. Spoken algorithms like “if X then do Y, otherwise do Z” or “select all of Y then do X with them” don’t translate to a language like CSS. Simply put; it’s a styling language. A language for designers, not developers. Some of the most experienced programmers I’ve worked with struggle to comprehend CSS for this very reason.

The Cascade is a metaphorical term for the syntax behind CSS. It calculates elements such as origin, specificity, order and importance by using special glyphs, known as combinators, to target elements (and pseudo-elements) and style them accordingly. No single article could do CSS syntax the justice it deserves—that’s what W3 Specs and Dan are for. However, assuming you already know a thing or two about CSS, let’s examine some lesser-known combinators and not how, but when to use them.

At design school we were all taught about classes and IDs, using . and # respectively, to directly target elements. That’s enough control to build a functional website—but it’s not flexible enough to handle a complete design shift. It also creates a lot more work than needed by using presentational values within markup. Let’s take a look at an alternative approach to targeting those difficult-to-get-to elements.

The Adjacent Sibling Combinator

We’ll kick things off with a selector that’s nice to use in subtle situations—employing the adjacent sibling combinator. The adjacent sibling combinator is denoted by connecting two elements with a + symbol:

h1 + p

This will select all p elements that appear directly after an h1 element in the DOM. Typographic theory suggests that we should indent paragraphs in body copy, but only if they succeed another paragraph. A practical use for this selector, then, is to add text-indent values to paragraphs without targeting the first in a tree, like so;

p + p {
    text-indent: 1em;

That beats styling all paragraphs with text-indent and zeroing out the first one with class="first" any day. Three lines, no classes and solid browser support. If you’re nesting your content-level img tags inside your p tags (and you should be) then we can simply pull their left margins back with a negative value of -1em:

p + p img {
    margin-left: -1em;

Simple enough, right? What if we wanted to style the first line of all paragraphs that directly follow a heading, without affecting any other paragraphs? Once again, we can refrain from using a presentational class to do this. A simple selector made up of the adjacent sibling combinator and a pseudo-element will do the trick:

h1 + p::first-line {
    font-variant: small-caps;

Note: while :first-line is a CSS 2.1 approved pseudo-element, the :: notation has been introduced at CSS level 3 in order to establish a discrimination between pseudo-classes and pseudo-elements.

The Child Combinator

A common markup protocol is to wrap your top-level sections in an element named something along the lines of #page or #wrap:

<div id="page">

        <section id="main"></section>


Regardless of whether you’re using HTML 5 or XHTML 1.1 syntax, this basic format should look familiar to you. If you’re running a fixed-width of 960px and aligning your document to the centre with each element horizontally filling the wrapper, your CSS likely resembles:

#page {
    width: 960px;
    margin: 0 auto;

footer { width: 100%; }

Or perhaps you’re being a bit more specific and prefixing with the #page parent to avoid hitting them when/if outside of this selection:

#page header,
#page article,
#page footer { width: 100%; }

There’s a better way. We’ve all seen the universal element selector; *, likely through a browser reset or similar. When we combine this with the child selector, we can target all elements that are direct descendants of #page without hitting their grandchildren or beyond:

#page > * { width: 100%; }

This will future-proof our document if we ever want to add or withdraw elements from the top-level structure. Referring back to our original markup scheme, this will hit the header, article and footer elements without touching #main and aside within article.


String and Substring Attribute Selectors

Attribute selectors are one of the most powerful we have. They too have been around to some degree since CSS 2.1 and are commonly found in the form of input[type="text"] or a[href="#top"]. However, CSS3 introduces a deeper level of control in the form of strings and substrings.

Note: up until this point, everything we’ve discussed has been CSS 2.1 standard, but we’re now stepping into CSS3 territory. We’ll leave it at the presentational layer, so it’s OK to use these right now.

We have four primary attribute string selectors available to us, where ‘v’ = value and ‘a’ = attribute:

  • v is one of a list of whitespace-separated values: element[a~="v"]
  • a begins exactly with v: element[a^="v"]
  • a ends exactly with v: element[a$="v"]
  • a contains value: element[a*="v"]

The potential for attribute string selectors is almost endless, but a perfect example is iconography. Perhaps you have an unordered list of links to your social media profiles:

<ul id="social">
    <li><a href="">Like on Facebook</a></li>
    <li><a href="">Follow on Twitter</a></li>

    <li><a href="">RSS</a></li>

Styling these is as simple as running a substring query through their href attribute to find a keyword. We can then progressively enhance these links, like so:

#social li a::before {
    content: '';
    background: left 50% no-repeat;
    width: 16px;
    height: 16px;

#social li a[href*="facebook"]::before {
    background-image: url(images/icon-facebook.png);

#social li a[href*="twitter"]::before {
    background-image: url(images/icon-twitter.png);

#social li a[href*="feedburner"]::before {
    background-image: url(images/icon-feedburner.png);

Similarly, we can target all links to PDF documents with the suffix substring selector:

a[href$=".pdf"]::before {
    background-image: url(images/icon-pdf.png);

Browsers that don’t support CSS3 attribute substrings won’t display these icons, but that’s OK—they’re not essential to functionality, they’re just a “nice-to-have”.

Structural Pseudo-Classes

Lastly, I want to outline the benefits of structural pseudo-classes, not to be confused with pseudo-elements or link and state pseudo-classes. We can use these to target elements based on their position within the DOM, rather than their contents. A fine example of when to use a structural pseudo-class can be to target the first (or last) element in a tree of elements, or to alternate between odd and even elements:


    <li>List Item 1</li>
    <li>List Item 2</li>
    <li>List Item 3</li>
    <li>List Item 4</li>

    <li>List Item 5</li>
    <li>List Item 6</li>

ul li { border-top: 1px solid #DDD; }
ul li:last-child { border-bottom: 1px solid #DDD; }
ul li:nth-child(even) { background: #EEE; }

Note: :first-child is the only pseudo-element available in the CSS 2.1 spec. All other pseudo-elements, including :last-child, are CSS3 standards.

The key to structural pseudo-elements, however, is when not to use them. They should be strictly reserved for when selectors relate to the position of an element and not its contents. If an element must be styled in a certain way regardless of its position in the DOM, that’s when you should be using a more meaningful, semantic selector, such as a class, ID or string.


You may already be using some or all of these combinators and selectors today—perhaps in the correct way, perhaps not—but it doesn’t hurt to have a reminder of when you can be using them instead of applying a class or ID to an element. Because that’s something that even the best of us are guilty of.

  • Nice. I’d like to say that I will apply some of these, but fear I might forget, so apologies in advance for the ugly css!

  • Great examples and good explanations of some of the more powerful yet less used CSS functionality.

  • Excellent stuff. I haven’t tried out any of this yet. The Child Combinator part (#page > * { width: 100%; }) was pretty eye opening. I’ll have play with this soon.

    • Just be careful as the > is not supported in older versions of internet explorer.

      • Coljung

        > is supported by IE7+ so guess you are referring to IE6 ?

  • Steinar Kjærnsrød

    Thanks for a very good article! I think many web developers fail to understand both the limitations AND power behind CSS. The key to understand both is to first understand HTML and the DOMs and the way these are tightly connected with CSS. Many fail to see that HTML offers excellent ways of structuring the document, and only think of it as a layout language for web pages. Documents authored this way are often unnecessary complex with deep nesting levels. Since CSS selectors target document structures, it becomes difficult and messy to apply CSS style to such documents since the author didn’t have structure in mind in the first place. 

  • Great primer. Thanks.

  • Very useful primer. Thanks.

  • Jess

    Thanks so much for this! I’m finishing up my last year of a two-year web design degree and articles like this are very helpful for writing clean and efficient CSS.

  • While these are undoubtedly cool, I do think there are potential performance issues with things #page > * {}. Admittedly, I haven’t carried out any tests on these, but I’d be willing to bet that that’s a bigger hit than the alternative. And that’s all before we start to think about browser compatibility. 

    It’s not that I don’t think that you should use all these selectors; it’s just that it’s not as clear-cut as saying that these are be necessity better than what you are suggesting replacing. It’s a matter of using them intelligently. Sometimes it’s better to omit them, or to apply classes through PHP, say, if the content is dynamically generated.

    • John Faulds

      You’re right Patrick. Google PageSpeed recommends against using the universal selector.

  • bob young

    This opens a whole new way of styling for me.  Probably reducing my stylesheets by half the number of rows.  Thanks for the article.

  • Tuomas L

    Possible one of the best CSS related articles I’ve ever read. Simply fantastic.

  • Ron

    Loved the article, excellent tutorial. I tried the Structural Pseudo-Classes example in FF4, Chrome and IE9. In FF4 and Chrome the example appears to work properly, where IE9 does not. IE9 is missing the even line shading. Another IE bug? 

    • IE9 has full support for :nth-child(n) as far as I know. But really, does it matter if IE user don’t see such a subtle enhancement? We all know they don’t deserve it!

      • Gerry Danen

        I agree that IE users don’t deserve to have us write crummy work-arounds. Even with the work-arounds, things still hardly look nice…

        Wasn’t Microsoft part of the CSS standards group, and yet they can’t deliver a browser that implements those same standards. Shameful.

      • Anonymous

        Loved the article as it opened my eyes to options that I did not know existed. However, Please be careful when bashing us “IE users” as some of us don’t have a choice. I work for a corporation with 20k employees and we’re stuck using IE6 until new funds come along, and we all know how difficult that is these days. I realize our 20k is a small percentage of the population who actually has the ability to upgrade their version of IE but none the less we still exist.
        Additionally I understand that if you continually provide “crummy work-arounds” people (corporations) will not see the need to upgrade their browsers. Therein lies the need for you to “educated” them and pull them along. I am a new product designer and like you I like riding on the cutting edge but I take a little more subtle approach. I’ll educate people and entice them to use the new product but I will not exclude them.
        I pose this question; How much revenue is lost because you used cutting edge methods (code) and lost customers due to their inability to access or even enjoy their visit to a site you designed? Lost revenue just to make a “subtle enhancement” to a web page!! Not in todays economy.
        Again, Thanks for your article.

  • John_Betong

    I like your list example and looking forward to removing reams of PHP code and replace with a couple your CSS snippets.

  • Dinesh Bharathy

    Amazing article irrespective for beginner or otherwise…

  • Great Article Chris.

    CSS2 and CSS3 are really amazing. Unless IE browsers are banned from this planet we will never get to use these. Even now the website i work for has 50% users from IE browsers.

    • Thanks Suhel,

      Most of these samples will work to some degree in IE—even the older versions. Please also remember that everything I’m talking about here is progressive enhancement. It doesn’t matter that IE doesn’t get the alternative backgrounds, or the icons, or the text-indentation or any similar features. Reward your premium users by giving them a better experience.

      My site only gets 3.8% of it’s users on any version of IE, so it all depends on the target market and how you cater for them. Don’t write messy code just to support those living in the past.

      • graphicus

        Sorry, that’s not an attitude that works in the commercial world outside the deisgn community. Clients want their web pages to look the same across all their customer’s broswers, and there are still businesses using IE6! The proportion that use IE7 is far in excess of 3.8%. The reasons for not updating can be complex in big coporations, and we can sneer and decry it all we like, but te bottom line is we have to deal with the real world if we are going to get paid.

        • I have to disagree with you there. I know very well IE is a significant force and my personal case is extreme, but I’ve worked with my fair share of people outside the design community. I appreciate that clients want their sites to look the same cross-browser, but clients don’t get the web—we do. It’s our job to educate them.

          • I agree that it is our job to educated the clients. Unfortunately sometimes we don’t have the luxury of spending that time because we have to deliver. Weather IE supports this or not does not invalid the fact that we can all use this markup in this way to obtain good results. Thank you very much for spreading the knowledge and may everyone in the world upgrade their damn IE!

          • graphicus

            I wasn’t criticizing the original article, which is very illuminating and useful. It will help focus on a more truly semantic use of CSS. But WRT to Browser support the following article gives an insight into the real worldwide picture.”Microsoft’s IE6 browser has been criticised for being slow, out of date and
            insecure. Although the company has moved to patch major security weaknesses, its
            approach is now to encourage people to upgrade their whole browser to, at least,

            With that ambition in mind, the company has also launched a “countdown”
            website,, to encourage people to
            upgrade and to educate their friends.

            The biggest problem, however, is posed by companies using legacy software.
            Older versions of Windows, for instance, cannot be upgraded to new Internet
            Explorer software. Businesses which rely on programmes built specifically for,
            say, Windows 98, are therefore stuck. In countries where significiant numbers of
            people use relatively old equipment, such as China, it’s therefore not
            surprising that 34.5 per cent of web users are on IE6. Usage in Saudia Arabia,
            Vietnam, Taiwan and India is also above 10 per cent.

            According to Microsoft, “In November 2010, IE6 commercial usage share as
            tracked by Net Applications reached an all-time low at 10.3%. This is actually
            significantly lower than all-up IE6 usage share, which dropped to 14.58% in

            At the time, in China IE6 accounted for 45.2 per cent of browser usage, down
            from 50.5 per cent in August of 2010.”

          • Chris, I agree with you that it’s our job to educate as much as possible. To that point, I ran into a GREAT post with some quick points to help communicate with a client:

            If explained in a logical manner, many (but not all) clients will see how it would be to their advantage to be as progressive as possible, and use those unneeded ‘bug fixing’ dollars elsewhere, perhaps for marketing etc.

        • Dave

          In my opinion, enterprises still using IE6 as the default browser are just incompetent! With today’s virtualization technologies it is pretty easy to setup a virtualized IE6 for the proprietary intranet applications, and use a modern browser as the corporate default.
          Another aspect is security: I think it is grossly negligent to use IE6 in an enterprise environment as the software is very insecure and has security holes!   When I see that there are still some banks using IE6 I get goose bumps.

        • I really don´t know why people have to take a position on this issue, If you have good comunication with your clients, you should be able to work out which browsers you need to support, and to what extent, long before you even get to coding. I´m trying to say this should be judged on a case by case basis.

      • Jamie

         this is not a good mentality to have.

  • As always Chris, brilliant!

  • Webmaster

    Too bad that IE, including in some cases IE8, doesn’t fully support these.  It’s the main reason I don’t use them, much as I would like to at times.  Indeed, for us, IE is still the most-used browser.


  • Interesting post. I read somewhere (don’t remember where) that using css selectors and combinators is the part of css that get’s rendered by the browser the slowest (probably due to ‘real’ calculations needed).
    Have you ever noticed that when relying on them heavily?

    • I’ve got to say I haven’t noticed any difference—I’d accept that there would be one, though minimal. However, I’m talking about literally halving the size of your markup and CSS here, if done properly. Perhaps it balances out?

      • I see – good point. Thanks for the feedback

    • Kanda samy

      Need to be little bit cautious not to overdo, especially the substring attribute selectors. Also I don’t think ie6 supports any of these advanced css selectors discussed here.

  • Sqldummy

    Brilliant article; amazingly useful. Bravo.

  • Fantastic article.

    I work in a bank that still uses IE6 as the corporate standard.  You’d think it was an issue of in-house app compatibility.  It’s not.  Rather, they “can’t justify the cost” of an updated deployment to upper management.  Internal client communication is next to nil.  Something all of us, regardless of our trade, should consider.

  • Luke


    div.footer > ul { float: left; }
    div.footer > ul + ul { float: right; }

    is so much more sensible than the backwards-ness that is:

    p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color: #3508fd}
    p.p2 {margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color: #ad201f}
    p.p3 {margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco}
    p.p4 {margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; min-height: 15.0px}
    span.s1 {color: #ad201f}
    span.s2 {color: #000000}
    span.s3 {color: #3508fd}
    span.Apple-tab-span {white-space:pre}

    div.footer > ul { float: right; }
    div.footer > ul:first-child { float: left; }
    thank you.

  • 3 Roads Media

    Great article. Had no idea about the substring selectors. Thanks!

  • Daniel G

    Amazing post!, I happen to stumble upon it and learned quite a few things.  I have never used the + selector in any of my css, but this will definitely use less coding up to perform the same layout im trying to accomplish with any extra abundance of classes. Thank you!!

  • Peter William Kong

    in reference to this suggestion:

    #page > * { width: 100%; }couldn’t you instead create a class.standard-width { width:960px;}and have all objects inside #page inherit from that? This option seemsDRYer to me, but I’m not a front-end expert, so I appreciate ya’ll’s opinions.

  • Gerry Danen

    Thanks for a very informative article, Chris.
    I will definitively have to apply some of the examples!

  • Thanks Chris.

    I hate that IE8 doesn’t support :last-child. It’s maddening.

  • Ever since the 1990s there has been a concerted attempt in web design to use CSS as a means to separate presentation from content.Often it was the case that web designers were adding extra classes or ids to page elements just so that they could use CSS to alter their design; but with CSS3, the push has been towards minimising HTML markup.CSS combinators assist in this quest but it isn’t just about following, but also about making you a faster, more efficient web designer.

  • Wow, now only if I had access to this nicely written information few months ago, I might have saved so many lines of code.

  • Anonymous

    Find the ideal shoe wholesaler
    best bag wholesaler cheap ladies clothing among our magnificent collection of
    elegant wholesale shoes, wholesale sandals, wholesale flip flops, wholesale
    ballet / ballerina wholesaler
    best kid clothing
    flats, & classy wholesale
    boots for wholesaler cheap men shoes ladies, as well as wholesale men’s shoes,
    cheap men shoes
    & far more. In case you are in
    the marketplace for a sexy high heel stiletto shoe, strappy sandals,
    sophisticated high heels, beautiful thong sandals, cute flip wholesaler cheap
    ladies shoes flop sandals, women’s pumps, wedges, or stylish wholesaler cheap
    child shoes high heel boots, J&M Footwear Inc., a Miami based wholesale
    shoes distributor, is the first place you ought to think about wholesaler
    cheap women clothing
    looking, as our shoe warehouse is
    stocked filled with hundreds of styles. It is wholesaler best child clothing
    here you will always find an ultra stylish collection of men’s & ladies
    dress or casual shoes at amazingly low, cheap wholesale prices.

  • joshy kp

    This is valuable and very informative for a Web designer who are yet go to the advanced CSS tricks.

    Other thing is, this article is simple and with examples, so easily we will get what we want.

    Nicely done.. Good job..

    Sharing knowledge is a remarkable thing.

  • AK


    I found that “#social li a::before” needs:
    “display: inline-block;” to work properly or w/h aren’t set.


Get the latest in Design, once a week, for free.