18

If I have this HTML, how can I select all elements between #one and #two with CSS? I can't use jQuery.

<p id="one"></p>
<p></p>
<p></p>
<p></p>
<p></p>
<p></p>
<p id="two"></p>
TylerH
  • 20,799
  • 66
  • 75
  • 101
Harmstra
  • 433
  • 1
  • 5
  • 15

4 Answers4

15

The ~ general sibling combinator is what you are looking for

#one ~ p:not(#two) {
  color: red;
}

So what the above selector does is, it starts selecting all the p elements which are adjacent to #one till #two and later, I use :not() pseudo to exclude the last p:

#one ~ p:not(#two) {
    color: red;
}
<p id="one">0</p>
<p>1</p>
<p>2</p>
<p>3</p>
<p>4</p>
<p>5</p>
<p id="two">6</p>

JSFiddle

Mr. Alien
  • 153,751
  • 34
  • 298
  • 278
7

Given two elements that are siblings (i.e. have the same parent), it is not possible in Selectors 3 to write a selector that matches elements between them if the structure of elements is not known (or if it is known to change).

In Selectors 3, you can only match the elements between them if either or both of the following is true:

  1. The tree position of the two elements relative to their parent is known.

    For example, if #one is always the first child and #two is always the last child, this is easy enough:

    #one ~ p:not(#two)
    

    or

    #one ~ p:not(:last-child)
    

    (Note that I don't include :not(:first-child) because the ~ combinator already ensures that the first matching element is never the first child — you may want to include it for the additional specificity or even just for the sake of clarity.)

    If #one is always the second child and #two is always the fifth child:

    #one ~ p:not(:nth-child(-n+2)):not(:nth-child(n+5))
    

    If #one is always the second child and #two is always the third last child:

    #one ~ p:not(:nth-child(-n+2)):not(:nth-last-child(-n+3))
    
  2. The number of elements to match is known.

    Note that if #1 is true you should use the techniques described in #1, not here. The following technique is extremely tedious and is meant to be a last resort for when #1 is not true.

    If there will only ever be n elements between #one and #two, you will need to build a list of selectors beginning with #one, adding + p to each successive selector up to n times.

    For example, if there will only ever be three p elements between #one and #two:

    #one + p,
    #one + p + p,
    #one + p + p + p
    

In Selectors 4, assuming #one and #two are unique as in a conforming document, the following selectors are robust (i.e. they work for any structure of elements, even if it is known to change):

#one ~ p:has(~ #two)

or

#one ~ p:not(#two, #two ~ p)

Use :has() in jQuery and other non-CSS contexts where it is supported, and :not() in CSS (where :has() with the ~ combinator is not expected to be supported). The latter currently works in Safari; it is not yet known when it will ship in other browsers.

Community
  • 1
  • 1
BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
  • I was originally going to post this answer with Stack Snippets, but [this bug](http://meta.stackoverflow.com/questions/313463/preview-in-list-items-is-off) makes it extremely difficult to do so. I'll do it later, when it's fixed. In the meantime, the examples should be easy enough to understand. – BoltClock Mar 04 '17 at 06:33
5
    #one ~ :not( #two ~ * ):not( #two )

Selects all element that are preceded of #one but not are preceded of #two and it is not #two

Pure logic, enjoy it

[UPDATE]

For the most browsers:

    :not(#one) {
      color: black /* color for out range */
    }

    #one~* {
      color: red;
    }

    #two~* , #two {
      color: black /* color for out range */
    }
Peter
  • 329
  • 7
  • 9
  • 1
    Most browsers cannot run this selector. https://caniuse.com/css-not-sel-list – Slbox Sep 08 '20 at 18:52
  • 1
    It work on most XML functionality with selector feature. I had update my answer if do you need a solve it for browser – Peter Sep 09 '20 at 19:54
2

You can wrap the elements in a div element and assign the div an id that you will then use in the CSS file to select what is inside the tag.

<div id="ID">
    <p></p>
    <p></p>
    <p></p>
    <p></p>
    <p></p>
</div>

#id {
    color:red;
}
<p>1</p>
<div id="id">
    <p>2</p>
    <p>3</p>
    <p>4</p>
    <p>5</p>
</div>
<p>6</p>
TylerH
  • 20,799
  • 66
  • 75
  • 101
ronce96
  • 84
  • 2
  • 9