| Hour | Requests | Cache hits | Errors |
|---|---|---|---|
| 00:00 | 340 | 220 | 9 |
| 03:00 | 420 | 270 | 7 |
| 06:00 | 380 | 250 | 12 |
| 09:00 | 550 | 360 | 8 |
| 12:00 | 610 | 410 | 11 |
| 15:00 | 720 | 490 | 14 |
| 18:00 | 830 | 570 | 10 |
| 21:00 | 920 | 630 | 6 |
Show codeHide code
src/chart - 18 files, plus src/behaviour/chart-interact.js
Every chart here is CSS and markup. No canvas, no SVG runtime, no charting library, and no build step. Hover a mark, tab into it, arrow along it, switch a series off from the legend, drag a range. Then turn the script off: every number is still on the page, because the reading was never in the drawing.
The markup panels below are read out of the live examples by site.js. With scripting off the examples still render and the panels stay empty.
Three series, a tooltip anchored to the point, a crosshair, a readout that survives the pointer leaving, arrow-key traversal inside each series, a legend that switches series off, and a brush over the range. Every one of those is optional behaviour on top of markup that already states all twenty-four readings as text.
| Hour | Requests | Cache hits | Errors |
|---|---|---|---|
| 00:00 | 340 | 220 | 9 |
| 03:00 | 420 | 270 | 7 |
| 06:00 | 380 | 250 | 12 |
| 09:00 | 550 | 360 | 8 |
| 12:00 | 610 | 410 | 11 |
| 15:00 | 720 | 490 | 14 |
| 18:00 | 830 | 570 | 10 |
| 21:00 | 920 | 630 | 6 |
Tab once to reach the first series, then use the arrow keys to walk it. Home and End jump to the ends. Enter or Space pins a point. Escape clears the readout. Tab again for the second series, then for the legend buttons, then for the two range handles. The whole chart is four tab stops, not twenty-four, which is what a roving tabindex is for.
The same states on a bar run: hover, focus, selected, and dimmed because another series is being pointed at. Rows on a phone and columns from 30em, because seven upright columns with seven labels under them do not fit in 288 pixels and rows always do. Resize the window and watch it turn.
Rows by default, columns under a modifier, and the value label always outside the track: a number printed inside its own bar is unreadable the moment the bar is shorter than the text, and no CSS can conditionally move it out.
One bar split into parts, and the same parts across categories. The part sizes are raw numbers used as flex-grow values, so the consumer never converts anything to a share and one number changing re-proportions the rest.
Both are one conic gradient with the running totals computed in calc, so the inline values stay the numbers the consumer already has. The legend is the chart; the disc is a second rendering of it and carries aria-hidden for that reason.
Stages and what survives each one. The taper is a clip-path between this stage's width and the next one's, because CSS cannot read a sibling's custom property and anything that hid that fact would be a script.
Part to whole where the parts are too many for a pie. There is no squarify pass here and the file says so first: the spans are chosen once by the consumer, which is the right trade for a budget or a service bill and the wrong one for data that changes shape hourly.
Two coordinates instead of one, and a third carried by size. The points are the same interactive mark as the time series above, so hover, focus, arrow keys, selection and the tooltip all work without a second implementation. This is the chart where the crosshair genuinely wants both lines.
A completion ring, a gauge, a meter with bands, and a sparkline. The first is in this group; the other three already live in the application layer, so this page composes with them rather than shipping a second copy of each.
Elevated. The high mark is 435 GB.
A sample every 800ms, appended without measuring anything: the new mark's height is a custom property, the node is cloned from the mark already in the list, appends arriving inside one frame are coalesced, and the window cap drops the oldest in the same write. An unbounded live list is a memory leak with a chart drawn on it, so the cap is not optional.
The button is a real toggle with aria-pressed, and the feed is a setInterval in the page rather than in the framework: bare.style has no opinion about where data comes from, only about what it costs to draw.
The tile grid, the period selector, and the comparison against the previous period. One column on a phone, two from 48em, four from 80em, and a tile spans two columns only where two exist: under auto-fit a span of two in a grid that resolved to one column creates an implicit second column and puts the page into horizontal scroll.
48,201
12.4% up from 42,900
0.42%
0.19pp down from 0.61%
218ms
31ms up from 187ms
84,120
flat from 84,060
| Page | Sessions | Share | Change |
|---|---|---|---|
| /pricing | 11,204 | 23% | up 8% |
| /docs | 9,880 | 21% | up 14% |
| / | 8,412 | 17% | flat |
| /changelog | 4,109 | 9% | down 3% |
| /status | 2,880 | 6% | up 41% |