Contiguous Sibling Selector

    James Edwards
    James Edwards
    Share

    Every now and then I have an idea for a new CSS selector that solves a particular problem. A while ago I thought of the Regex-matching Attribute Selector, which matches attribute values according to a regular expression. Recently, I had another idea, inspired by a project I was working on at the time—what I’ve chosen to call the Contiguous Sibling Selector. To examine how it works, let’s begin with an HTML code example we can refer to as we go along:

    <div>
        <h2>First heading</h2>
        <p>First paragraph</p>
        <p>Second paragraph</p>
    
        <h3>Second heading</h3>
        <p>Third paragraph</p>
    </div>
    CSS currently provides two sibling selectors. The first of these is the Adjacent Sibling Selector, which selects the first sibling element of a specified type (or other selection), that follows the first within the same parent context:
    h2 + p { ... }
    So, in our HTML example, it would select the first paragraph that immediately follows the first heading, but not the second paragraph after that, nor the third that follows the second heading. Then there’s the General Sibling Selector, which selects all sibling elements that follow the first within the same context, and would therefore select all three paragraphs in the code example:
    h2 ~ p { ... }
    Between those two extremes there’s a third possibility—it would select the first two paragraphs, but not the third; in other words, contiguous siblings. It could look like this:
    h2 ~+ p { ... }
    We could express that situation with this combination selector:
    h2 + p, h2 + p + p { ... }
    But as is often the case, that’s only ideal when the number of elements involved is small and known
    ; what if it were much large—like a dozen or more elements? What if the number of elements were unknown, and could amount to hundreds? You could end up with selectors that make this one look compact:
    h2 + p,
    h2 + p + p,
    h2 + p + p + p,
    h2 + p + p + p + p,
    h2 + p + p + p + p + p,
    h2 + p + p + p + p + p + p,
    h2 + p + p + p + p + p + p + p,
    h2 + p + p + p + p + p + p + p + p,
    h2 + p + p + p + p + p + p + p + p + p,
    h2 + p + p + p + p + p + p + p + p + p + p,
    h2 + p + p + p + p + p + p + p + p + p + p + p,
    h2 + p + p + p + p + p + p + p + p + p + p + p + p { ... }
    And it’s precisely for this situation that I came up with the idea. I wanted a pure CSS component for a show/hide mechanism for the sections in a technical manual. The manual markup was structured as a series of level-two headings, each followed by one or more paragraphs (like the first part of the code example seen here). The paragraphs are all hidden by default, so at first all you see is the headings. You view the content that follows each one by clicking on the heading, and that behavior is handled by scripting. But you can also come to the page with a URL containing a hash, which matches a heading ID, so that it jumps straight to that section, and I wanted that section to display automatically; for instance, to show (and only show) every paragraph that follows the specific heading. Since each section could contain dozens of paragraphs, it seemed excessive to define that with adjacent sibling selectors—one for each possible paragraph like the bulky example above. And, of course, the general sibling selector wouldn’t do the job, because it would select all
    the paragraphs in all the following sections, rather than just the target section. So, eventually, I did that with scripting too. But I can’t help but remember how easy it would’ve been if only I’d had that contiguous sibling selector:
    h2 ~+ p { display:none; }
    
    h2:target ~+ p { display:block; }

    Thumbnail credit: mortimer?

    Frequently Asked Questions (FAQs) about Contiguous Sibling Selector

    What is the difference between the general sibling combinator and the adjacent sibling combinator?

    The general sibling combinator () and the adjacent sibling combinator (+) are both used to select sibling elements in CSS. However, they function differently. The adjacent sibling combinator (+) selects only the first sibling that directly follows the first element. On the other hand, the general sibling combinator () selects all siblings that follow the first element, not just the immediate one. This means that the general sibling combinator can select multiple elements, while the adjacent sibling combinator can only select one.

    How can I use the contiguous sibling selector to style multiple elements?

    The contiguous sibling selector, also known as the adjacent sibling combinator, can be used to style multiple elements by chaining them together. For example, if you want to style all paragraphs that directly follow a heading, you can use the following code:
    h1 + p {
    color: red;
    }
    This will apply the style to the first paragraph that directly follows each heading.

    Can I use the contiguous sibling selector with pseudo-classes?

    Yes, the contiguous sibling selector can be used with pseudo-classes. For example, you can use it with the :hover pseudo-class to change the style of an element when the mouse pointer is over a sibling element. Here’s an example:
    button:hover + p {
    color: blue;
    }
    In this case, the paragraph that directly follows a button will change color when the button is hovered over.

    What happens if there are no matching sibling elements?

    If there are no matching sibling elements, the contiguous sibling selector will not select any elements. The styles defined in the CSS rule will not be applied to any elements. This is because the contiguous sibling selector only selects the first sibling that directly follows the first element, and if there is no such sibling, no elements are selected.

    Can the contiguous sibling selector be used to select previous siblings?

    No, the contiguous sibling selector cannot be used to select previous siblings. It only selects the first sibling that directly follows the first element. If you need to select previous siblings, you would need to rearrange your HTML elements or use JavaScript.

    Is the contiguous sibling selector supported in all browsers?

    Yes, the contiguous sibling selector is widely supported in all modern browsers, including Chrome, Firefox, Safari, and Edge. However, it may not be supported in older versions of these browsers or in Internet Explorer.

    Can I use the contiguous sibling selector with other combinators?

    Yes, the contiguous sibling selector can be used in combination with other CSS combinators. For example, you can use it with the child combinator (>) to select an element that is both a direct child and a direct sibling of another element.

    How does the specificity of the contiguous sibling selector compare to other selectors?

    The contiguous sibling selector has the same specificity as other combinators and attribute selectors. It has lower specificity than ID selectors, pseudo-classes, and class selectors, and higher specificity than type selectors and universal selectors.

    Can I use the contiguous sibling selector to select elements based on their attributes?

    Yes, you can use the contiguous sibling selector in combination with attribute selectors to select elements based on their attributes. For example, you can select the first sibling with a specific attribute that directly follows another element.

    Can the contiguous sibling selector select non-adjacent siblings?

    No, the contiguous sibling selector can only select the first sibling that directly follows another element. If you need to select non-adjacent siblings, you would need to use the general sibling combinator (~).