{"id":1223,"date":"2026-05-21T08:00:00","date_gmt":"2026-05-21T08:00:00","guid":{"rendered":"https:\/\/computercoursesonline.com\/?p=1223"},"modified":"2026-05-21T20:58:11","modified_gmt":"2026-05-21T20:58:11","slug":"advanced-tree-counting-mathematical-layouts-with-sibling-index-and-sibling-count","status":"publish","type":"post","link":"https:\/\/computercoursesonline.com\/index.php\/2026\/05\/21\/advanced-tree-counting-mathematical-layouts-with-sibling-index-and-sibling-count\/","title":{"rendered":"Advanced Tree Counting: Mathematical Layouts With `sibling-index()` And `sibling-count()`"},"content":{"rendered":"

Advanced Tree Counting: Mathematical Layouts With `sibling-index()` And `sibling-count()`<\/title><\/p>\n<article>\n<header>\n<h1>Advanced Tree Counting: Mathematical Layouts With `sibling-index()` And `sibling-count()`<\/h1>\n<address>Durgesh Pawar<\/address>\n<p> 2026-05-21T08:00:00+00:00<br \/>\n 2026-05-21T20:44:30+00:00<br \/>\n <\/header>\n<p>You know that thing where you have a grid of cards, and you want them to fade in one after another? That staggered cascade effect. Looks great. Should be simple. And yet every time I\u2019ve built it, the implementation has made me feel like I\u2019m doing something fundamentally stupid.<\/p>\n<figure class=\"break-out\">\n<p data-height=\"480\" data-theme-id=\"light\" data-slug-hash=\"zxowBog\" data-user=\"smashingmag\" data-default-tab=\"result\" class=\"codepen\">See the Pen [Dynamic Staggered Animations with CSS sibling-index() [forked]](https:\/\/codepen.io\/smashingmag\/pen\/zxowBog) by <a href=\"https:\/\/codepen.io\/durgeshpawar\">Durgesh<\/a>.<\/p><figcaption>See the Pen <a href=\"https:\/\/codepen.io\/smashingmag\/pen\/zxowBog\">Dynamic Staggered Animations with CSS sibling-index() [forked]<\/a> by <a href=\"https:\/\/codepen.io\/durgeshpawar\">Durgesh<\/a>.<\/figcaption><\/figure>\n<p>Because the options were always the same. Say you want staggered animation delays on a list of 10 items. You either wrote a Sass loop that spat out a dozen <code>:nth-child()<\/code> rules, each one hardcoding a <code>--index<\/code> variable for that specific position:<\/p>\n<pre><code class=\"language-css\">\/* One rule per item. Hope the list never grows. *\/\nli:nth-child(1) { --idx: 1; }\nli:nth-child(2) { --idx: 2; }\nli:nth-child(3) { --idx: 3; }\n\/* ... eight more of these ... *\/\nli:nth-child(10) { --idx: 10; }\n\nli {\n animation-delay: calc(var(--idx) * 100ms);\n}\n<\/code><\/pre>\n<p>Ten items. Ten rules. If the list grows to 50? You cap it and hope for the best, or set up a Sass loop that generates hundreds of selectors at build time. Engineers like Roman Komarov have come up with <a href=\"https:\/\/kizu.dev\/tree-counting-and-random\/\">O(\u00e2\u02c6\u0161N) strategies<\/a> — legitimately clever stuff — but you still end up with 63 rules to cover 1,023 elements.<\/p>\n<p>Or you looped through elements in JavaScript and set inline styles. <code>style="--index: 3"<\/code>. Right there in the DOM. Works fine. Also spreads layout concerns across your scripts and quietly breaks six months later when someone refactors the component without realizing the CSS depends on a JavaScript-injected variable.<\/p>\n<p>Both approaches have always bugged me for the same reason: <strong>you\u2019re telling the browser something it already knows<\/strong>. The browser <em>built<\/em> the DOM tree. It knows which element is the third child. It has the data. <strong>CSS just couldn\u2019t access it.<\/strong><\/p>\n<p>Well, now it can:<\/p>\n<pre><code class=\"language-css\">li {\n animation-delay: calc(sibling-index() * 100ms);\n}\n<\/code><\/pre>\n<p>One line. Works for 5 items or 5,000. No event listeners. No mutation observers. No re-renders.<\/p>\n<p><code>sibling-index()<\/code> and <code>sibling-count()<\/code> are part of the <a href=\"https:\/\/drafts.csswg.org\/css-values-5\/#tree-counting\">CSS Values and Units Module Level 5<\/a> spec (Section 9, if you\u2019re the type who reads W3C drafts for fun). The proposal was <a href=\"https:\/\/github.com\/w3c\/csswg-drafts\/issues\/4559\">approved via CSSWG issue #4559<\/a> after substantial discussion. The functions themselves take no arguments — you just use them.<\/p>\n<ul>\n<li><strong><code>sibling-index()<\/code><\/strong> gives you the 1-based position of an element among its parent\u2019s children. First child returns <code>1<\/code>. Fifth child returns <code>5<\/code>. It only counts element nodes — text nodes, comments, and whitespace are all invisible to it.<\/li>\n<li><strong><code>sibling-count()<\/code><\/strong> gives you the total number of element children the parent has. Basically, the CSS equivalent of <code>element.parentElement.children.length<\/code> in JavaScript, but available in your stylesheet.<\/li>\n<\/ul>\n<p>Both functions resolve to <code><integer><\/code> — not <code><string><\/code>, an actual number. That means you can throw them into <code>calc()<\/code>, <code>min()<\/code>, <code>max()<\/code>, <code>round()<\/code>, <code>mod()<\/code>, trigonometric stuff like <a href=\"https:\/\/web.dev\/articles\/css-trig-functions\"><code>sin()<\/code> and <code>cos()<\/code><\/a>. When you write <code>calc(sibling-index() * 100ms)<\/code>, CSS handles the type coercion and spits out a valid <code><time><\/code> value. No tricks needed. Compare that with <code>counter()<\/code>, which returns a string and can only live inside <code>content<\/code> on pseudo-elements — it\u2019s a different thing entirely.<\/p>\n<p>One clarification that trips people up: <code>:nth-child()<\/code> is a <em>selector<\/em>. It picks elements. It doesn\u2019t produce a value. You can\u2019t write <code>calc(:nth-child() * 10px)<\/code> — that\u2019s not valid CSS. <code>sibling-index()<\/code> does the opposite. It sits inside your declarations and gives you a number you can calculate with. They solve different problems, and until now we\u2019ve been duct-taping <code>:nth-child()<\/code> into a role it was never designed for.<\/p>\n<h2 id=\"patterns-worth-stealing\">Patterns Worth Stealing<\/h2>\n<p>Once it clicks that these are just integers, ideas come fast.<\/p>\n<div data-audience=\"non-subscriber\" data-remove=\"true\" class=\"feature-panel-container\">\n<aside class=\"feature-panel\">\n<div class=\"feature-panel-left-col\">\n<div class=\"feature-panel-description\">\n<p>Meet <strong><a data-instant href=\"https:\/\/www.smashingconf.com\/online-workshops\/\">Smashing Workshops<\/a><\/strong> on <strong>front-end, design & UX<\/strong>, with practical takeaways, live sessions, <strong>video recordings<\/strong> and a friendly Q&A. With Brad Frost, St\u00e9ph Walter and <a href=\"https:\/\/smashingconf.com\/online-workshops\/workshops\">so many others<\/a>.<\/p>\n<p><a data-instant href=\"smashing-workshops\" class=\"btn btn--green btn--large\">Jump to the workshops \u21ac<\/a><\/div>\n<\/div>\n<div class=\"feature-panel-right-col\"><a data-instant href=\"smashing-workshops\" class=\"feature-panel-image-link\"><\/p>\n<div class=\"feature-panel-image\">\n<img loading=\"lazy\" class=\"feature-panel-image-img lazyload\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" alt=\"Feature Panel\" width=\"257\" height=\"355\" data-src=\"\/images\/smashing-cat\/cat-scubadiving-panel.svg\"><\/p>\n<\/div>\n<p><\/a>\n<\/div>\n<\/aside>\n<\/div>\n<h3 id=\"reverse-stagger\">Reverse Stagger<\/h3>\n<p>Want the last item to animate first? Subtract:<\/p>\n<pre><code class=\"language-css\">.card {\n animation: fade-in 0.4s ease both;\n animation-delay: calc((sibling-count() - sibling-index()) * 80ms);\n}\n<\/code><\/pre>\n<p>Last child gets <code>(N - N) * 80ms = 0ms<\/code> — it fires instantly. First child gets <code>(N - 1) * 80ms<\/code>. The animation kicks off the moment the page loads instead of pausing for an awkward beat.<\/p>\n<h3 id=\"automatic-equal-widths\">Automatic Equal Widths<\/h3>\n<p>Stop counting children manually to set percentages:<\/p>\n<pre><code class=\"language-css\">.tab {\n width: calc(100% \/ sibling-count());\n}\n<\/code><\/pre>\n<p>Five tabs? 20% each. Add a sixth? 16.66%. Remove two? 25%. No media queries, no resize observers, no JavaScript at all.<\/p>\n<p>That said, you can imagine a scenario where too many items make for really narrow tabs, at which point you might want to go with something else, perhaps a Flexbox wrapping solution.<\/p>\n<h3 id=\"hue-distribution\">Hue Distribution<\/h3>\n<p>Spread colors evenly across the color wheel:<\/p>\n<pre><code class=\"language-css\">.swatch {\n background-color: hsl(\n calc((360deg \/ sibling-count()) * sibling-index()) 70% 50%\n );\n}\n<\/code><\/pre>\n<p>Three items get hues 120\u00c2\u00b0 apart. Twelve items get 30\u00c2\u00b0 increments. The palette adapts to whatever\u2019s in the DOM, which is the kind of thing you\u2019d normally reach for a JavaScript color library to do.<\/p>\n<h3 id=\"circular-menus\">Circular Menus<\/h3>\n<p>Distributing items in a circle used to mean calculating sine and cosine in JavaScript. CSS now has <a href=\"https:\/\/web.dev\/articles\/css-trig-functions\"><code>sin()<\/code> and <code>cos()<\/code> natively<\/a> (Juan Diego Rodr\u00c3\u00adguez has a great <a href=\"https:\/\/css-tricks.com\/the-most-hated-css-feature-cos-and-sin\/\">practical walkthrough<\/a> of these on CSS-Tricks), and combined with tree-counting, the whole thing collapses into pure CSS:<\/p>\n<pre><code class=\"language-css\">.radial-item {\n --angle: calc((360deg \/ sibling-count()) * sibling-index());\n --radius: 120px;\n\n position: absolute;\n left: calc(50% + var(--radius) * cos(var(--angle)));\n top: calc(50% + var(--radius) * sin(var(--angle)));\n transform: rotate(calc(var(--angle) * -1));\n}\n<\/code><\/pre>\n<p>Six items? Hexagon. Eight? Octagon. Add or remove items, and the layout recalculates. No JavaScript computing coordinates.<\/p>\n<h3 id=\"z-index-stacking\">Z-Index Stacking<\/h3>\n<p>Building a card fan? One line:<\/p>\n<pre><code class=\"language-css\">.card {\n z-index: calc(sibling-count() - sibling-index());\n}\n<\/code><\/pre>\n<p>First card stacks highest, last card gets 0. Flip the math if you want the reverse.<\/p>\n<div class=\"partners__lead-place\"><\/div>\n<h2 id=\"the-gotchas\">The Gotchas<\/h2>\n<p>These are worth going through individually because they\u2019re not obvious from the spec.<\/p>\n<h3 id=\"shadow-dom-scoping\">Shadow DOM Scoping<\/h3>\n<p><code>sibling-index()<\/code> and <code>sibling-count()<\/code> operate on the DOM tree, not the flattened visual tree. This distinction will absolutely bite you with <a href=\"https:\/\/www.smashingmagazine.com\/2025\/07\/web-components-working-with-shadow-dom\/\">Web Components<\/a>.<\/p>\n<p>Say you have a custom element with this shadow DOM:<\/p>\n<pre><code class=\"language-html\"><section>\n <slot><\/slot>\n <div class=\"internal\"><\/div>\n<\/section>\n<\/code><\/pre>\n<p>If you style <code>.internal<\/code> with <code>sibling-index()<\/code>, it returns <code>2<\/code>. Always. Even if the <code><slot><\/code> projects 300 elements. The function sees two children of <code><section><\/code> in the shadow tree — the <code><slot><\/code> and the <code>.internal<\/code> div. Projected light DOM content doesn\u2019t exist as far as the count is concerned.<\/p>\n<p>There\u2019s also a security thing going on here. If a light DOM stylesheet tries to reach into a component via <code>::part()<\/code> and use <code>sibling-index()<\/code>, the browser returns <code>0<\/code>. Flat zero. It\u2019s a deliberate wall to prevent external CSS from probing the internal structure of third-party components. Honestly, I think that\u2019s the right call.<\/p>\n<h3 id=\"pseudo-elements-don-t-count\">Pseudo-Elements Don\u2019t Count<\/h3>\n<p><code>::before<\/code> and <code>::after<\/code> aren\u2019t siblings. They don\u2019t show up in <code>sibling-count()<\/code> and they don\u2019t have their own <code>sibling-index()<\/code>. But — and this is the part that\u2019ll save you a debugging session — you <em>can<\/em> use these functions inside pseudo-element declarations. When you write <code>#target::before { width: calc(sibling-index() * 10px); }<\/code>, it evaluates <code>sibling-index()<\/code> against <code>#target<\/code>, not against the pseudo-element. The pseudo-element isn\u2019t a real node, so the function traces back to its originating element. Same story with <code>::slotted(*)::before<\/code> — it checks the slotted element\u2019s index in the light DOM.<\/p>\n<h3 id=\"display-none-still-counts\"><code>display: none<\/code> Still Counts<\/h3>\n<p>This one burned me. Elements with <code>display: none<\/code> vanish from the layout tree. They take up no space. Screen readers don\u2019t see them. But they\u2019re still in the DOM.<\/p>\n<p>Since <code>sibling-index()<\/code> reads the DOM tree, not the layout tree, hidden elements get counted:<\/p>\n<pre><code class=\"language-html\"><ul>\n <!-- sibling-index() = 1 -->\n <li>Apple<\/li>\n <!-- sibling-index() = 2, invisible -->\n <li style=\"display:none\">Banana<\/li>\n <!-- sibling-index() = 3, NOT 2 -->\n <li>Cherry<\/li> \n<\/ul>\n<\/code><\/pre>\n<p>Cherry is <code>3<\/code>, not <code>2<\/code>. The hidden banana still holds its spot.<\/p>\n<p>This doesn\u2019t matter for most layouts. But if you\u2019re building something like a search filter that hides non-matching items with <code>display: none<\/code>, your staggered animations and circular layouts will develop gaps. The visible items keep their original, non-sequential indexes. For anything that depends on continuous counting — radial menus, proportional widths — you\u2019ll need to actually remove filtered nodes from the DOM instead of just hiding them. Or fall back to JavaScript-managed indexes.<\/p>\n<p><strong>Note:<\/strong> <code>visibility: hidden<\/code> and <code>opacity: 0<\/code> count too, but that feels more intuitive since those elements still take up space. <code>display: none<\/code> is the sneaky one because the element disappears visually but still occupies a DOM slot.<\/p>\n<h4 id=\"custom-properties-evaluate-immediately\">Custom Properties Evaluate Immediately<\/h4>\n<p>This is subtle. If you try to centralize the index on a parent:<\/p>\n<pre><code class=\"language-css\">.parent {\n --idx: sibling-index();\n}\n<\/code><\/pre>\n<p>…that <code>--idx<\/code> resolves right there on <code>.parent<\/code>. It grabs the parent\u2019s own sibling index, locks it to that number, and every child inherits that single fixed value. Every child gets the same number. Almost certainly not what you want or expect.<\/p>\n<p>The fix is simple — put the function on the elements that need it:<\/p>\n<pre><code class=\"language-css\">.child {\n --idx: sibling-index();\n animation-delay: calc(var(--idx) * 100ms);\n}\n<\/code><\/pre>\n<p>The CSSWG has discussed an <code>inherits: declaration<\/code> addition to <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/CSS\/@property\"><code>@property<\/code><\/a> that could theoretically fix this. If you haven\u2019t used <code>@property<\/code>, it lets you define a custom property\u2019s type, initial value, and inheritance behavior — way more control than a raw <code>--variable<\/code>. But the <code>inherits: declaration<\/code> idea is still in early CSSWG discussion, not baked into any spec draft. It could be years before it lands — or it might not land at all. Even with <code>@property<\/code> today, there\u2019s no mechanism to say <em>\u201cdon\u2019t evaluate yet, wait for the child.\u201d<\/em> So for now, just apply directly.<\/p>\n<h3 id=\"performance-at-scale\">Performance at Scale<\/h3>\n<p>Changing the DOM — i.e., adding, removing, reordering children — triggers style recalculation for affected siblings. The browser handles this during the cascade phase (before layout and paint), so it\u2019s faster than the old approach of looping in JavaScript and stamping inline styles.<\/p>\n<p>But there\u2019s a real cost if you push it. Inserting an element at the beginning of a container with 10,000 children forces the engine to recalculate the sibling index for all 10,000 elements after it. For normal stuff — navigation, card grids, tab bars — you\u2019ll never notice. For a live stock ticker or an infinite-scroll feed with thousands of nodes constantly churning, keep using JavaScript-managed indexes inside your virtualization window. These functions are fast. They\u2019re not zero-cost.<\/p>\n<h2 id=\"browser-support\">Browser Support<\/h2>\n<p>As of writing, <a href=\"https:\/\/developer.chrome.com\/blog\/new-in-chrome-138\">Chrome\/Edge 138<\/a> shipped these functions in stable releases (June 2025), and <a href=\"https:\/\/webkit.org\/blog\/17640\/webkit-features-for-safari-26-2\/\">Safari 26.2<\/a> followed. Firefox hasn\u2019t shipped them in stable yet, but Mozilla\u2019s <a href=\"https:\/\/github.com\/mozilla\/standards-positions\/issues\/1194\">spec position is positive<\/a> and implementation work is actively underway — tracked under <a href=\"https:\/\/bugzilla.mozilla.org\/show_bug.cgi?id=1953973\">Bugzilla issue #1953973<\/a>. Check <a href=\"https:\/\/caniuse.com\/wf-sibling-count\">caniuse<\/a> for the latest before you ship.<\/p>\n<p>Chrome and Safari together cover roughly 75–80% of global traffic. That\u2019s a strong majority, but Firefox\u2019s absence means you still need a fallback.<\/p>\n<p>For shipping today, <code>@supports<\/code> is your friend:<\/p>\n<pre><code class=\"language-css\">\/* Baseline that works everywhere *\/\n.item {\n width: 25%;\n animation-delay: 0ms;\n}\n\n\/* Progressively enhance where supported *\/\n@supports (z-index: sibling-index()) {\n .item {\n width: calc(100% \/ sibling-count());\n animation-delay: calc(sibling-index() * 80ms);\n }\n}\n<\/code><\/pre>\n<p>Static fallback for Firefox. Mathematical layout for everyone else. Nobody gets a broken page.<\/p>\n<blockquote><p><strong>On polyfills:<\/strong><\/p>\n<p>A JavaScript polyfill that loops through siblings and sets inline styles is the exact thing these functions exist to replace. But that doesn\u2019t mean you\u2019re stuck with hardcoded fallback values either. Juan Diego Rodr\u00c3\u00adguez wrote a solid piece on \u201c<a href=\"https:\/\/css-tricks.com\/how-to-wait-for-the-sibling-count-and-sibling-index-functions\/\">How to Wait for the <code>sibling-count()<\/code> and <code>sibling-index()<\/code> Functions<\/a>\u201d that lays out the right model for progressive enhancement until native support hits Baseline. His approach uses existing CSS techniques (like Roman Komarov\u2019s <a href=\"https:\/\/kizu.dev\/tree-counting-and-random\/\">counting hacks<\/a>) as a bridge rather than a full JavaScript polyfill. Worth reading if you need to ship something production-ready today while Firefox catches up.<\/p><\/blockquote>\n<div class=\"partners__lead-place\"><\/div>\n<h2 id=\"accessibility-notes\">Accessibility Notes<\/h2>\n<p>This needs saying because it\u2019s easy to get excited and forget: <strong>these functions are purely visual<\/strong>. They change how things look. They don\u2019t change what things <em>mean<\/em>.<\/p>\n<p>If you use <code>sibling-index()<\/code> math to visually reorder a list — via <code>order<\/code> or grid placement — a screen reader still reads the DOM in source order. Keyboard tab order follows the DOM, too. Visual layout and semantic structure will contradict each other, and that\u2019s an accessibility failure.<\/p>\n<p>For interactive components like data grids, radial menus, or custom listboxes that lean on tree-counting for layout, you still need JavaScript to sync ARIA attributes. <code>aria-posinset<\/code> and <code>aria-setsize<\/code> have no idea what CSS is calculating. If your CSS says <em>\u201cthis is visually item 3 of 7\u201d<\/em> but ARIA says something different (or nothing), assistive technology users get a broken experience.<\/p>\n<p>On the debugging side, recent versions of Chrome DevTools let you inspect computed <code>sibling-index()<\/code> and <code>sibling-count()<\/code> values directly in the Elements panel, which helps when the math isn\u2019t doing what you expect.<\/p>\n<figure class=\"\n \n break-out article__image\n \n \n \"><\/p>\n<p> <a href=\"https:\/\/files.smashing.media\/articles\/mathematical-layouts-sibling-index-sibling-count\/sibling-index-devtools.jpeg\"><\/p>\n<p> <img loading=\"lazy\" width=\"800\" height=\"400\" src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" alt=\"sibling-index devtools\" class=\"lazyload\" data-src=\"https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_80\/w_400\/https:\/\/files.smashing.media\/articles\/mathematical-layouts-sibling-index-sibling-count\/sibling-index-devtools.jpeg\"><\/p>\n<p> <\/a><figcaption class=\"op-vertical-bottom\">\n (<a href=\"https:\/\/files.smashing.media\/articles\/mathematical-layouts-sibling-index-sibling-count\/sibling-index-devtools.jpeg\">Large preview<\/a>)<br \/>\n <\/figcaption><\/figure>\n<h2 id=\"what-s-coming\">What\u2019s Coming<\/h2>\n<p>The current spec only counts <em>all<\/em> element siblings. But the CSSWG has documented a planned extension in <a href=\"https:\/\/github.com\/w3c\/csswg-drafts\/issues\/9572\">issue #9572<\/a>: an <code>of <selector><\/code> argument, matching what <code>:nth-child()<\/code> already supports.<\/p>\n<p>Something like <code>sibling-index(of .active)<\/code> would let you count only siblings matching a specific selector. An element that\u2019s the eighth child overall but the third <code>.active<\/code> child would return <code>3<\/code>. For dynamic UIs where you\u2019re filtering or toggling visibility, that would keep the index sequential without requiring DOM manipulation.<\/p>\n<p>There\u2019s also been CSSWG discussion around <a href=\"https:\/\/github.com\/w3c\/csswg-drafts\/issues\/11068\"><code>children-count()<\/code><\/a> and <a href=\"https:\/\/github.com\/w3c\/csswg-drafts\/issues\/11069\"><code>descendant-count()<\/code><\/a> functions — the first would tell you how many children an element has (useful for parent-driven layouts), the second would count all descendants recursively. Both are still at the proposal stage, but they\u2019d round out the tree-counting story: <code>sibling-index()<\/code> and <code>sibling-count()<\/code> give you the horizontal view (where am I among my peers?), while <code>children-count()<\/code> and <code>descendant-count()<\/code> would give you the vertical view (what\u2019s below me?).<\/p>\n<p><em>That feeling I mentioned at the top — writing ten <code>:nth-child()<\/code> rules for a staggered animation and wondering if you\u2019re missing something obvious? You weren\u2019t. The obvious thing just didn\u2019t exist yet.<\/em><\/p>\n<div class=\"signature\">\n <img src=\"data:image\/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" alt=\"Smashing Editorial\" width=\"35\" height=\"46\" loading=\"lazy\" class=\"lazyload\" data-src=\"https:\/\/www.smashingmagazine.com\/images\/logo\/logo--red.png\"><br \/>\n <span>(gg, yk)<\/span>\n<\/div>\n<\/article>\n","protected":false},"excerpt":{"rendered":"<p>Advanced Tree Counting: Mathematical Layouts With `sibling-index()` And `sibling-count()` Advanced Tree Counting: Mathematical Layouts With `sibling-index()` And `sibling-count()` Durgesh Pawar 2026-05-21T08:00:00+00:00 2026-05-21T20:44:30+00:00 You know that thing where you have a grid of cards, and you want them to fade in one after another? That staggered cascade effect. Looks great. Should be simple. And yet every…<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[11],"tags":[],"_links":{"self":[{"href":"https:\/\/computercoursesonline.com\/index.php\/wp-json\/wp\/v2\/posts\/1223"}],"collection":[{"href":"https:\/\/computercoursesonline.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/computercoursesonline.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/computercoursesonline.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/computercoursesonline.com\/index.php\/wp-json\/wp\/v2\/comments?post=1223"}],"version-history":[{"count":1,"href":"https:\/\/computercoursesonline.com\/index.php\/wp-json\/wp\/v2\/posts\/1223\/revisions"}],"predecessor-version":[{"id":1224,"href":"https:\/\/computercoursesonline.com\/index.php\/wp-json\/wp\/v2\/posts\/1223\/revisions\/1224"}],"wp:attachment":[{"href":"https:\/\/computercoursesonline.com\/index.php\/wp-json\/wp\/v2\/media?parent=1223"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/computercoursesonline.com\/index.php\/wp-json\/wp\/v2\/categories?post=1223"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/computercoursesonline.com\/index.php\/wp-json\/wp\/v2\/tags?post=1223"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}