sylar32
sylar32

Reputation: 177

Select first and last element of sequences with specific class in CSS

I have a lot of divs having class line with strong.datum element within. I would need to highlight first and last element of each sequence with class .active. If it is not possible to do it with CSS, is there any chance to do it via jQuery?

In this example should have class .start elements .dt_26, .dt_66, .dt_27, .dt_77 and class .end should have elements .dt_46, .dt_76, .dt_57 and .dt_97.

<div class="line">
<strong class="dt_16 app_54 datum">1.6.</strong>
<strong class="dt_26 app_54 datum active">2.6.</strong>
<strong class="dt_36 app_54 datum active">3.6.</strong>
<strong class="dt_46 app_54 datum active">4.6.</strong>
<strong class="dt_56 app_54 datum">5.6.</strong>
<strong class="dt_66 app_54 datum active">6.6.</strong>
<strong class="dt_76 app_54 datum active">7.6.</strong>
<strong class="dt_86 app_54 datum active">8.6.</strong>
<strong class="dt_96 app_54 datum active">9.6.</strong>
<strong class="dt_106 app_54 datum">10.6.</strong>
</div>
<div class="line">
<strong class="dt_17 app_54 datum">1.7.</strong>
<strong class="dt_27 app_54 datum active">2.7.</strong>
<strong class="dt_37 app_54 datum active">3.7.</strong>
<strong class="dt_47 app_54 datum active">4.7.</strong>
<strong class="dt_57 app_54 datum active">5.7.</strong>
<strong class="dt_67 app_54 datum">6.7.</strong>
<strong class="dt_77 app_54 datum">7.7.</strong>
<strong class="dt_87 app_54 datum active">8.7.</strong>
<strong class="dt_97 app_54 datum active">9.7.</strong>
<strong class="dt_107 app_54 datum">10.7.</strong>
</div>

Upvotes: 0

Views: 164

Answers (3)

Louys Patrice Bessette
Louys Patrice Bessette

Reputation: 33933

Here's a jQuery solution...

Using .prev() and .next(), you can loop through all the .line .children() elements and check if they're first or last.

I even made an addition for the fun of it... You also can check if they're "lonely"... ;)

As you can see, the code is pretty self explanatory...

