Die Knöpfe bleiben, die Inhaltsangabe klappt auf

Ich hatte „die Beschreibung nur beim Hovern" gelesen und daraufhin
Beschreibung *und* Knöpfe ausgeblendet. Die Knöpfe gehören immer dahin: in
Ruhe steht oben, was läuft und was man damit tun kann.

Die Inhaltsangabe dagegen steht erst da, wenn man es will. Zwei Sekunden
auf dem Titel stehenbleiben, dann fährt er hoch und darunter klappt sie
auf; wer nur vorbeifährt, sieht nichts. Gibt es keine, passiert gar
nichts — der Absatz fällt dann ganz aus dem Fluss.

**Angefasst wird am Titel, losgelassen am ganzen Aufmacher.** Das ist die
ganze Vorsicht an dieser Stelle. Beim Aufklappen wächst der Block nach
oben, der Titel rückt um 77 Bildpunkte weg und steht nicht mehr unter dem
Zeiger. Hinge das Zuklappen an seinem `:hover`, wäre das die erste Hälfte
einer Schaukel. Der Aufmacher selbst kann das nicht: gemessen, offen wie
zu, 476 px hoch ab 48 — auf den Bildpunkt derselbe Kasten.

**Die Höhe wird gemessen, nicht geraten.** Nach `auto` lässt sich nicht
überblenden, und eine feste Obergrenze wäre bei einer einzeiligen Angabe
zu drei Vierteln Leerlauf. Gemessen wird bei jedem Folienwechsel und bei
jeder Fensteränderung; `scrollHeight` ginge nicht, der meldet bei einem
`-webkit-box` die ungeklammerte Höhe.

**Der Rasterabstand wandert mit.** Gemessen: zugeklappt stehen zwischen
Eckdaten und Knopfzeile 16 px — mit Inhaltsangabe wie ohne, und genau so
viele wie vorher. Aufgeklappt sind es 12 über und 16 unter dem Text, und
die Knopfzeile steht still (Unterkante 492 in beiden Zuständen).

