Reputation: 4834
First off, I know that this can be done via JS (and currently have this approach implemented), but I'd prefer to use native CSS if possible. Less JS, less DOM access, and so forth.
TL;DR
Is there a CSS selector to target elements with a specific CSS property? More specifically, to target the element with the greatest order
property?
Something like...
el:greatest(property:order) {...}
Setup
I've got a list, something like...
<div class="list-container">
<ul class="list">
<li style="order: 0;">One</li>
<li style="order: 1;">two</li>
<li style="order: 2;">three</li>
...
<li style="order: n;">Last</li>
</ul>
</div>
This is used as an infinite scroller, and so the entire list (ul
) scrolls within the container. The details aren't hugely important, but essentially the number of list items is constant, and are recycled as the user scrolls.
Clarification: Even though the number of list items is constant, there is no bounds to the maximum order number. If the initial orders are order=0, 1, 2, 3
(list of four items), then 0->4
, 1->5
, 2->6
, and so on. Only one order is changed at a time - either to greater than all others (end of the list) or lesser than all others (start of the list).
I accomplish this recycling by displaying the list as a flex-box
and changing the order of the list items programattically.
More pertinent CSS is something like...
.list-container {
overflow: scroll;
}
ul.list {
display: flex;
flex-direction: column;
list-style: none;
}
li {
... other rules
margin-bottom: 5px;
}
li:last-child {
margin-bottom: 0;
}
Each list item has a bottom-margin
, which acts as a buffer between each item (purely for aesthetics). BUT! It looks dumb when you scroll to the bottom of the list and there is an unnecessary margin before the bottom of the list container. Therefor, set the last-child
to not have a bottom margin.
The list ends up looking something like...
... note: list BG set to red
so you can see the padding, and li:last-child
has BG set to aqua
, so you can see which item is being treated as the last
Problem solved, right!?
So, The Problem...
(Assume the list has n
list items.)
In a normal list, the above CSS would work great. The issue comes when I take the top list item (order: 0;
) and reassign the order so that it is moved to the bottom of the list (order: n+1;
). Even though the list item might be painted and displayed at the bottom of the list, it is still treated within the DOM as the first list item.
The DOM looks like...
<div class="list-container">
<ul class="list">
<li style="order: n+1;">One</li>
<li style="order: 1;">two</li>
<li style="order: 2;">three</li>
...
<li style="order: n;">Last</li>
</ul>
</div>
And the result looks like...
Because list item order: n;
is still the last-child
within the DOM, its bottom margin is removed, even though there is another list item displayed below it.
The same issue arrises when using margin-top
and li:first-child
. It's inescapable!
So, Can I...?
Is there a native CSS way to target the element with the greatest order number? Or perhaps there is another CSS-only trick to accomplish the same?
Much thanks!
Upvotes: 1
Views: 862
Reputation: 56690
Since the number of list items is constant
is said in the question, you can just set the CSS for the largest order element, using the attribute selector.
DISCLAIMER:
But please note, this selector is very
fragile
and the selector contents needs to be exactly the same as the contents of the style attribute.
li[style*="order: 4;"] {
background-color: lightblue;
}
.list-container {
overflow: auto;
}
ul.list {
display: flex;
flex-direction: column;
list-style: none;
}
li {
... other rules margin-bottom: 5px;
}
li:last-child {
margin-bottom: 0;
}
<div class="list-container">
<ul class="list">
<li style="order: 4;">One</li>
<li style="order: 1;">two</li>
<li style="order: 2;">three</li>
<li style="order: 3;">Last</li>
</ul>
</div>
Upvotes: 0
Reputation: 331
Instead of removing the margin on the last li
element, you could hide it by setting the bottom margin of the ul
element to -5px and setting the overflow property to hidden.
Upvotes: 1