Introduction to Combinator Selectors
In addition to selecting elements with basic selectors such as classes and ids, CSS also categorically has another set of selectors called combinator selectors, which are inherently a more complex form of selection, or at least compared to the ones covered in the previous lesson.
These combinator selectors include the adjacent sibling combinator, the general sibling combinator, the child combinator, and the descendant combinator, all of which are going to be covered in this lesson.
Setting Up the HTML
In my index.html, inside my body element, we're going to begin by adding an h1 element, an h2, an h3, h4, h5, and h6.
I'll press and hold the alt key on my keyboard, and with my mouse, I'll click to add a selection inside each one of my heading elements, and I'll have all of them display hello world. I'll also give all of them a class attribute, the h1 element with the class of h1, the h2 element with the class of h2, and I'll just fast forward for the rest.
Now that we have some elements to work with, I’ll head over to my CSS file.
Understanding Combinator Selectors
Now we're familiar with selecting elements directly by their class name for example, but combinator selectors work a bit differently. The purpose of a combinator selector is to combine two individual selectors, and leverage their relationship to select the second selector.
This is going to make more sense if I show you an example, and we're going to begin with the adjacent sibling combinator.
The Adjacent Sibling Combinator (+)
The adjacent sibling combinator is actually the plus symbol, which I'll add immediately, and what this combinator selector wants to do, is select an element only if it is positioned immediately after another..
So for example, let's say I wanted to select the h2 element, only if it was defined after the h1 element..
To compose this rule, against our adjacent sibling combinator, we select the h1 element on the left hand side, and then we select the h2 element on the right hand side. This selection is saying, select the right hand side element, only if it is defined immediately after the left hand side element. Or in other words, select the h2 element only if it is defined immediately after the h1 element.
Inside curly braces, I'll add a color of red, and when I save, we see, our second heading is now red. If we look at our index.html, we see, our h2 element is in fact defined immediately after the h1, which is why our ruleset is working, but if I go back to my CSS file, and change the right hand side selector from h2 to h3, and save, we see, our color of red is just not being applied at all, because the condition of our adjacent sibling combinator isn't true. The element being selected on the right hand side of this adjacent sibling combinator, needs to be adjacent to the element selected on the left hand side, if not, this entire ruleset is ignored.
The adjacent sibling combinator only works if the target element comes immediately after the first element. If there’s anything in between, the rule won’t apply.
The General Sibling Combinator (~)
Now our next combinator selector is the general sibling combinator. Unlike the previous selector, the general sibling combinator can select any sibling element, without them needing to be adjacently positioned.
For example, we're currently attempting to select our h3 element, but since it isn't defined immediately after the h1, our entire ruleset isn't being applied..
If I replace the adjacent sibling combinator with the general sibling combinator, the general sibling combinator being the tilde symbol, and save, we see, the condition of our general sibling combinator is being met, our ruleset is being applied, and our h3 element is now therefore red.
I can now select any sibling element I want.. If I select the h4 element, and save, we see, our h4 is now red, and if I select the h5 element, and save, we see, our h5 is now red..
Now although the element we select on the right hand side of our general sibling combinator, no longer needs to be adjacently positioned to the element selected on the left hand side, our right hand side element still needs to be a sibling to the left hand side element.. and what that means, is if I go to my index.html, and wrap a div around my h4, h5, and h6 elements, and save, we see, our h5 element in our live server is no longer red.
With the h4, h5, and h6 elements wrapped inside a div, they’re no longer siblings to the h1, h2 and h3 elements, and with them no longer being siblings, back in my CSS, the condition of our general sibling combinator isn't being met, and this entire ruleset is therefore being ignored.
For the general sibling combinator to work, the target element must still be a sibling in the same parent element. Wrapping elements inside another container breaks this relationship.
If I try selecting the h4 element, and save, we see, it still doesn't work because the h4 element, just like the h5 element, was wrapped inside a div and is therefore no longer considered a sibling to the h1 element.
But if I try selecting the h3 element, and save, we see, our h3 element is red, because back my index.html, we see, the h3 element isn't inside the div, and is a sibling to the h1 element.
With the general sibling combinator, elements need to siblings, otherwise it won't work, but this is a good segue into our next combinator selector, the child combinator.
The Child Combinator (>)
Unlike our two previous combinator selectors, whom both required elements to be siblings, the child combinator exists specifically to select elements that direct children of a parent element.
So with the child selector we're now stepping away from a sibling relationship, into a parent child relationship, and an example of a parent child relationship in our HTML, is our div and heading elements inside it.
This div is a parent to the h4, h5, and h6 elements, and these heading elements are children to this div element.
Inside our styles.css file, I'll replace the h1 selector with our div, I'll replace the tilde symbol for the greater than symbol, because a greater than symbol is how to invoke the child combinator selector, and I'll replace the h3 selector for the h4 selector.
Now with the child combinator, we're saying look inside div elements, and find the elements with the h4 class name. When I save, we see, our h4 element is now red. If I try selecting the h3 element instead, and save, we see, it doesn't work, because our h3 element isn't inside our div, so I'll undo my changes.
The child selector only selects direct children, but this is very important, they need to be a direct children of the parent, they cannot be nested further down somewhere else, they cannot be grandchildren.
So for example, in my index.html, inside my div, I’ll add an unordered list with a list element, and inside it, I’ll copy my h4 element and paste it inside.
When I save, we see my h4 element inside the unordered list isn’t red, only the h4 element that is a direct child of our div is red, and this is because the child selector only selects elements that are direct children, it doesn't select grandchildren.
The child combinator (>
) only matches direct children. Nested elements
further down (grandchildren or deeper) are ignored.
The Descendant Combinator (space)
Now this leads us to our last combinator selector, the descendant combinator selector, and this selector is just like the previous one, but it does allow us to select elements that are deeply nested as grandchildren.
In my CSS, I'll remove the greater than symbol, and just leave a space. This empty space between both selectors is actually a combinator selector, the descendant combinator selector, and when I save, we see, both h4 headings are being given the color of red, regardless of how deeply nested they might be.
The descendant combinator (a space) is the most flexible—it matches all levels of nesting, not just direct children.