allejo allejo - 5 months ago 15
CSS Question

CSS detect factor of siblings

So I've been able to detect the number of siblings an element has by using nth-child(), however I haven't been able to figure out a way to select only the last few elements based on the total number of siblings.

In the following code snippet, I've achieved the goal I wanted by adding classes. But I would like a way to achieve this with just CSS selectors, if possible. In the following code snippet, each "group" has 2 rows, a row being defined as 3 elements together. I would like to select the orange elements as seen in the snippet below without adding classes. Either selecting the elements in the last row or selecting all of the elements except for those in the last row.



ul {
padding-left: 0;
}

ul::after {
content: '';
display: table;
clear: both;
}

li {
background-color: #efefef;
border: 1px dotted #000;
box-sizing: content-box;
float: left;
list-style-type: none;
padding: 10px 0;
text-align: center;
width: 33%
}

.alt {
background-color: orange;
}

<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li class="alt">4</li>
</ul>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li class="alt">4</li>
<li class="alt">5</li>
</ul>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li class="alt">4</li>
<li class="alt">5</li>
<li class="alt">6</li>
</ul>




Answer

Since nth-last-child can take a formula, you can do this for any number of elements using the same technique as in the other question you referenced.

ul {
  padding-left: 0;
}

ul::after {
  content: '';
  display: table;
  clear: both;
}

li {
  background-color: #efefef;
  border: 1px dotted #000;
  box-sizing: content-box;
  float: left;
  list-style-type: none;
  padding: 10px 0;
  text-align: center;
  width: 33%
}

/* 3 elements in last row */
li:first-child:nth-last-child(3n+0) ~ li:nth-last-child(1),
li:first-child:nth-last-child(3n+0) ~ li:nth-last-child(2),
li:first-child:nth-last-child(3n+0) ~ li:nth-last-child(3),

/* 2 elements in last row */
li:first-child:nth-last-child(3n+2) ~ li:nth-last-child(1),
li:first-child:nth-last-child(3n+2) ~ li:nth-last-child(2),

/* 1 element in last row */
li:first-child:nth-last-child(3n+1) ~ li:nth-last-child(1) {
  background-color: orange;
}
<ul>
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
</ul>
<ul>
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
  <li>5</li>
</ul>
<ul>
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
  <li>5</li>
  <li>6</li>
</ul>
<ul>
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
  <li>5</li>
  <li>6</li>
  <li>7</li>
  <li>8</li>
  <li>9</li>
  <li>10</li>
  <li>11</li>
  <li>12</li>
  <li>13</li>
</ul>


The expression li:first-child:nth-last-child(3) requires an li which is both the first-child of its parent and also the third from last child. These two constraints together mean that the parent element must have exactly 3 children. In similar fashion, li:first-child:nth-last-child(3n+0) means that the parent must have a number of children that is a multiple of 3.

Once we have constrained what first elements are valid, we then need to select the last element(s) in order to highlight them. The sibling selector (~) will select siblings of the matched element, and we use nth-last-child again to select the element N from the end.

These rules are combined and repeated to handle the case of 1, 2, or 3 elements in the last row.

Comments