DEV Community

FSCSS tutorial for FSCSS tutorial

Posted on

FSCSS auto-loop: percentage keyframes from an array

This snippet builds a stepped “processing 0% → 99% → done” animation by looping an array into @keyframes percentages — not a JS timer.


Setup

  1. npm install -g fscss@latest
  2. VS Code: FSCSS language support (FSCSS Support)
  3. File: my-first-fscss.fscss → compile or runtime-load

Source (your idea, tightened)

h2::after {
  content: "...";
  animation: count 10s steps(100) forwards;
}

/* 1, 2, … 99  (auto list for keyframe stops) */
@arr numlist[count(99)]

@define counter(start:ing..., process:ing..., end:ed){`
  0% {
    content: "@use(start)0%";
  }
  @arr.numlist[]% {
    content: "@use(process)@arr.numlist[]%";
  }
  100% {
    content: "@use(end)";
  }
`}

@keyframes count {
  @counter(Processing..., Processing..., Processed)
}
Enter fullscreen mode Exit fullscreen mode

What “auto-loop” is here

Piece Role
count(99) Builds a numeric list used as 1–99 (engine: count(n) / count(n, 1) → index list).
@arr numlist[…] Stores that list.
@arr.numlist[] Auto-index: expand once per item.
@arr.numlist[]% Each item becomes a keyframe selector: 1%, 2%, … 99%.
@define counter(…) Template for the keyframe body; `@use(start
{% raw %}@counter(…) inside @keyframes Injects the whole ladder into count.

So the loop is compile-time expansion, not for in the browser.


Breakdown

1. Target

h2::after {
  content: "...";
  animation: count 10s steps(100) forwards;
}
Enter fullscreen mode Exit fullscreen mode
  • Animates content on the pseudo-element.
  • steps(100) ≈ one visual step per percent over 10s.
  • forwards keeps the final Processed text.

2. Index array

@arr numlist[count(99)]
Enter fullscreen mode Exit fullscreen mode

Same family as modules indexes: a list long enough to drive stops. Here each value is also the percentage number in the output.

3. Reusable keyframe block

@define counter(start:…, process:…, end:…){` … `}
Enter fullscreen mode Exit fullscreen mode
  • 0% — intro label + 0%.
  • @arr.numlist[]% — for each n in numlist, emit:
    • selector: n%
    • content: "<process>n%"
  • 100% — final label only (e.g. Processed).

4. Wire into a named animation

@keyframes count {
  @counter(Processing..., Processing..., Processed)
}
Enter fullscreen mode Exit fullscreen mode

Expands to a long @keyframes count { … } with ~100 content stops.


Shape of compiled CSS (illustrative)

Exact quoting depends on the compiler; structure is:

h2::after {
  content: "...";
  animation: count 10s steps(100) forwards;
}

@keyframes count {
  0% {
    content: "Processing...0%";
  }
  1% {
    content: "Processing...1%";
  }
  2% {
    content: "Processing...2%";
  }
  /* … */
  99% {
    content: "Processing...99%";
  }
  100% {
    content: "Processed";
  }
}
Enter fullscreen mode Exit fullscreen mode

That is the auto-loop: one array walk → many keyframe rules.


Example HTML

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>FSCSS auto-loop counter</title>
  <script src="https://cdn.jsdelivr.net/npm/fscss@1.2.4/runtime.min.js" async></script>
  <link type="text/fscss" href="my-first-fscss.fscss">
  <!-- or: <link rel="stylesheet" href="my-first-fscss.css"> after CLI -->
  <style>
    body {
      font-family: system-ui, sans-serif;
      padding: 2rem;
      background: #0f172a;
      color: #e2e8f0;
    }
    h2 {
      font-size: 1.25rem;
      font-weight: 600;
    }
    h2::after {
      margin-left: 0.35em;
      color: #38bdf8;
    }
  </style>
</head>
<body>
  <h2>Status</h2>
  <!-- ::after shows Processing...0% → … → Processed -->
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

Compile

fscss my-first-fscss.fscss my-first-fscss.css
Enter fullscreen mode Exit fullscreen mode

Mental model

count(99)  →  list of stops
@arr.x[]%  →  “for each item, emit item% { … }”
@define    →  reuse labels (start / process / end)
@keyframes →  holds the expanded ladder
Enter fullscreen mode Exit fullscreen mode

Auto-loop = array auto-index used as keyframe percentages (or selectors elsewhere), so one definition drives N rules.


Variants

  • Progress label only: change @use(process) strings.
  • Fewer steps: count(20) + shorter animation / steps(20).
  • Same pattern for staggered selectors: .item-@arr.idx[] { animation-delay: … } (as in arrays docs).

Loop the array at compile time; the browser only plays the keyframes.

Top comments (0)