$(".line").children().each(function(){

  // Firsts
  if( $(this).hasClass("active") && !$(this).prev().hasClass("active") ){
    $(this).addClass("first");
  }
  
  // Lasts
  if( $(this).hasClass("active") && !$(this).next().hasClass("active") ){
    $(this).addClass("last");
  }
  
  // Lonelies
  if( $(this).hasClass("active") && !$(this).prev().hasClass("active") && !$(this).next().hasClass("active") ){
    $(this).removeClass("first last").addClass("alone");
  }
});
.first{
  color: green;
}
.last{
  color: orange;
}
.alone{
  color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div class="line">
  <strong class="dt_16 app_54 datum">1.6.</strong>
  <strong class="dt_26 app_54 datum active">2.6.</strong>
  <strong class="dt_36 app_54 datum active">3.6.</strong>
  <strong class="dt_46 app_54 datum active">4.6.</strong>
  <strong class="dt_56 app_54 datum">5.6.</strong>
  <strong class="dt_66 app_54 datum active">6.6.</strong>
  <strong class="dt_76 app_54 datum active">7.6.</strong>
  <strong class="dt_86 app_54 datum active">8.6.</strong>
  <strong class="dt_96 app_54 datum active">9.6.</strong>
  <strong class="dt_106 app_54 datum">10.6.</strong>
</div>
<div class="line">
  <strong class="dt_17 app_54 datum">1.7.</strong>
  <strong class="dt_27 app_54 datum active">2.7.</strong>
  <strong class="dt_37 app_54 datum active">3.7.</strong>
  <strong class="dt_47 app_54 datum active">4.7.</strong>
  <strong class="dt_57 app_54 datum active">5.7.</strong>
  <strong class="dt_67 app_54 datum">6.7.</strong>
  <strong class="dt_77 app_54 datum">7.7.</strong>
  <strong class="dt_87 app_54 datum active">8.7.</strong>
  <strong class="dt_97 app_54 datum">9.7.</strong>
  <strong class="dt_107 app_54 datum">10.7.</strong>
</div>

Upvotes: 1

kukkuz
kukkuz

Reputation: 42352

It's not exactly possible in CSS - so here is a vanilla JS solution - see explanations inline:

// get a list of line elemnts
[...document.querySelectorAll('.line')].forEach(function(line) {
  // reduce the child elements
  [...line.querySelectorAll('strong')].reduce(function(p,c) {
    if (c.classList.contains('active')) {
      if(!p) // mark first
        c.classList.add('first');
       // mark last after checking the following child
      if((!c.nextElementSibling || !c.nextElementSibling.classList.contains('active')) && p)
        c.classList.add('last');
      return true;
    }
    return false;
  }, false);
})
.first {
  color: cadetblue;
}

.last {
  color: red;
}
<div class="line">
  <strong class="dt_16 app_54 datum">1.6.</strong>
  <strong class="dt_26 app_54 datum active">2.6.</strong>
  <strong class="dt_36 app_54 datum active">3.6.</strong>
  <strong class="dt_46 app_54 datum active">4.6.</strong>
  <strong class="dt_56 app_54 datum">5.6.</strong>
  <strong class="dt_66 app_54 datum active">6.6.</strong>
  <strong class="dt_76 app_54 datum active">7.6.</strong>
  <strong class="dt_86 app_54 datum active">8.6.</strong>
  <strong class="dt_96 app_54 datum active">9.6.</strong>
  <strong class="dt_106 app_54 datum">10.6.</strong>
</div>
<div class="line">
  <strong class="dt_17 app_54 datum">1.7.</strong>
  <strong class="dt_27 app_54 datum active">2.7.</strong>
  <strong class="dt_37 app_54 datum active">3.7.</strong>
  <strong class="dt_47 app_54 datum active">4.7.</strong>
  <strong class="dt_57 app_54 datum active">5.7.</strong>
  <strong class="dt_67 app_54 datum">6.7.</strong>
  <strong class="dt_77 app_54 datum">7.7.</strong>
  <strong class="dt_87 app_54 datum active">8.7.</strong>
  <strong class="dt_97 app_54 datum active">9.7.</strong>
  <strong class="dt_107 app_54 datum">10.7.</strong>
</div>

Upvotes: 1

Erik Philips
Erik Philips

Reputation: 54628

AFAIK You can't select the first and last element with additional requirements (like with specific class etc) via css. Fairly easy with jQuery.

$(document).ready(function() {
  $(".line").each(function(i, line) {
    $(line).children("strong.active:first, strong.active:last").addClass("highlight");
  });
});
.highlight {
  background-color: yellow;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="line">
<strong class="dt_16 app_54 datum">1.6.</strong>
<strong class="dt_26 app_54 datum active">2.6.</strong>
<strong class="dt_36 app_54 datum active">3.6.</strong>
<strong class="dt_46 app_54 datum active">4.6.</strong>
<strong class="dt_56 app_54 datum">5.6.</strong>
<strong class="dt_66 app_54 datum active">6.6.</strong>
<strong class="dt_76 app_54 datum active">7.6.</strong>
<strong class="dt_86 app_54 datum active">8.6.</strong>
<strong class="dt_96 app_54 datum active">9.6.</strong>
<strong class="dt_106 app_54 datum">10.6.</strong>
</div>
<div class="line">
<strong class="dt_17 app_54 datum">1.7.</strong>
<strong class="dt_27 app_54 datum active">2.7.</strong>
<strong class="dt_37 app_54 datum active">3.7.</strong>
<strong class="dt_47 app_54 datum active">4.7.</strong>
<strong class="dt_57 app_54 datum active">5.7.</strong>
<strong class="dt_67 app_54 datum">6.7.</strong>
<strong class="dt_77 app_54 datum">7.7.</strong>
<strong class="dt_87 app_54 datum active">8.7.</strong>
<strong class="dt_97 app_54 datum active">9.7.</strong>
<strong class="dt_107 app_54 datum">10.7.</strong>
</div>

The reason this works and something like:

.line > strong.active:first {
  background-color: yellow;
}

doesn't work is because the jQuery parsing engine is not exactly the same as CSS selectors. :first in jQuery just selects the first element after selectors, where-as :first is css literally means the first element regardless of selectors, so (CSS) if your selectors remove the literal-first element then :first never matches.

Upvotes: 1

Related Questions