Can CSS detect the number of children an element has?

CssCss Selectors

Css Problem Overview


I'm probably answering my own question, but I'm extremely curious.

I know that CSS can select individual children of a parent, but is there support to style the children of a container, if its parent has a certain amount of children.

for example

container:children(8) {
  // style the parent this way if there are 8 children
}

I know it sounds weird, but my manager asked me to check it out, haven't found anything on my own so I decided to turn to SO before ending the search.

Css Solutions


Solution 1 - Css

Clarification:

Because of a previous phrasing in the original question, a few SO citizens have raised concerns that this answer could be misleading. Note that, in CSS3, styles cannot be applied to a parent node based on the number of children it has. However, styles can be applied to the children nodes based on the number of siblings they have.


Original answer:

Incredibly, this is now possible purely in CSS3.

/* one item */
li:first-child:nth-last-child(1) {
/* -or- li:only-child { */
	width: 100%;
}

/* two items */
li:first-child:nth-last-child(2),
li:first-child:nth-last-child(2) ~ li {
	width: 50%;
}

/* three items */
li:first-child:nth-last-child(3),
li:first-child:nth-last-child(3) ~ li {
	width: 33.3333%;
}

/* four items */
li:first-child:nth-last-child(4),
li:first-child:nth-last-child(4) ~ li {
	width: 25%;
}

The trick is to select the first child when it's also the nth-from-the-last child. This effectively selects based on the number of siblings.

Credit for this technique goes to André Luís (discovered) & Lea Verou (refined).

Don't you just love CSS3? 

CodePen Example:

Sources:

Solution 2 - Css

No. Well, not really. There are a couple of selectors that can get you somewhat close, but probably won't work in your example and don't have the best browser compatibility.

:only-child

The :only-child is one of the few true counting selectors in the sense that it's only applied when there is one child of the element's parent. Using your idealized example, it acts like children(1) probably would.

:nth-child

The :nth-child selector might actually get you where you want to go depending on what you're really looking to do. If you want to style all elements if there are 8 children, you're out of luck. If, however, you want to apply styles to the 8th and later elements, try this:

p:nth-child( n + 8 ){
    /* add styles to make it pretty */
}

Unfortunately, these probably aren't the solutions you're looking for. In the end, you'll probably need to use some Javascript wizardry to apply the styles based on the count - even if you were to use one of these, you'd need to have a hard look at browser compatibility before going with a pure CSS solution.

W3 CSS3 Spec on pseudo-classes

EDIT I read your question a little differently - there are a couple other ways to style the parent, not the children. Let me throw a few other selectors your way:

:empty and :not

This styles elements that have no children. Not that useful on its own, but when paired with the :not selector, you can style only the elements that have children:

div:not(:empty) {
    /* We know it has stuff in it! */
}

You can't count how many children are available with pure CSS here, but it is another interesting selector that lets you do cool things.

Solution 3 - Css

NOTE: This solution will return the children of sets of certain lengths, not the parent element as you have asked. Hopefully, it's still useful.

Andre Luis came up with a method: http://lea.verou.me/2011/01/styling-children-based-on-their-number-with-css3/ Unfortunately, it only works in IE9 and above.

Essentially, you combine :nth-child() with other pseudo classes that deal with the position of an element. This approach allows you to specify elements from sets of elements with specific lengths.

For instance :nth-child(1):nth-last-child(3) matches the first element in a set while also being the 3rd element from the end of the set. This does two things: guarantees that the set only has three elements and that we have the first of the three. To specify the second element of the three element set, we'd use :nth-child(2):nth-last-child(2).


Example 1 - Select all list elements if set has three elements:

li:nth-child(1):nth-last-child(3),
li:nth-child(2):nth-last-child(2),
li:nth-child(3):nth-last-child(1) {
	width: 33.3333%;
}

Example 1 alternative from Lea Verou:

li:first-child:nth-last-child(3),
li:first-child:nth-last-child(3) ~ li {
	width: 33.3333%;
}


Example 2 - target last element of set with three list elements:

li:nth-child(3):last-child {
	/* I'm the last of three */
}

Example 2 alternative:

li:nth-child(3):nth-last-child(1) {
	/* I'm the last of three */
}


Example 3 - target second element of set with four list elements:

li:nth-child(2):nth-last-child(3) {
	/* I'm the second of four */
}

Solution 4 - Css

Working off of Matt's solution, I used the following Compass/SCSS implementation.

@for $i from 1 through 20 {
    li:first-child:nth-last-child( #{$i} ),
    li:first-child:nth-last-child( #{$i} ) ~ li {
      width: calc(100% / #{$i} - 10px);
    }
  }

This allows you to quickly expand the number of items.

Solution 5 - Css

If you are going to do it in pure CSS (using scss) but you have different elements/classes inside the same parent class you can use this version!!

  &:first-of-type:nth-last-of-type(1) {
    max-width: 100%;
  }

  @for $i from 2 through 10 {
    &:first-of-type:nth-last-of-type(#{$i}),
    &:first-of-type:nth-last-of-type(#{$i}) ~ & {
      max-width: (100% / #{$i});
    }
  }

Solution 6 - Css

Yes we can do this using nth-child like this:

div:nth-child(n + 8) {
    background: red;
} 

This will make the 8th div child onwards become red. Hope this helps...

Also, if someone ever says "hey, they can't be done with styled using css, use JS!" doubt them immediately. CSS is extremely flexible nowadays

.container div {
  background: blue;
}

.container div:nth-child(n + 8) {
  background: red;
}

<div class="container">
  <div>div 1</div>
  <div>div 2</div>
  <div>div 3</div>
  <div>div 4</div>
  <div>div 5</div>
  <div>div 6</div>
  <div>div 7</div>
  <div>div 8</div>
  <div>div 9</div>
  <div>div 10</div>
  <div>div 11</div>
  <div>div 12</div>
</div>

In the example the first 7 children are blue, then 8 onwards are red...

[External example]

Solution 7 - Css

No, there is nothing like this in CSS. You can, however, use JavaScript to calculate the number of children and apply styles.

Solution 8 - Css

If you're looking for a way to style all elements if more than N exist (e.g. 2 or more):

li:first-child:nth-last-child(n+2),
li:first-child:nth-last-child(n+2) ~ li {
  background-color: red;
}

<ul>
  <li>first</li>
</ul>

<ul>
  <li>first</li>
  <li>second</li>
</ul>

<ul>
  <li>first</li>
  <li>second</li>
  <li>third</li>
</ul>

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionBrodieView Question on Stackoverflow
Solution 1 - CssMatthematticsView Answer on Stackoverflow
Solution 2 - CssderekerdmannView Answer on Stackoverflow
Solution 3 - CssifuguView Answer on Stackoverflow
Solution 4 - CssmwtiddView Answer on Stackoverflow
Solution 5 - CssJuan Sebastian Contreras AceveView Answer on Stackoverflow
Solution 6 - CssAlanFosterView Answer on Stackoverflow
Solution 7 - CssNiet the Dark AbsolView Answer on Stackoverflow
Solution 8 - CssfredrivettView Answer on Stackoverflow