sibling-count()

Mojtaba Seyedi on

Get affordable and hassle-free WordPress hosting plans with Cloudways — start your free trial today.

Experimental: Check browser support before using this in production.

The sibling-count() CSS function returns the total number of sibling elements an element has, including itself. Think of it sort of as the CSS equivalent of JavaScript’s element.parentElement.children.length.

ul li {
  width: calc(100% / sibling-count());
}

Syntax

<sibling-count()> = sibling-count()

The sibling-count() function takes no arguments and returns an <integer>.

Use cases

1. Reverse staggered transitions

A common use case for sibling-index() is creating staggered animations. Now, if you combine it with sibling-count(), you can reverse the direction of that stagger — making the last item animate first, and the first item animate last.

Here’s how that looks in practice:

.item {
  transition-duration: calc((sibling-count() - sibling-index() + 1) * 200ms);
}

Instead of delaying each item, I can control how long its transition lasts. That way, all items start at the same time, but earlier ones take longer to finish. So, if you have four items, the first one runs 800ms and the last one runs for 200ms.

At the time, this only works behind the Experimental Web Platform features flag in Chromium-based browsers. Here is a video so you can see how it turns out:

2. Dynamic layout sizing

In our previous example, the bars that slide in with a reverse stagger also show another cool use of sibling-count() — setting size based on how many elements there are.

Instead of giving each bar a fixed height, like 25%, we used this:

.bar {
  height: calc(100% / sibling-count());
}

That means no matter how many bars we add or remove, they’ll always split the space evenly. This trick works great for flex layouts — whether it’s height or width, you can use sibling-count() to set the sizing dynamically.

3. Responsive typography

Let’s say you’re rendering a bunch of tags. With sibling-count(), you can automatically adjust the font size based on how many tags there are. That means: more tags equals smaller text, and fewer tags equals bigger text.

.tag {
  font-size: calc(3rem - (sibling-count() * 0.1rem));
}

Try clicking the tags to remove them — watch the font size scale up as the count goes down.

sibling-count() works on the DOM tree, not the flat tree

The specification states:

These functions, to match selectors like :nth-child(), operate on the DOM tree, rather than the flat tree like most CSS values do. They may, in the future, have variants that support counting flat tree siblings.

But what does that actually mean? Let’s look at an example to break it down.

<fancy-section>  
  <div>Slotted 1</div> 
  <div>Slotted 2</div>  
  <div>Slotted 3</div> 
</fancy-section>

<script>
  class FancySection extends HTMLElement {
    constructor() {
      super();
      this.attachShadow({ mode: 'open' }).innerHTML = `
        <section>
          <slot></slot>
          <div>Internal</div>
        </section>
        <style>
          div {
            width: calc(100% / sibling-count());
          }
        </style>
      `;
    }
  }

  customElements.define('fancy-section', FancySection);
</script>

At a glance, it looks like we have four <div>s visible in the page:

  1. Three coming from the light DOM and slotted into the component
  2. One internal <div> inside the shadow DOM

So you might expect the sibling-count() to be 4. But it’s actually 2, and here’s why. When the browser renders a component, it creates two trees:

  • The DOM tree: The actual parent/child relationships in markup
  • The flat tree: What you see — with slots filled and components expanded

The sibling-count() function works on the DOM tree, which means it doesn’t see slotted content as siblings of internal elements. It only considers elements that are siblings in the same tree scope.

So, inside the <section> element, the DOM structure is:

<section>
  <slot></slot>        <!-- First child -->
  <div>Internal</div>  <!-- Second child -->
</section>

And that’s why the sibling-count() function returns a value of 2.

width: calc(100% / sibling-count()); /* 100% / 2 = 50% */

Even though visually we have four siblings, those are not real siblings in the DOM tree.

Future possibility: filtered siblings with of selector

The specification also states:

These functions may, in the future, be extended to accept an of <complex-real-selector-list> argument, similar to :nth-child(), to filter on a subset of the children.

That means you might be able to do something like this in the future:

li {
  ... sibling-count(of .on-sale)
}

In this example, only list items with the .on-sale class are counted when calculating the siblings, regardless of where they are in the full list.

<ul>
  <li>Regular item</li>
  <li class="on-sale">Sale item 1</li>
  <li>Regular item</li>
  <li class="on-sale">Sale item 2</li>
  <li class="on-sale">Sale item 3</li>
</ul>

Specification

The sibling-count() function is part of CSS Values and Units Module Level 5, which is currently in Working Draft status at the time of writing. That means a lot can change between now and when the feature becomes a formal Candidate Recommendation for implementation.

Browser support

As of May 2025, sibling-count() is only supported in Chromium-based browsers (like Chrome and Edge), and even then, you’ll need to enable the Experimental Web Platform features flag at chrome://flags to try it out. It’s not production-ready yet, but it’s a great time to experiment and explore what it can do.

Track the progress of the Chrome’s implementation over at Chrome Platform Status. You can check Firefox’s work in Bugzilla Ticket #1953973.

More information