Search code examples
csssass

CSS property value based on the child --index. Can it be done purelly with CSS or at least Sass?


I've built a Counter widget that has some animations options. One of those are the numbers appearing, one at a time. To achive this, the HTML output separates each number on it's own span tag.

<span class="ui-e-num"> 
    <span>1</span>
    <span>3</span>
    <span>5</span>
    <span>+</span>
</span>

The CSS is:

.ui-e-num span {
    display: inline-block;
    opacity: 0;
    translate: 0 -60px;
    text-shadow: 0 15px 10px var(--parent-num-color);
    filter: blur(2px);
    transition: translate 320ms cubic-bezier(0, 0, 0.17, 1), text-shadow 360ms ease-out, filter 360ms ease-out, opacity 200ms ease-in;
}

.ui-e-num.active span {
    opacity: 1;
    translate: 0 0;
    text-shadow: 0 0 0 transparent;
    filter: blur(0);
}

The challenge is that all .ui-e-num span childs needs a transition-delay that is increased for each one. Based on the code I inserted here, the number <span>1</span> would have a transition-delay: 100ms; the number <span>1</span> would have transition-delay:200ms and so on.

This can be achieved with JS of course, but I wanted to built it with CSS only, however I can't figure it out how the could would look like.

I've built a sass foreach to achieve this, but it seens like there's a better and more optimized way of doing this with less code.


Solution

  • The short answer is no, you can't do that with basic CSS, some CSS compilers (SASS/SCSS) may allow you to write something that gets that result, but would likely create more CSS than you actually need.

    However, you can pass in a custom CSS variable to each entry and make use of that in the CSS as if it were a variable increasing over the number of children; it doesn't require any JavaScript.

    See below for the snippet:

    function toggleClass() {
      document.getElementsByClassName("ui-e-num")[0].classList.toggle("active");
    }
    .ui-e-num span {
      display: inline-block;
      opacity: 0;
      translate: 0 -60px;
      text-shadow: 0 15px 10px var(--parent-num-color);
      filter: blur(2px);
      transition: translate 320ms cubic-bezier(0, 0, 0.17, 1), text-shadow 360ms ease-out, filter 360ms ease-out, opacity 200ms ease-in;
      /* make use of the `--n` value */
      transition-delay: calc(200ms * var(--n));
    }
    
    .ui-e-num.active span {
      opacity: 1;
      translate: 0 0;
      text-shadow: 0 0 0 transparent;
      filter: blur(0);
    }
    <span class="ui-e-num">
      <!-- set the `--n` value here -->
      <span style="--n: 1;">1</span>
      <span style="--n: 2;">3</span>
      <span style="--n: 3">5</span>
      <span style="--n: 4;">+</span>
    </span>
    
    
    <button type="button" onclick="toggleClass();">Toggle Active class</button>

    Note: I've added in the button just so you can toggle the active class on and off.

    N.B: This question is quite similar to this one, but focuses on nth-child for which this answer was the best inspiration (but it's not the accepted answer on that question)