I've got something that behaves the same way as the provided snippet. I've got a list of items, that when one is selected, I want that one to be displayed at the top of the list, which I can easily do with flex ordering. Only one can be selected at a time. But since each of the list elements have borders, the last element shouldn't have a border. Simply using the li:last-of-type
works fine for most cases, except for when the it's the last list item that is selected.
I've tried several selectors that should select the last list item in a unordered list that doesn't have a given class, but the last-of-type
selector doesn't seem to be behaving properly.
In case it isn't clear in the code, the selector I'm referring to is .selection li:not(.selected):last-of-type
. And the problem is the double border at the bottom of the list. It should be a single border coming from the unordered list element.
.selection ul {
display: flex;
flex-direction: column;
border: .15rem solid #666;
}
.selection li {
order: 2;
border-bottom: .15rem dashed #666;
}
.selection li.selected {
order: 1;
}
/** This selector should work in my mind, but it doesn't **/
.selection li:not(.selected):last-of-type {
border-bottom: none;
}
/** Non-important styles to put it into context **/
ul { list-style: none; padding: 0; width: 25%; margin: 2rem auto; }
li { padding: 1rem 2rem; background-color: #ebebeb; }
li:hover { background-color: #ccc; }
a { color: inherit; text-decoration: none; }
<div class="selection">
<ul>
<li><a href="">1</a></li>
<li><a href="">2</a></li>
<li class="selected">3</li>
</ul>
</div>
I've also created this Codepen snippet to demonstrate the problem.
I have a feeling this is a problem with the :last-of-type
selector, and maybe I'm using it wrong, but in my mind, the above selector should work.
Any help or insight into how to fix this, or another way to select the element, or insight into why this doesn't work would be appreciated.
The :last-of-type selector allows you to target the last occurence of an element within its container. It is defined in the CSS Selectors Level 3 spec as a “structural pseudo-class”, meaning it is used to style content based on its relationship with parent and sibling content. ).
There comes the use of pseudo selectors. This article explains the :not(:last-child):after selector. This selector does not select the element after the last child element. It is mostly used to add the content after every child element except the last.
class is not possible with last-of-type . Edit: To actually add something constructive to this answer, you could fallback to JavaScript to locate this selector, or revise your markup/CSS.
The :nth-last-of-type(n) selector matches every element that is the nth child, of a particular type, of its parent, counting from the last child. n can be a number, a keyword, or a formula.
Consider this alternative approach:
:not
selector entirelyul
a border only on the left, right and topli
ul {
display: flex;
flex-direction: column;
border-top: .15rem solid #666;
border-left: .15rem solid #666;
border-right: .15rem solid #666;
}
li { border-bottom: .15rem solid #666; }
Revised Codepen
Here's why your selector isn't working:
.selection li:not(.selected):last-of-type { border-bottom: none; }
It appears to me that you're saying you want to match the last li
element as long as it doesn't have the class selected
.
But this isn't how last-of-type
works. If the li
is a sibling, the selector will match it, regardless of class
. The selector matches DOM elements. This means that even if you applied display: none
to an li
, the selector would still match it.
6.6.5.9.
:last-of-type
pseudo-classThe
:last-of-type
pseudo-class represents an element that is the last sibling of its type in the list of children of its parent element.source: https://drafts.csswg.org/selectors-3/#last-of-type-pseudo
More details: How to get nth-child selector to skip hidden divs
Instead of trying to remove border-bottom
from the last unselected item (which is hard or impossible in CSS), it's way easier to set a border-top
to each item and remove the extra one from the item visually above others, which is... .selected
!
Your constraint of having:
a different border on my list elements than on the general outside border
is permitted with this solution.
Updated pen
.selection ul {
display: flex;
flex-direction: column;
border: .15rem solid #666;
}
.selection li {
order: 2;
border-top: .15rem dashed #666;
background: lightblue;
}
.selection li.selected {
order: 1;
border-top: none;
background: tomato;
}
/** Non-important styles to put it into context **/
ul { list-style: none; padding: 0; width: 25%; margin: 2rem auto; }
li { padding: 1rem 2rem; background-color: #ebebeb; }
li:hover { background-color: #ccc; }
a { color: inherit; text-decoration: none; }
<div class="selection">
<ul>
<li><a href="">1</a></li>
<li><a href="">2</a></li>
<li class="selected">3</li>
</ul>
</div>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With