Scroll the note list, not the page
With a hundred notes in it the list grew to its full height, the page scrolled instead of the list, and the editor — a flex sibling stretching to the row — became as tall as every note put together: 12419px next to a 700px window. The cause was one word. `body` had `min-height: 100dvh`, which leaves the page free to grow with its content, and a column of flex boxes with no definite height at the top cannot cap anything below it. `min-height: 0` on the items lets them shrink but nothing was telling them what to shrink *to*. The page now has a definite height and no scrolling of its own, so the two panes do the scrolling, which is what they were built for. The settings screen and the login screen scroll themselves, having no pane. While there: the editor's floor drops from 12rem to 6rem so a landscape phone with its keyboard up keeps the toolbar and the save button on screen rather than overflowing, and the login card centres with `margin: auto` rather than `justify-content`, because a centred flex item in a scrolling container cannot be scrolled back to once it overflows the top. Reproduced with 123 seeded day notes and measured in Firefox at 1100px and 390px, before and after: page 12684px → 700px, list scrolls itself, editor 12419px → 435px, toolbar and save button still on screen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -36,18 +36,34 @@
|
|||||||
|
|
||||||
* { box-sizing: border-box; }
|
* { box-sizing: border-box; }
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A *definite* height, not a minimum.
|
||||||
|
*
|
||||||
|
* `min-height` leaves the page free to grow with its content, and a column of
|
||||||
|
* flex boxes with no definite height at the top cannot cap anything below it:
|
||||||
|
* with a hundred notes in the list, the list grew to its full height, the page
|
||||||
|
* scrolled instead of the list, and the editor — a flex sibling stretching to
|
||||||
|
* the row — became as tall as every note put together. Scrolling belongs to the
|
||||||
|
* two panes, so the page itself must not have any.
|
||||||
|
*/
|
||||||
body {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
background: var(--bg);
|
background: var(--bg);
|
||||||
color: var(--fg);
|
color: var(--fg);
|
||||||
/* Fills the viewport on a phone, where 100vh lies about the toolbar. */
|
height: 100vh;
|
||||||
min-height: 100dvh;
|
/* dvh where it exists: 100vh lies about the height while a phone's toolbar
|
||||||
|
is on screen. */
|
||||||
|
height: 100dvh;
|
||||||
|
overflow: hidden;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left);
|
padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left);
|
||||||
}
|
}
|
||||||
|
|
||||||
.screen { display: flex; flex-direction: column; flex: 1; min-height: 0; }
|
.screen { display: flex; flex-direction: column; flex: 1; min-height: 0; overflow: hidden; }
|
||||||
|
|
||||||
|
/* The page does not scroll, so anything that is not itself a pane must. */
|
||||||
|
#login, #view-settings { overflow-y: auto; }
|
||||||
[hidden] { display: none !important; }
|
[hidden] { display: none !important; }
|
||||||
|
|
||||||
/* --- chrome ------------------------------------------------------------ */
|
/* --- chrome ------------------------------------------------------------ */
|
||||||
@@ -85,6 +101,7 @@ header { border-bottom: 1px solid var(--line); }
|
|||||||
.rail {
|
.rail {
|
||||||
flex: 0 0 18rem;
|
flex: 0 0 18rem;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
|
min-height: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
border-right: 1px solid var(--line);
|
border-right: 1px solid var(--line);
|
||||||
@@ -147,7 +164,18 @@ header { border-bottom: 1px solid var(--line); }
|
|||||||
|
|
||||||
.row mark { background: color-mix(in srgb, var(--accent) 28%, transparent); color: inherit; border-radius: 0.15rem; }
|
.row mark { background: color-mix(in srgb, var(--accent) 28%, transparent); color: inherit; border-radius: 0.15rem; }
|
||||||
|
|
||||||
.detail { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 0.5rem; padding: 0.75rem; min-height: 0; }
|
.detail {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
min-height: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.5rem;
|
||||||
|
padding: 0.75rem;
|
||||||
|
/* The editor inside it scrolls; the pane itself never does, so the toolbar
|
||||||
|
and the save button cannot be pushed off a short screen. */
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
/* Only a phone needs a way back to the list; on a wide screen it is never gone. */
|
/* Only a phone needs a way back to the list; on a wide screen it is never gone. */
|
||||||
.back { display: none; align-self: flex-start; padding: 0.4rem 0.7rem; font-size: 0.9rem; }
|
.back { display: none; align-self: flex-start; padding: 0.4rem 0.7rem; font-size: 0.9rem; }
|
||||||
@@ -232,7 +260,9 @@ header { border-bottom: 1px solid var(--line); }
|
|||||||
*/
|
*/
|
||||||
.editor {
|
.editor {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-height: 12rem;
|
/* Small enough that a landscape phone with its keyboard up still shows the
|
||||||
|
toolbar and the actions rather than overflowing the pane. */
|
||||||
|
min-height: 6rem;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
padding: 0.75rem;
|
padding: 0.75rem;
|
||||||
border: 1px solid var(--line);
|
border: 1px solid var(--line);
|
||||||
@@ -309,7 +339,7 @@ header { border-bottom: 1px solid var(--line); }
|
|||||||
|
|
||||||
textarea {
|
textarea {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-height: 12rem;
|
min-height: 6rem;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 0.75rem;
|
padding: 0.75rem;
|
||||||
border: 1px solid var(--line);
|
border: 1px solid var(--line);
|
||||||
@@ -386,8 +416,11 @@ input[type="password"], input[type="text"] {
|
|||||||
font: inherit;
|
font: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
#login { justify-content: center; }
|
/* `margin: auto` rather than `justify-content: center`: a centred flex item in
|
||||||
#login .card { width: min(24rem, 100%); align-self: center; }
|
a scrolling container cannot be scrolled back to once it overflows the top,
|
||||||
|
which on a short screen with the keyboard up would put the password field out
|
||||||
|
of reach. */
|
||||||
|
#login .card { width: min(24rem, calc(100% - 1.5rem)); margin: auto; }
|
||||||
#login button { width: 100%; margin-top: 1rem; }
|
#login button { width: 100%; margin-top: 1rem; }
|
||||||
|
|
||||||
.steps { margin: 0.5rem 0; padding-left: 1.1rem; color: var(--muted); font-size: 0.85rem; line-height: 1.5; }
|
.steps { margin: 0.5rem 0; padding-left: 1.1rem; color: var(--muted); font-size: 0.85rem; line-height: 1.5; }
|
||||||
|
|||||||
Reference in New Issue
Block a user