DEV Community

Cover image for tricky css selector
Frank Wisniewski
Frank Wisniewski

Posted on

3 3

tricky css selector

alternative to jQuerys nextUntil()

Today I encountered a seemingly simple problem:

  • the paragraphs under each header h2 need a different text color
    • sample1-1 to sample1-3 -> blue
    • sample2-1 to sample2-2 -> red
    • sample3-1 -> green
  • a click on h2 must toggle display the direct following paragraphs
<!DOCTYPE html>
<html lang=en>
  <meta charset=UTF-8>
  <title>Document</title>
  <h1>Sample</h1>
    <h2>sample-1</h2>
      <p>sample1-1
      <p>sample1-2
      <p>sample1-3
    <h2>sample-2</h2>
      <p>sample2-1
      <p>sample2-2
    <h2>sample-3</h2>
      <p>sample3-1
  <h3>Note</h3>
  <p>the paragraphs under each header2
  <p>need a different text color 
  <p>test1-1 to test1-3 -> blue
  <p>test2-1 to test2-2 -> red
  <p>test3-1 -> green
  <p>a click on h2 must toggle display the direct
  <p>following paragraphs
Enter fullscreen mode Exit fullscreen mode

OK, let's start with the colors,
and write some simple css rules,
the General Sibling Selector (~)
is my friend :-):

h2:first-of-type~p {color:blue}
h2:nth-of-type(2)~p {color:red}
h2:nth-of-type(3)~p {color:green}
Enter fullscreen mode Exit fullscreen mode

Done, the colors under the respective h2 are correct. Unfortunately, the paragraphs under the following h3 also turn green.
I didn't consider that the General Sibling Selector (~) selects all following paragraphs.

What should I do?

  • i need the first h2 Element h2:nth-of-type(1)
  • all the following paragraphs ~p
  • but not the following paragraphs behind the second h2

OK, at first i try to select all following paragraphs after the second h2

  • select all behind the first h2 h2:nth-of-type(1)~*
  • but not p (this selects only the headers h2,h2,h3)
  • but i need the following paragraphs with ~p
  • summarized h2:nth-of-type(1)~*:not(p)~p

So the complete selector looks like this:

h2:nth-of-type(1)~p:not(h2:nth-of-type(1)~*:not(p)~p)
Enter fullscreen mode Exit fullscreen mode

and the css for coloring the paragraphs

h2:nth-of-type(1)~p:not(h2:nth-of-type(1)~*:not(p)~p){
  color:blue;
}
h2:nth-of-type(2)~p:not(h2:nth-of-type(2)~*:not(p)~p){
  color:red;
}
h2:nth-of-type(3)~p:not(h2:nth-of-type(3)~*:not(p)~p){
  color:green;
}
Enter fullscreen mode Exit fullscreen mode

the problem toggle display

give h2 a pointer cursor and create a class to toggle display

h2{
  cursor: pointer;
  user-select:none;
}
.no-display{
  display:none;
}
Enter fullscreen mode Exit fullscreen mode

The rest is no longer a real problem because we already created the appropriate selectors in the previous step:

"use strict";

  document.querySelectorAll('h2')
    .forEach(( node, index ) =>
      node.addEventListener ( 'click', () =>
        document.querySelectorAll(
        `h2:nth-of-type(${index+1})~p:not(h2:nth-of-type(${index+1})~*:not(p)~p)`
        )
          .forEach(node => node.classList.toggle('no-display'))
      )
  )

Enter fullscreen mode Exit fullscreen mode

The complete code:

<!DOCTYPE html>
<html lang=de>
  <meta charset=UTF-8>
  <title>Document</title>
  <style>

    h2:nth-of-type(1)~p:not(h2:nth-of-type(1)~*:not(p)~p){
      color:blue;
    }
    h2:nth-of-type(2)~p:not(h2:nth-of-type(2)~*:not(p)~p){
      color:red;
    }
    h2:nth-of-type(3)~p:not(h2:nth-of-type(3)~*:not(p)~p){
      color:green;
    }

    h2{
      cursor: pointer;
      user-select:none;
    }
    .no-display{
      display:none;
    }

  </style>
  <h1>Sample</h1>
    <h2>Test-1</h2>
      <p>test1-1
      <p>test1-2
      <p>test1-3
    <h2>Test-2</h2>
      <p>test2-1
      <p>test2-2
    <h2>Test-3</h2>
      <p>test3-1
  <h3>Note</h3>
  <p>the paragraphs under each header2
  <p>need a different text color 
  <p>test1-1 to test1-3 -> blue
  <p>test2-1 to test2-2 -> red
  <p>test3-1 -> green
  <p>a click on h2 must toggle display the direct
  <p>following paragraphs

  <script>
  "use strict";

  document.querySelectorAll('h2')
    .forEach(( node, index ) =>
      node.addEventListener ( 'click', () =>
        document.querySelectorAll(
        `h2:nth-of-type(${index+1})~p:not(h2:nth-of-type(${index+1})~*:not(p)~p)`
        )
          .forEach(node => node.classList.toggle('no-display'))
      )
  )

  </script>
Enter fullscreen mode Exit fullscreen mode

SurveyJS custom survey software

JavaScript UI Libraries for Surveys and Forms

SurveyJS lets you build a JSON-based form management system that integrates with any backend, giving you full control over your data and no user limits. Includes support for custom question types, skip logic, integrated CCS editor, PDF export, real-time analytics & more.

Learn more

Top comments (0)

nextjs tutorial video

Youtube Tutorial Series 📺

So you built a Next.js app, but you need a clear view of the entire operation flow to be able to identify performance bottlenecks before you launch. But how do you get started? Get the essentials on tracing for Next.js from @nikolovlazar in this video series 👀

Watch the Youtube series

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay