Search code examples
htmlcsscss-variables

Can a recursive variable be expressed in css?


For the html:

<body>
<div>
  <div>
    <div>
      ...
    </div>
  </div>
</div>
</body>

Are there any ways to create a recursive variable that uses its parent's value:

body > div {
    --x: 1;
}

div {
    --x: calc(var(--x) + 1);
}

The above is not valid because css variables cannot have dependency cycles. Another invalid example:

body > div {
    --is-even: 0;
    --is-odd: 1;
}

div {
    --is-even: var(--is-odd);
    --is-odd: var(--is-even);
}

Are there any indirect ways to express such recursive variables in css?


Solution

  • You can use two CSS variables to simulate the recursive behavior and avoid cycle dependency.

    Here is an example:

    body {
      --x: 10;
    }
    .y {
      --y: calc(var(--x) + 1);
    }
    .x{
      --x: calc(var(--y) + 1);
    }
    .result {
      border-right:calc(1px * var(--y)) solid red;
      border-left:calc(1px * var(--x)) solid green;
      height:50px;
    }
    <body>
      <div class="y">
        <div class="x">
          <div class="y">
            <div class="x">
              <div class="y">
                <div class="x">
                  <div class="y result">
    
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </body>

    If you inspect the element you will find for the last element that border-right is equal to 17px (10 + 7) and border-left is equal to 16px (10 + 6)

    enter image description here

    This idea fits nicely in elements with a 2 level structure, like lists:

    body {
      --x: 30;
    }
    
    ul { 
        font-size: calc(var(--x) * 1px);
        --y: calc(var(--x) - 8);
    }
    
    li {
      --x: calc(var(--y));
    }
      <ul>level A
        <li>item 1
        </li>
        <li>item 2
          <ul>level B
            <li>item 2.1
              <ul>level C
                <li>item 2.1.1
                </li>
                <li>item 2.1.2
                </li>
              </ul>
            </li>
            <li>item 2.2
            </li>
          </ul>
        </li>
      </ul>