Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Targeting the last element among a set of element types with CSS

I've tried this;

@mixin text-format{
>p, >ul, >h1, >h2, >h3, >h4, >h5{
    &:last-of-type{
        background-color:green;
    }
}
}

.text-body{
@include text-format;
}

Pure CSS

.text-body > p:last-of-type, .text-body > ul:last-of-type, .text-body > h1:last-of-type, .text-body > h2:last-of-type, .text-body > h3:last-of-type, .text-body > h4:last-of-type, .text-body > h5:last-of-type {
  background-color: green;
}

This selects the last instance of each of those element types, but exclusive to that element type. I simply want to select the last element within the div no matter what it is, but within the specified element types in the selector.

Fiddle; http://jsfiddle.net/bazzle/bcLt62jx/

like image 683
bazzlebrush Avatar asked Jul 28 '15 12:07

bazzlebrush


People also ask

How do you target the last element in CSS?

The :last-child selector allows you to target the last element directly inside its containing element. 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.

How do you target specific elements in CSS?

URLs with an # followed by an anchor name link to a certain element within a document. The element being linked to is the target element. The :target selector can be used to style the current active target element.

What is Last-of-type in CSS?

Definition and Usage. The :last-of-type selector matches every element that is the last child, of a particular type, of its parent. Tip: This is the same as :nth-last-of-type(1). Version: CSS3.

How do you select the last two elements in CSS?

nth-child() is a very handy pseudo-selector, but sometimes you need to approach things from the other end, starting from the last item. That's where nth-last-child comes to the rescue.


2 Answers

Sounds like you might be looking for

.text-body > :nth-last-child(1 of p, ul, h1, h2, h3, h4, h5)

from Selectors 4 (originally specced as :nth-last-match()). This restricts the list of potential matches to just those element types, and picks the last occurrence of them within the parent element, .text-body. An illustration:

<div class="text-body">
  <h1></h1>
  <p></p>
  <ul></ul>
  <h2></h2>
  <p></p>
  <span></span>
</div>

In this example, there are six children, five of which are any of p, ul, h1, h2, h3, h4, h5. The last element out of these five is the p that immediately precedes the span, so it matches the above selector. The h1 will match the equivalent :nth-child() expression, while the span will never match any such expression given the selector-list — in fact, the span itself can be expressed as :not(p, ul, h1, h2, h3, h4, h5).

While :nth-child(), :nth-last-child() and :not() were all introduced in Selectors 3, the selector-list argument is new to Selectors 4. But no one has implemented it yet, and no one knows when it will be. Unfortunately, there is no equivalent using what is currently available, as it's basically the same as this question except rather than a class selector, you're looking for the nth (last) child matching a pool of options. In both situations, you're dealing with the nth occurrence of some subset of an element's children.

Your best bet is to use JavaScript to, for example, add a class to the last instance among these element types on page load. Something like this with the native DOM/Selectors APIs:

var types = document.querySelectorAll('.text-body > p, .text-body > ul, .text-body > h1, .text-body > h2, .text-body > h3, .text-body > h4, .text-body > h5');
types[types.length - 1].className += ' last';

... which is quite the abomination compared to the following jQuery:

$('.text-body').children('p, ul, h1, h2, h3, h4, h5').last().addClass('last');

Note that

:nth-last-child(1 of p, ul, h1, h2, h3, h4, h5)

is not equivalent to

:last-child:matches(p, ul, h1, h2, h3, h4, h5)

