Commit e1a9f52605

e1a9f52605bcbb486290e7fa10b63ddf596cf65b

parent: f39a596ecd

Verified · cmc

cmc <hello@cleberg.net> · 2026-09-19 22:52 UTC

web: sticky columns scroll, and a phone keeps its wrapping

A sticky column taller than the viewport had an unreachable tail once
the page scrolled: .filenav, .sidecol and the dashboard aside cap at the
viewport and scroll inside themselves, above 62rem only.

.meta on the one-line rows kept white-space: nowrap below 62rem, so a
long branch name or a long owner/repo#N forced horizontal page scroll.
.meta and .topics reset there beside .title and .desc.

The pinned chip row moves to the 80rem block: the pinned block is a chip
row whenever it is not a column (spec rule 7), rather than a full-width
bordered list with its counts at the far edge between 62 and 80rem.

h2.empty has no user left now the dashboard prints no empty headings.
main.wide folds into the shared container rule.

Ref #226
internal/web/layout_test.go +1 −1
@@ -19,7 +19,7 @@ func TestSharedCenteredContainer(t *testing.T) {
1919 css := string(StyleCSS)
2020 for _, want := range []string{
2121 "--container: 100rem;",
22 "main.content, footer { max-width: calc(var(--container) + 2 * var(--sp-6)); margin: 0 auto; }",
22 "main.content, main.wide, footer { max-width: calc(var(--container) + 2 * var(--sp-6)); margin: 0 auto; }",
2323 ".repohead .wrap { max-width: calc(var(--container) + 2 * var(--sp-6)); margin: 0 auto; padding: 0 var(--sp-6); }",
2424 "main.reading { max-width: calc(72rem + 2 * var(--sp-6)); margin: 0 auto; }",
2525 "main.bounded { max-width: calc(48rem + 2 * var(--sp-6)); margin: 0 auto; }",
internal/web/static/style.css +21 −8
@@ -375,8 +375,9 @@ main.content {
375375 width: 100%;
376376 padding: var(--sp-5) var(--sp-6) var(--sp-7);
377377}
378main.content, footer { max-width: calc(var(--container) + 2 * var(--sp-6)); margin: 0 auto; }
379main.wide { max-width: calc(var(--container) + 2 * var(--sp-6)); }
378/* the container is the default width and what `wide` names; reading and
379 bounded follow, so equal specificity gives them the cascade */
380main.content, main.wide, footer { max-width: calc(var(--container) + 2 * var(--sp-6)); margin: 0 auto; }
380381main.reading { max-width: calc(72rem + 2 * var(--sp-6)); margin: 0 auto; }
381382main.bounded { max-width: calc(48rem + 2 * var(--sp-6)); margin: 0 auto; }
382383footer {
@@ -1410,6 +1411,14 @@ a.memberchip .role { color: var(--muted); }
14101411.sidecol form.searchform { margin-top: var(--sp-2); }
14111412.sidecol form.searchform input[type="text"] { min-width: 0; width: 100%; }
14121413
1414/* a sticky column taller than the viewport scrolls inside itself, or its
1415 tail is unreachable once the page scrolls. Above 62rem only: below it
1416 .filenav is hidden and the other two are static. .dashpins stops being
1417 a column at 80rem and resets both properties there. */
1418@media (min-width: 62.01rem) {
1419 .filenav, .sidecol, .dashgrid > aside { max-height: calc(100vh - 2 * var(--sp-4)); overflow-y: auto; }
1420}
1421
14131422.refchip {
14141423 display: inline-flex;
14151424 align-items: center;
@@ -1543,7 +1552,6 @@ pre.quickstart { margin: 0 0 var(--sp-4); }
15431552.profilehead .meta { margin: var(--sp-1) 0 0; }
15441553.activity { margin-bottom: var(--sp-5); }
15451554h2 .count { background: none; color: var(--muted); font-weight: 400; font-size: var(--fs-2); margin-left: var(--sp-2); padding: 0; }
1546h2.empty { color: var(--muted); font-weight: 500; font-size: var(--fs-3); margin: var(--sp-2) 0; }
15471555/* 53 week columns x 7 day rows, tinted with the link blue */
15481556.actgraph-scroll { overflow-x: auto; padding-bottom: var(--sp-1); }
15491557.actgraph { display: flex; gap: 3px; width: max-content; padding-top: 18px; }
@@ -1599,7 +1607,12 @@ svg.icon { vertical-align: -0.125em; }
15991607/* ---- breakpoints ---- */
16001608@media (max-width: 80rem) {
16011609 .dashgrid { grid-template-columns: minmax(0, 1fr) 20rem; }
1602 .dashgrid > .dashpins { grid-column: 1 / -1; position: static; }
1610 /* not a column any more, so it neither sticks nor scrolls in itself */
1611 .dashgrid > .dashpins { grid-column: 1 / -1; position: static; max-height: none; overflow: visible; }
1612 /* a pinned block that is not a column is the chip row (spec rule 7) */
1613 .pins { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
1614 .pins li { border: 1px solid var(--line); border-radius: var(--r-ctl); padding: var(--sp-1) var(--sp-3); }
1615 .pins .n, .dashpins .meta { display: none; }
16031616}
16041617
16051618@media (max-width: 62rem) {
@@ -1610,13 +1623,13 @@ svg.icon { vertical-align: -0.125em; }
16101623 /* rows go back to two lines where one does not fit */
16111624 ul.issuelist.rows .issuemain, ul.repolist.rows li, ul.loglist.rows .commitmain { display: block; }
16121625 ul.issuelist.rows .title, ul.repolist.rows .desc { white-space: normal; }
1626 /* a nowrap meta or topic line on one of these rows forces horizontal
1627 page scroll on a phone: a long branch name, a long owner/repo#N */
1628 ul.issuelist.rows .meta, ul.loglist.rows .meta,
1629 ul.repolist.rows .meta, ul.repolist.rows .topics { white-space: normal; }
16131630
16141631 .dashgrid { grid-template-columns: 1fr; }
16151632 .dashgrid > aside { position: static; }
1616 /* the pinned column goes back to a chip row on a phone */
1617 .pins { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
1618 .pins li { border: 1px solid var(--line); border-radius: var(--r-ctl); padding: var(--sp-1) var(--sp-3); }
1619 .pins .n, .dashpins .meta { display: none; }
16201633 .tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); }
16211634
16221635 /* the tree page is the navigator on a phone */