Vishal Shah
Vishal Shah

Reputation: 4124

A CSS selector to get last visible div

A tricky CSS selector question, don't know if it's even possible.

Lets say this is the HTML layout:

<div></div>
<div></div>  
<div></div>  
<div style="display:none"></div>
<div style="display:none"></div>  

I want to select the last div, which is displayed (ie. not display:none) which would be the third div in the given example. Mind you, the number of divs on the real page can differ (even the display:none ones).

Upvotes: 207

Views: 261039

Answers (10)

s123
s123

Reputation: 171

div:not([style*="display:none"], :has(~ div:not([style*="display:none"])))

We need to get the last thing that matches div:not([style*="display:none"]). Let's call that x. We need to select x and then get the last one, which would be any x which does not have any x after it. To select something which has a selector after it, we use :has(~ ...) and we use :not(...) to negate it.

So x:not(:has(~ x)), or div:not([style*="display:none"]):not(:has(~ div:not([style*="display:none"])), simplified to div:not([style*="display:none"], :has(~ div:not([style*="display:none"]))

Upvotes: 1

Tyler Wayne
Tyler Wayne

Reputation: 363

Try

div:not([style*="display: none"]):last-child

Upvotes: 20

Glaerferyn
Glaerferyn

Reputation: 211

Just for the sake of completeness, I solved this problem using pure css with the :has operator.

In your example you will have the following rule : div:has(+ div[style*="display:none"] It will select all node with the condition of having a direct sibling with a display:none style rule.

div > div:has(+ div[style*="display:none"]),
div > div:last-child {
  background: red;
  color: white;
}
<h3>Example 1 :</h3>
<div>
  <div>A</div>
  <div>B</div>  
  <div>C</div>  
  <div style="display:none">D</div>
  <div style="display:none">E</div> 
</div>
<h3>Example 2 :</h3>
<div>
  <div>A</div>
  <div>B</div>  
  <div>C</div>  
  <div>D</div>
  <div>E</div> 
</div>

div:last-child is only there to support the case where all the blocks would be visible, therefore there would be no sibbling but we want to apply the css rule anyway.

Please note that it only works because your hidden divs are sibblings.

Upvotes: 5

pavel
pavel

Reputation: 27092

Pure JS solution (eg. when you don't use jQuery or another framework to other things and don't want to download that just for this task):

var divs = document.getElementsByTagName('div');
var last;

if (divs) {
  for (var i = 0; i < divs.length; i++) {
    if (divs[i].style.display != 'none') {
      last = divs[i];
    }
  }
}

if (last) {
  last.style.background = 'red';
}
<div>A</div>
<div>B</div>
<div>C</div>
<div style="display:none">D</div>
<div style="display:none">E</div>

External link

Upvotes: 6

Alex Grande
Alex Grande

Reputation: 8027

If you can use inline styles, then you can do it purely with CSS.

I am using this for doing CSS on the next element when the previous one is visible:

div[style='display: block;'] + table {
  filter: blur(3px);
}

Upvotes: 14

dudewad
dudewad

Reputation: 13933

The real answer to this question is, you can't do it. Alternatives to CSS-only answers are not correct answers to this question, but if JS solutions are acceptable to you, then you should pick one of the JS or jQuery answers here. However, as I said above, the true, correct answer is that you cannot do this in CSS reliably unless you're willing to accept the :not operator with the [style*=display:none] and other such negated selectors, which only works on inline styles, and is an overall poor solution.

Upvotes: 57

Surreal Dreams
Surreal Dreams

Reputation: 26380

You could select and style this with JavaScript or jQuery, but CSS alone can't do this.

For example, if you have jQuery implemented on the site, you could just do:

var last_visible_element = $('div:visible:last');

Although hopefully you'll have a class/ID wrapped around the divs you're selecting, in which case your code would look like:

var last_visible_element = $('#some-wrapper div:visible:last');

Upvotes: 80

martynas
martynas

Reputation: 12290

It is not possible with CSS, however you could do this with jQuery.

JSFIDDLE DEMO

jQuery:

$('li').not(':hidden').last().addClass("red");

HTML:

<ul>
        <li>Item 1</li>
        <li>Item 2</li>
        <li>Item 3</li>
        <li class="hideme">Item 4</li>    
</ul>

CSS:

.hideme {
    display:none;
}

.red {
    color: red;
}

jQuery (previous solution):

var $items = $($("li").get().reverse());

$items.each(function() {

    if ($(this).css("display") != "none") {
        $(this).addClass("red");
        return false;
    }

});

Upvotes: 3

Guillaume86
Guillaume86

Reputation: 14400

I think it's not possible to select by a css value (display)

edit:

in my opinion, it would make sense to use a bit of jquery here:

$('#your_container > div:visible:last').addClass('last-visible-div');

Upvotes: 9

eveevans
eveevans

Reputation: 4460

in other way, you can do it with javascript , in Jquery you can use something like:

$('div:visible').last()

*reedited

Upvotes: 1

Related Questions