Most chart libraries solve the same problem with the same tools: Canvas, SVG, a JavaScript runtime, and a bundle that adds weight to every page that loads it.
st-core.fscss takes a different approach. No SVG. No Canvas. No runtime rendering. Just CSS doing the work it was always capable of doing.
The Core Idea
st-core.fscss uses three browser-native features to render charts:
-
clip-path: polygon()to draw the chart shape - CSS custom properties (
--st-p1through--st-p8) to store data points - FSCSS mixins to generate the chart structure at compile time
The flow is straightforward:
data → CSS variables → clip-path → visual chart
Once compiled, your stylesheet contains only what your charts need. No runtime overhead. No extra depth added to your HTML. If you use the CDN, you are loading a small FSCSS loader and nothing else.
Multi-Line Charts
The multi-line chart is a good example of how the architecture stays clean even as complexity grows.
The key concept is one renderer, multiple datasets. You define a single @st-chart-line renderer and let each line element carry its own data via scoped CSS variables.
<script src="https://cdn.jsdelivr.net/npm/fscss@1.1.24/exec.min.js" async></script>
<style>
@import((*) from st-core)
@st-root()
.chart {
height: 200px;
position: relative;
@st-chart-points(20, 25, 21, 37, 30, 60, 27, 50)
}
@st-chart-line(.chart-line)
.chart-line {
background: currentColor;
@st-chart-line-width(2px);
}
.line-1 { color: #32D8D4; }
.line-2 {
color: #E8A030;
@st-chart-points(10, 20, 16, 15, 66, 50, 80, 54)
}
.line-3 {
color: #B840C8;
@st-chart-points(5, 39, 20, 30, 27, 70, 60, 70)
}
@st-chart-grid(.chart-grid, 10, 7)
@st-chart-axis-y(.y-axis)
@st-chart-axis-x(.x-axis)
</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>
<div class="x-axis">
<span>Sun</span><span>Mon</span><span>Tue</span>
<span>Wed</span><span>Thu</span><span>Fri</span><span>Sat</span>
</div>
Each line element overrides its own dataset independently. The renderer reads whichever --st-p* variables are scoped to that element. The result is composable and predictable.
Available Mixins
| Mixin | Output |
|---|---|
@st-chart-line |
Line renderer |
@st-chart-fill |
Area chart fill |
@st-chart-dot |
Data point markers |
@st-chart-grid |
Background grid |
@st-chart-axis-x / @st-chart-axis-y
|
Axis label layout |
All generated at compile time.
Real-Time Updates
For dynamic data, you can update chart variables directly from JavaScript:
chart.style.cssText = `
--st-p1: 40%;
--st-p2: 75%;
--st-p3: 60%;
`;
JavaScript passes the values. CSS handles the rendering. Animations work automatically if you have a transition defined.
Why It Works This Way
No heavy dependencies to install or maintain. The browser's own rendering pipeline does the visual work, so performance stays native. Your data lives in CSS as plain custom properties, not inside a configuration object or a framework component. And because you write the styles yourself, nothing about the chart's appearance is locked into a preset.
Live Demo
fscss-ttr.github.io/st-core.fscss/multi-chart
st-core.fscss is a new and actively maintained open source project. If the approach interests you, contributions are welcome. Explore the repo on GitHub and try building your own chart system.