Reputation: 2629
How do I select the last element in a sequence of adjacent elements?
Consider the following markup:
HTML
<ul>
<li class="foo">...</li>
<li class="foo">...</li>
<li class="foo">...</li> <!-- bingo -->
<li class="bar">...</li>
<li class="bar">...</li>
<li class="bar">...</li>
<li class="bar">...</li> <!-- bingo -->
<li class="foo">...</li> <!-- bingo -->
<li class="bar">...</li>
<li class="bar">...</li> <!-- bingo -->
</ul>
The number of consecutive foo
or bar
elements is dynamic. Also, assume the markup cannot be modified in any way.
Selecting adjacent elements is pretty straight forward:
CSS
.foo + .foo,
.bar + .bar { /* do something */ }
But selecting the last element in a series of consecutive elements, is that possible?
Upvotes: 16
Views: 2757
Reputation: 7551
The CSS support for :has
is still poor but it can solve the problem:
/* selects any .foo that has no .foo immediately after it */
.foo:has(+ :not(.foo)) {}
Upvotes: 4
Reputation: 210
I don't believe there's a way to do this without changing the HTML or the way you generate it. However, if you generate it via the .append()
method, all you'd have to do to use this (theoretically) is change it to .prepend()
. If you do that, you can change the ul's css to have it select backwards, and then you can use the + selector like so:
(edit: I don't know how to reorder the snippet, but the JS is the least important and only there for if you want to see the .prepend()
in action)
//some generation examples just for fun
foo.addEventListener('click',addKnown);
bar.addEventListener('click',addKnown);
r.addEventListener('click',addRandom);
function addKnown(e) {
let li = document.createElement('li');
li.className = e.target.id;
li.textContent = e.target.id;
document.querySelector('ul').prepend(li);
}
function addRandom(e) {
let li = document.createElement('li');
let type = ['foo','bar'][Math.round(Math.random())];
li.className = type;
li.textContent = type;
document.querySelector('ul').prepend(li);
}
ul {
display: flex;
flex-direction: column-reverse;
}
li:first-of-type,
.foo+.bar,
.bar+.foo {
color: red
}
<ul>
<li class="bar">bar</li> <!-- bingo -->
<li class="bar">bar</li>
<li class="foo">foo</li> <!-- bingo -->
<li class="bar">bar</li> <!-- bingo -->
<li class="bar">bar</li>
<li class="bar">bar</li>
<li class="bar">bar</li>
<li class="foo">foo</li> <!-- bingo -->
<li class="foo">foo</li>
<li class="foo">foo</li>
</ul>
<!-- some generation examples just for fun-->
<button id="foo">Add foo</button>
<button id="bar">Add bar</button>
<button id="r">Add random</button>
I would also recommend giving the ul some sort of class or id unless you only have one or want this to be the case for all of your uls on the page.
I'm sorry, I know this isn't exactly what you wanted (because it does technically change the markup by making it backwards), but I hope it's something that's at least possible or helpful in finding something that is.
Upvotes: 0
Reputation: 293
There appears to be an nth-last-child selector:
http://css-tricks.com/almanac/selectors/n/nth-last-child/
You should be able to use it with a zero argument to get the last one
Edit: nth-last-child will indeed select the last child, which does not match the bingo's
Hopefully you can change the structure:
<ul>
<ul>
<li class="foo">foo 1</li>
<li class="foo">foo 2</li>
<li class="foo">foo 3 bingo</li>
</ul>
<ul>
<li class="bar">bar 1</li>
<li class="bar">bar 2</li>
<li class="bar">bar 3</li>
<li class="bar">bar 4 bingo</li>
</ul>
<ul>
<li class="foo">foo 1</li>
<li class="foo">foo 2 bingo</li>
</ul>
</ul>
and this css will work:
.foo:nth-last-child(1),
.bar:nth-last-child(1)
{
background-color: blue;
}
Upvotes: -2
Reputation: 99
You must be dynamically setting up the list.... in that case give a name or an id to the last element and add the css effect you want....
What you asked is not possible according to me unless you have some way of recognizing the last element (may be the id or the name, again set this up if you are in control)
Upvotes: 0