DEV Community

Cover image for St-core.fscss Multi-Line Chart Pure CSS
FSCSS tutorial for FSCSS tutorial

Posted on

St-core.fscss Multi-Line Chart Pure CSS

st-core.fscss is a pure-CSS charting system that renders line charts with no SVG, no Canvas, and no JavaScript charting library. It uses:

  • clip-path: polygon() for the line shapes
  • CSS custom properties (--st-p1--st-p8) for the 8 data points
  • FSCSS mixins that expand at compile/runtime into the required CSS

How Multi-Line Charts Work

You declare one @st-chart-line renderer. Every element that matches the class becomes an independent line.

  • The chart container can hold a default dataset (@st-chart-points).
  • Line 1 inherits that default.
  • Additional lines override with their own @st-chart-points.
  • Each line gets its own color via background or color.

X positions are fixed (0 %, 14 %, 28 %, 42 %, 57 %, 71 %, 85 %, 100 %).

Y values are given on a 0–100 scale (100 = top of the chart). The library inverts them internally for CSS coordinates.

Complete Multi-Line Chart Example

<script src="https://cdn.jsdelivr.net/npm/fscss@1.1.24/exec.min.js" async></script>

<style>
@import((*) from st-core)

@st-root()

.chart {
  position: relative;
  height: 200px;
  background: var(--st-surface);
  border-radius: var(--st-radius-lg);
  overflow: hidden;
  /* default dataset – inherited by line-1 */
  @st-chart-points(20, 25, 21, 37, 30, 60, 27, 50)
}

/* single renderer for all lines */
@st-chart-line(.chart-line)

.chart-line {
  @st-chart-line-width(2.5px)
}

/* line-1 inherits container data */
.line-1 {
  background: #32D8D4;
}

/* line-2 has its own dataset */
.line-2 {
  background: #E8A030;
  @st-chart-points(10, 20, 16, 15, 66, 50, 80, 54)
}

/* line-3 has its own dataset */
.line-3 {
  background: #B840C8;
  @st-chart-points(5, 39, 20, 30, 27, 70, 60, 70)
}

/* optional grid + axes */
@st-chart-grid(.chart-grid, 10, 7)
@st-chart-axis-y(.y-axis)

.chart-grid {
  opacity: 0.08;
}
</style>

<div class="chart">
  <div class="chart-line line-1"></div>
  <div class="chart-line line-2"></div>
  <div class="chart-line line-3"></div>
  <div class="chart-grid"></div>
  <div class="y-axis">
    <span>0</span><span>20</span><span>40</span>
    <span>60</span><span>80</span><span>100</span>
  </div>
</div>
Enter fullscreen mode Exit fullscreen mode

Key Rules

Rule Explanation
One renderer @st-chart-line(.chart-line) is declared once
Default data Container’s @st-chart-points is inherited by the first line
Overrides Later lines set their own @st-chart-points
Color Set with background (or color + currentColor)
Line thickness @st-chart-line-width(2.5px) (default is 1.5 px)
Grid / axes Optional helpers for visual polish

Design Tokens (@st-root)

Call @st-root() once (usually at the top of your stylesheet). It injects these CSS custom properties:

Colors

Token Default Purpose
--st-bg #0e0d14 Page background
--st-surface #161422 Chart / surface background
--st-card #1c1a2e Card background
--st-accent #9d7eff Primary accent
--st-accent-2 #c4a8ff Secondary accent
--st-accent-dim #3a2e6e Dimmed accent
--st-green #4fffb0 Positive / up
--st-red #ff5e7d Negative / down
--st-text #e8e3ff Primary text
--st-muted #6b6488 Muted text / axis labels
--st-border rgba(157,126,255,.15) Borders

Radius & Spacing

Token Default
--st-radius-xl 40px
--st-radius-lg 16px
--st-radius-md 12px
--st-radius-sm 10px
--st-pad 24px

Chart-specific

Token Default Purpose
--st-p1--st-p8 sample values Y data points
--st-chart-line-width 1.5px Stroke thickness

You can override any token globally or scoped to a single chart:

.chart {
  --st-accent: #32D8D4;
}
Enter fullscreen mode Exit fullscreen mode

HTML Structure Summary

<div class="chart">                 <!-- container + default data -->
  <div class="chart-line line-1"></div>  <!-- inherits default data -->
  <div class="chart-line line-2"></div>  <!-- own @st-chart-points -->
  <div class="chart-line line-3"></div>  <!-- own @st-chart-points -->
  <div class="chart-grid"></div>         <!-- optional -->
  <div class="y-axis"></div>            <!-- optional -->
</div>
<div class="x-axis"></div>              <!-- optional, usually outside -->
Enter fullscreen mode Exit fullscreen mode

Runtime Data Updates (optional JS)

Because data lives in CSS variables, you can update any line by writing properties:

const line2 = document.querySelector('.line-2');
[15, 30, 25, 40, 55, 45, 70, 60].forEach((v, i) => {
  line2.style.setProperty(`--st-p${i + 1}`, `${100 - v}%`);
});
Enter fullscreen mode Exit fullscreen mode

The browser repaints the clip-path automatically — no redraw library needed.

Sources

Repository and examples:
Help us star the repo if it helps 🙏

This gives you a zero-JS-runtime (or near-zero) multi-series line chart that stays extremely lightweight.


Top comments (0)