as the latter matches the last child of its parent if and only if it is any one of those element types. In other words, :last-child:matches(...) is the Selectors 4 equivalent of p, ul... { &:last-child { ... } } (the second part of Harry's answer).

like image 53
BoltClock Avatar answered Nov 15 '22 07:11

BoltClock


If you need to select the last child within a parent element irrespective of it's element type then you need to use a simple :last-child selector like below:

& > :last-child{
  background-color:green;
}

The above selector will select the last-child within the .text-body irrespective of what type of element it is.

In the below snippet, you can see how the background-color: green is applied to the last-child of the both .text-body blocks even though the last-child within the first block is a p and that within the second block is a span.

.text-body p,
.text-body ul {
  margin-bottom: 1em;
}
.text-body >:last-child {
  background-color: green;
}
<div class="text-body">
  <h1>Title</h1>
  <p>
    But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, the master-builder of human
    happiness. No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter consequences that are extremely painful.
  </p>
  <ul>
    <li>List item 1</li>
    <li>List item 2</li>
    <li>List item 3</li>
    <li>List item 4</li>
  </ul>
  <h2>Subtitle</h2>
  <p>
    Nor again is there anyone who loves or pursues or desires to obtain pain of itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some great pleasure. To take a trivial example, which of us ever
    undertakes laborious physical exercise, except to obtain some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no annoying consequences, or one who avoids a pain that produces no resultant
    pleasure?
  </p>
</div>

<div class="text-body">
  <h1>Title</h1>
  <p>
    But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, the master-builder of human
    happiness. No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter consequences that are extremely painful.
  </p>
  <ul>
    <li>List item 1</li>
    <li>List item 2</li>
    <li>List item 3</li>
    <li>List item 4</li>
  </ul>
  <h2>Subtitle</h2>
  <span>
    Nor again is there anyone who loves or pursues or desires to obtain pain of itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some great pleasure. To take a trivial example, which of us ever
    undertakes laborious physical exercise, except to obtain some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no annoying consequences, or one who avoids a pain that produces no resultant
    pleasure?
  </span>
</div>

On the other hand, if you want to select the last child only when its element type is one among a list of values then you need to use the last-child selector with an extra criteria like below:

>p, >ul, >h1, >h2, >h3, >h4, >h5{
    &:last-child{
        background-color:green;
    }
}

The above selector will select the last-child when its element type is one among p, ul, h1, h2, h3, h4, h5.

If the element type of the last-child is anything other than these then the combination criteria would not be matched and hence the style would not get applied. In the below snippet, you can see how the background-color: green is applied to the last-child of the first .text-body but not to that of the second .text-body because in the 2nd, the last child is a span.

.text-body p,
.text-body ul {
  margin-bottom: 1em;
}
.text-body > p:last-child,
.text-body > ul:last-child,
.text-body > h1:last-child,
.text-body > h2:last-child,
.text-body > h3:last-child,
.text-body > h4:last-child,
.text-body > h5:last-child {
  background-color: green;
}
<div class="text-body">
  <h1>Title</h1>
  <p>
    But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, the master-builder of human
    happiness. No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter consequences that are extremely painful.
  </p>
  <ul>
    <li>List item 1</li>
    <li>List item 2</li>
    <li>List item 3</li>
    <li>List item 4</li>
  </ul>
  <h2>Subtitle</h2>
  <p>
    Nor again is there anyone who loves or pursues or desires to obtain pain of itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some great pleasure. To take a trivial example, which of us ever
    undertakes laborious physical exercise, except to obtain some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no annoying consequences, or one who avoids a pain that produces no resultant
    pleasure?
  </p>
</div>

<div class="text-body">
  <h1>Title</h1>
  <p>
    But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, the master-builder of human
    happiness. No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter consequences that are extremely painful.
  </p>
  <ul>
    <li>List item 1</li>
    <li>List item 2</li>
    <li>List item 3</li>
    <li>List item 4</li>
  </ul>
  <h2>Subtitle</h2>
  <span>
    Nor again is there anyone who loves or pursues or desires to obtain pain of itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some great pleasure. To take a trivial example, which of us ever
    undertakes laborious physical exercise, except to obtain some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no annoying consequences, or one who avoids a pain that produces no resultant
    pleasure?
  </span>
</div>
like image 21
Harry Avatar answered Nov 15 '22 06:11

Harry