Day page: stop metric cards overflowing the viewport on phones
The #day-body card grid used bare 1fr columns, whose minimum track size is
the widest card's min-content. The humidity ladder's nowrap value ranges
("17.3 g/m³–19.9 g/m³") pushed that minimum past the viewport on phones —
the page scrolled sideways 21px at 390px wide and 51px at 360px — so the
whole Day view sat off-center.
- Size #day-body columns with minmax(0, 1fr) so card content can never
widen the page canvas.
- Collapse the unit repeated on both range bounds ("17.3–19.9 g/m³") and
drop it from the observed ◀ marker; the unit still reads from the card
summary, median, and historical range.
- Let .ladder-val wrap as a last resort instead of nowrap-widening the row.
- Rebalance the mobile ladder tracks (pct 54→46, marker 48→42) so the
longest range stays on one line down to ~375px screens; narrower than
that it wraps cleanly at the unit.
This commit is contained in:
parent
431457132a
commit
e5b1bb0fc2
2 changed files with 35 additions and 10 deletions
|
|
@ -132,6 +132,22 @@ function render(data) {
|
|||
].join("");
|
||||
}
|
||||
|
||||
// Collapse a space-separated unit shared by both bounds ("17.3 g/m³–19.9 g/m³"
|
||||
// → "17.3–19.9 g/m³") so ranges fit the narrow value column on phones. Attached
|
||||
// units (76°, 0.25") pass through untouched.
|
||||
function fmtRange(fmt, lo, hi) {
|
||||
const a = fmt(lo), b = fmt(hi);
|
||||
const i = a.lastIndexOf(" ");
|
||||
if (i > 0 && b.endsWith(a.slice(i))) return `${a.slice(0, i)}–${b}`;
|
||||
return `${a}–${b}`;
|
||||
}
|
||||
// The unit-less value for the ◀ marker — the unit is already on the range beside
|
||||
// it and in the card's summary, and dropping it keeps the marker on one line.
|
||||
const bareVal = (fmt, v) => {
|
||||
const s = fmt(v), i = s.lastIndexOf(" ");
|
||||
return i > 0 ? s.slice(0, i) : s;
|
||||
};
|
||||
|
||||
// One metric card: an observed summary line + the tier ladder (highest tier on
|
||||
// top). The tier the observed value falls into is highlighted with its value.
|
||||
function ladderCard(title, m, fmt, kind) {
|
||||
|
|
@ -153,7 +169,7 @@ function ladderCard(title, m, fmt, kind) {
|
|||
? `median ${fmt(m.ladder.median)}`
|
||||
: `${m.ladder.rain_days.toLocaleString()} rain days · dry ${m.ladder.dry_pct}%`;
|
||||
const note = `<span class="ladder-note-left">${noteLeft}</span>` +
|
||||
`<span class="ladder-range">Historical Range ${fmt(m.ladder.min)}–${fmt(m.ladder.max)}</span>`;
|
||||
`<span class="ladder-range">Historical Range ${fmtRange(fmt, m.ladder.min, m.ladder.max)}</span>`;
|
||||
|
||||
const rows = m.ladder.tiers.map((t) => {
|
||||
const active = t.c === activeClass ? " active" : "";
|
||||
|
|
@ -163,9 +179,9 @@ function ladderCard(title, m, fmt, kind) {
|
|||
if (t.c === "dry") { val = t.range; pct = ""; }
|
||||
else if (t.hi == null) val = `> ${fmt(t.lo)}`; // top tier: strictly beyond p99
|
||||
else if (t.lo == null) val = `< ${fmt(t.hi)}`; // bottom tier: strictly below p1
|
||||
else val = `${fmt(t.lo)}–${fmt(t.hi)}`;
|
||||
else val = fmtRange(fmt, t.lo, t.hi);
|
||||
const marker = t.c === activeClass && obs
|
||||
? `<span class="ladder-mark">◀ ${fmt(obs.value)}</span>` : "";
|
||||
? `<span class="ladder-mark">◀ ${bareVal(fmt, obs.value)}</span>` : "";
|
||||
return `<div class="ladder-row${active}">
|
||||
<span class="ladder-sw" style="background:${tierColor(t.c)}"></span>
|
||||
<span class="ladder-label" style="--cat:${tierColor(t.c)}">${t.label}</span>
|
||||
|
|
|
|||
|
|
@ -459,10 +459,12 @@ main { max-width: 1200px; margin: 0 auto; padding: 20px 24px 60px; }
|
|||
.day-step:disabled { opacity: .4; cursor: default; }
|
||||
|
||||
/* Metric cards: one column on phones, side by side on monitors so the page
|
||||
doesn't run as a single long strip of full-width ladders. */
|
||||
#day-body { display: grid; grid-template-columns: 1fr; gap: 16px; align-items: start; }
|
||||
@media (min-width: 1000px) { #day-body { grid-template-columns: repeat(2, 1fr); } }
|
||||
@media (min-width: 3400px) { #day-body { grid-template-columns: repeat(3, 1fr); } }
|
||||
doesn't run as a single long strip of full-width ladders. minmax(0, 1fr)
|
||||
(not bare 1fr, whose min is the content) so one wide ladder row can't inflate
|
||||
the shared column track past the viewport and push the whole page off-center. */
|
||||
#day-body { display: grid; grid-template-columns: minmax(0, 1fr); gap: 16px; align-items: start; }
|
||||
@media (min-width: 1000px) { #day-body { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
|
||||
@media (min-width: 3400px) { #day-body { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
|
||||
|
||||
.ladder-card {
|
||||
background: var(--surface); border: 1px solid var(--border);
|
||||
|
|
@ -502,10 +504,14 @@ main { max-width: 1200px; margin: 0 auto; padding: 20px 24px 60px; }
|
|||
.ladder-sw { width: 14px; height: 14px; border-radius: 4px; }
|
||||
.ladder-label { font-weight: 700; color: color-mix(in oklab, var(--cat, var(--text)), var(--text) 22%); }
|
||||
.ladder-pct { color: var(--muted); font-size: 12px; }
|
||||
.ladder-val { justify-self: end; font-variant-numeric: tabular-nums; white-space: nowrap; }
|
||||
/* Value ranges may wrap (long unit strings like "8.1 g/m³–12.9 g/m³" on narrow
|
||||
phones) — nowrap here would widen the row past the card and scroll the page. */
|
||||
.ladder-val { justify-self: end; text-align: right; font-variant-numeric: tabular-nums; }
|
||||
/* Observed marker: stays in the rightmost column but reads from its left edge,
|
||||
so the arrow sits right beside the value range it points at. */
|
||||
.ladder-mk { justify-self: start; min-width: 0; }
|
||||
/* Markers are unit-less ("◀ 11.5") so nowrap can't push them past the card —
|
||||
the widest (precip, ◀ 0.25") bleeds a few px into the row padding at most. */
|
||||
.ladder-mark { color: var(--accent); font-weight: 800; white-space: nowrap; font-size: 12.5px; }
|
||||
|
||||
|
||||
|
|
@ -857,10 +863,13 @@ main { max-width: 1200px; margin: 0 auto; padding: 20px 24px 60px; }
|
|||
#cal-tip .tt-type { font-size: 13.5px; margin: 1px 0 5px; padding-bottom: 5px; }
|
||||
#cal-tip .tt-grid { column-gap: 8px; row-gap: 2px; }
|
||||
/* Day ladder on mobile: tighten the fixed tracks but keep every column (including
|
||||
the percentile range) so the ranges still line up down the ladder. */
|
||||
the percentile range) so the ranges still line up down the ladder. Slack moved
|
||||
from the pct/marker tracks to the value column keeps the longest range
|
||||
("17.3–19.9 g/m³", ~88px) on one line down to ~375px screens; narrower than
|
||||
that it wraps at the unit. The label track can't give ("Above Normal" ≈ 89px). */
|
||||
.day-nav { width: 100%; }
|
||||
.day-date { flex: 1; }
|
||||
.ladder-row { grid-template-columns: 13px 90px 54px 1fr 48px; column-gap: 8px; font-size: 12.5px; }
|
||||
.ladder-row { grid-template-columns: 13px 90px 46px 1fr 42px; column-gap: 8px; font-size: 12.5px; }
|
||||
|
||||
header { padding: 14px 16px; }
|
||||
h1 { font-size: 19px; }
|
||||
|
|
|
|||
Loading…
Reference in a new issue