Stop the ranked charts from spilling over the tables below them
CI / test (push) Successful in 1m32s

The bars were wrapped in <div class="chart">, and .chart was already the
fixed-height box the time-series charts are drawn in: 120px, with a border
and a background. A chart that grows a row at a time does not fit in a cage,
so the SVG overflowed it and landed on the table underneath.

Renamed to .ranked, which is a wrapper rather than the mark itself, and
capped at the design width so a wide window scales the box instead of
inflating the 12px labels.

The test reads the class back out of the markup and checks the stylesheet
does not cap it, because the collision was invisible in both files on their
own — each rule was reasonable, and only the shared name was wrong.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ilker ManapandClaude Opus 5 committed 2026-09-17 19:06:53 +02:00
1 parent eb9e9b348c
commit f8bb78103f
3 files changed
+38 -3

No files matched your search

+1 -1
View File
@@ -54,7 +54,7 @@ func HBarChart(rows []Row, colour, unit string) template.HTML {
plotW := width - labelW - valueW
var b strings.Builder
fmt.Fprintf(&b, `<div class="chart"><svg viewBox="0 0 %.0f %.0f" role="img" `+
fmt.Fprintf(&b, `<div class="ranked"><svg viewBox="0 0 %.0f %.0f" role="img" `+
`preserveAspectRatio="xMinYMin meet" aria-label="ranked bars">`, width, height)
for i, r := range rows {
+31
View File
@@ -115,3 +115,34 @@ func TestTheChartScalesToItsContainer(t *testing.T) {
t.Error("a fixed pixel width was set on the chart")
}
}
func TestTheRankedWrapperIsNotGivenAFixedHeight(t *testing.T) {
// This chart grows a row at a time, so whatever class it wears must not be
// one the stylesheet caps. It wore "chart", which is the fixed-height box
// the time-series charts live in, and the bars spilled over the table
// underneath them.
out := string(HBarChart([]Row{{Label: "a", Value: 1}}, "", ""))
class := "" // the wrapper's class, read back out of the markup
if i := strings.Index(out, `<div class="`); i >= 0 {
rest := out[i+len(`<div class="`):]
class = rest[:strings.Index(rest, `"`)]
}
if class == "" {
t.Fatalf("no wrapper to check:\n%s", out)
}
css, err := staticFiles.ReadFile("static/base.css")
if err != nil {
t.Fatal(err)
}
for _, line := range strings.Split(string(css), "\n") {
decl, ok := strings.CutPrefix(strings.TrimSpace(line), "."+class+" ")
if !ok || !strings.HasPrefix(decl, "{") {
continue
}
if strings.Contains(decl, "height:") && !strings.Contains(decl, "height: auto") {
t.Errorf("%q is capped by the stylesheet, so taller charts overflow it: %s",
class, strings.TrimSpace(line))
}
}
}
+6 -2
View File
@@ -164,5 +164,9 @@ select { font: inherit; padding: .35rem .4rem; border: 1px solid var(--line);
.tile .v { font-size: 1.5rem; line-height: 1.1; font-variant-numeric: tabular-nums; }
.tile .k { font-size: .8rem; color: var(--muted); }
.tile svg { display: block; margin-top: .35rem; }
.chart { margin: .25rem 0 1rem; }
.chart svg { display: block; max-width: 100%; height: auto; }
/* Ranked horizontal bars. A wrapper, not the SVG itself: .chart above is the
* fixed-height time-series box, and sharing the name gave these a 120px cage
* their taller content overflowed, over the table beneath them. Capped at the
* design width so scaling up never inflates the 12px labels. */
.ranked { margin: .25rem 0 1rem; }
.ranked svg { display: block; width: 100%; max-width: 720px; height: auto; }