Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

CSS CSS Selectors Going Further with Attribute Selectors and Pseudo-Classes :only-child and :empty

:only-child no working as expected?

When I add <h1> as another child of <body> in addition to <ul>. The pseudo selector still applies the effect, but only font-size takes place. Color property does not apply, though.

It's supposed to be like the instruction video where neither of them get the effect of :only-child. But here, one property applies while another one is ignored. This is so confusing to me.

HTML:

<!DOCTYPE html>
<html>
<head>
    <title>Selectors</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link href='http://fonts.googleapis.com/css?family=Nunito:400,300' rel='stylesheet' type='text/css'>
  <link rel="stylesheet" href="css/style.css">
    <style>
        body {
            font-family: 'Nunito', sans-serif;
            color: #616161;
            padding: 40px 0;
        }
        h1 {
      text-align: center;
    }
        ul {
            list-style: none;
            width: 50%;
            margin: auto;
        }
        li {
            border-bottom: 1px dotted #40918c;
            padding: 15px 10px;
        }
    </style>
</head>
<body>
  <h1>My List:</h1>
    <ul>
        <li>Item 1</li>
        <li>Item 2</li>
        <li>Item 3</li>
        <li>Item 4</li>
        <li></li>
        <li>Item 6</li>
        <li>Item 7</li>
        <li>Item 8</li>
        <li>Item 9</li>
        <li>Item 10</li>        
    </ul>
</body>
</html>

CSS:

/* Structural Pseudo-classes------------------ */

li:first-child {
  background-color: #52bab3;
  color: white;
}

li:last-child {
  border: none;
}

:only-child {
  color: #52bab3;
  font-size: 1.5em;
}

:empty {
  background-color: tomato;
}

Snapshot if you want to look at: https://w.trhou.se/gy28p8x7fe

1 Answer

andren
andren
28,558 Points

I don't know when this video was recorded but looking at the documentation for the :only-child selector it does appear that there has been a small (but somewhat significant) change in how it works since it was introduced.

That change is that originally it only targeted elements that had a parent element, in the new revision it does not have this requirement, it will select any non-sibling element regardless of whether it has parents or not.

This is significant because it causes it to actually target the html element, since that is technically speaking an element which has no sibling. And since font-size is a property that can be inherited the h1, ul and li elements end up inheriting the font-size from the html element.

The color property is not inherited due to the fact that you specify a color for the body element inside the style tag, so the h1, ul and li elements ends up inheriting their color from that instead.

If you change your selector so that it only applies to elements within the body element like this:

/* Do note the space between body and :only-child, that is required and not a typo */
body :only-child {
  color: #52bab3;
  font-size: 1.5em;
}

Then it should act the same way that it does in the video.

The space is needed because this is a descendant selector that targets elements with no siblings within the body element. If you had no space between the selectors like this body:only-child then the selectors would instead be combined and only target elements with a tag of body which have no siblings.

Edit: Added extra info on the space in the selector.

You're right Andren. Your solution works, which means that :only-child expands to target <html>, not only <body> anymore.

The inheritance concept explaining the mess-up with color property is so interesting. Is it because internal style takes precedence over external style?

Most of the pseudo selectors appear right after the regular selector without space. :only-child is somewhat different. I tried with ul:only-child, and it didn't work out because of the wrong syntax. With the space between them, it now works as expected!

andren
andren
28,558 Points

You're right Andren. Your solution works, which means that :only-child expands to target <html>, not only <body> anymore.

The way that I originally discover this is actually that I used the Chrome Developer tools to inspect the elements in your page. If you are using chrome you can right-click on an element and select "Inspect" doing so will open up a window with a lot of information about the HTML and CSS on the page. Including information about exactly what styles are being applied to a particular element and where those styles are coming from.

The inheritance concept explaining the mess-up with color property is so interesting. Is it because internal style takes precedence over external style?

Not quite, while it is true that internal styles have a higher priority than external ones that only applies to duplicate rules that have the same priority, and it doesn't really have anything to do with inheritance.

The way inheritance works is that there are some properties which are inherited which means that if an element does not get that property explicitly set then instead of having a default value set it will instead inherit that it's value from it's parent, if the parent does not have that property set then it will inherit it from it's parent and so on.

So in the case of font-size in your code no element had it set explicitly expect the html element, so all of the elements ended up inheriting it from that. With color the body had is set explicitly so the children of the body element ended up inheriting it from that instead. This means that if you removed the color property from the body element then they would inherit that from the html element too.

Most of the pseudo selectors appear right after the regular selector without space. :only-child is somewhat different. I tried with ul:only-child, and it didn't work out because of the wrong syntax. With the space between them, it now works as expected!

That's because the space changed what type of selector it is. Without a space you are combining two separate selectors together. In the case of ul:only-child you are combining a tag selector and a psuedo selector. The result is that CSS will only target elements that are both an ul and an :only-child. With the space added you are creating a descendant selector. So "ul :only-child" creates a selector that targets all :only-child elements that are descendants (children, grandchildren, etc) of an ul element.

This applies to all other types of selector as well, typing them without a space always combines them, while using a space creates a descendant selector.

Sorry for the overly long post, just thought I'd try to clarify some things.