Nebenbei kommt das Abbruchsignal endlich an: `hero()` nahm eines
entgegen, aber `main.ts` baute die Startseite ohne. Sie wird gemerkt — ihr
Neun-Sekunden-Takt lief also weiter, während man längst woanders war.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-10-06 22:05:44 +02:00
co-authored by Claude Opus 5
parent ac9faacefb
commit 02978e482c
4 changed files with 140 additions and 38 deletions
+99 -3
View File
@@ -204,7 +204,20 @@ export function hero(
e.bewertung ? `★ ${e.bewertung.toFixed(1)}` : null,
].filter(Boolean).join(' · ');
text.textContent = e.beschreibung ?? '';
// **Nichts zu zeigen heisst: kein Aufklappen.** Bei einer angefangenen
// Folge steht hier oft gar nichts, und bei „S2 · F5 — Der Pakt" wäre das
// Auffahren eine Bewegung um einer Zeile willen, die schon oben steht.
// Mit `.hidden` fällt der Absatz aus dem Fluss und nimmt seinen
// Rasterabstand mit; der Block steht dann bei jeder Folie gleich hoch.
//
// **Hier und nicht am Ende von `zeige`** — weiter unten steht ein `return`
// für noch nicht freigegebene Titel.
const beschreibung = e.beschreibung?.trim() ?? '';
text.textContent = beschreibung;
text.classList.toggle('hidden', beschreibung.length === 0);
hatText = beschreibung.length > 0;
if (!hatText) zuklappen();
anstossen();
mehr.onclick = () => oeffnen(e.art, e.id);
// **Drei Fälle, und jeder sagt die Wahrheit.**
@@ -290,11 +303,94 @@ export function hero(
wurzel.addEventListener('pointercancel', () => { start = null; });
}
/* ---------- Die Inhaltsangabe klappt auf ---------- */
/** Wie lange der Zeiger auf dem Titel stehen muss. */
const GEDULD_MS = 2000;
let hatText = false;
let wartet: number | undefined;
let angemeldet = false;
/** Misst die aufgeklappte Höhe und schreibt sie als Eigenschaft.
*
* **Kurz auf `auto` und wieder zurück.** Dazwischen wird nicht gezeichnet —
* beides liegt in derselben Aufgabe. `scrollHeight` ginge nicht: bei einem
* `-webkit-box` meldet der die *ungeklammerte* Höhe, bei sechs Zeilen also
* das Doppelte dessen, was je zu sehen ist. */
function messen(): void {
if (!hatText) return;
const vorher = text.style.height;
text.style.height = 'auto';
const hoehe = Math.round(text.getBoundingClientRect().height);
text.style.height = vorher;
inhalt.style.setProperty('--hero-texthoehe', `${hoehe}px`);
}
/** Einmal je Bild, nicht einmal je Ereignis — wie `weichNachBildlauf`. */
function anstossen(): void {
if (angemeldet) return;
angemeldet = true;
requestAnimationFrame(() => { angemeldet = false; messen(); });
}
function aufklappen(): void {
if (!hatText) return;
messen(); // Erst messen, dann schalten.
inhalt.classList.add('aufgeklappt');
}
function zuklappen(): void {
if (wartet !== undefined) { window.clearTimeout(wartet); wartet = undefined; }
inhalt.classList.remove('aufgeklappt');
}
// **Angefasst wird am Titel, losgelassen am ganzen Aufmacher.**
//
// Das ist die ganze Vorsicht an dieser Stelle. Klappt die Inhaltsangabe auf,
// wächst `.hero-inhalt` nach oben — der Titel rückt um zwanzig bis siebzig
// Bildpunkte weg und steht nicht mehr unter dem Zeiger. Hinge das Zuklappen
// an seinem `:hover`, wäre das die erste Hälfte einer Schaukel: weg vom
// Zeiger, zu, wieder unter den Zeiger, auf, und so fort im Takt der
// Überblendung.
//
// Der Aufmacher selbst kann das nicht: er ist `min(62vh, 560px)` hoch, fest.
// Sein Rechteck ändert sich beim Aufklappen um keinen Bildpunkt, ein Zeiger
// darin kann also nicht hinausgeschoben werden.
const anfassen = (e: PointerEvent): void => {
// Ohne Zeiger kein Verweilen — am Finger steht die Inhaltsangabe ohnehin
// die ganze Zeit da, siehe `hover: hover` im Regelwerk.
if (e.pointerType === 'touch') return;
if (!hatText || inhalt.classList.contains('aufgeklappt')) return;
window.clearTimeout(wartet);
wartet = window.setTimeout(() => { wartet = undefined; aufklappen(); }, GEDULD_MS);
};
/** Bricht nur das Warten ab, nie das Aufgeklappte.
*
* Ist es offen, ist dieses Verlassen gerade das, was das Aufklappen selbst
* verursacht hat. */
const loslassen = (): void => {
if (wartet !== undefined) { window.clearTimeout(wartet); wartet = undefined; }
};
[schriftzug, titel].forEach(el => {
el.addEventListener('pointerenter', anfassen);
el.addEventListener('pointerleave', loslassen);
});
// Drei Zeilen sind bei 620 px Breite andere als bei 380.
window.addEventListener('resize', anstossen, { passive: true });
wurzel.addEventListener('mouseenter', anhalten);
wurzel.addEventListener('mouseleave', starten);
wurzel.addEventListener('mouseleave', () => { starten(); zuklappen(); });
wurzel.addEventListener('focusin', anhalten);
wurzel.addEventListener('focusout', starten);
signal?.addEventListener('abort', anhalten);
signal?.addEventListener('abort', () => {
anhalten();
loslassen();
window.removeEventListener('resize', anstossen);
});
zeige(0);
starten();