Umut: "Effekte gibts keine, sind die aktiv?" Nachgemessen: die Zeigereffekte liefen alle. Die Einblendungen gab es seit Schema v3 - nur benutzt hatte sie niemand, weil eine Animation beim Laden unterhalb der Falz wertlos ist. Mit animation-timeline: view() laufen dieselben Keyframes, wenn der Abschnitt in den Blick kommt - hinter der Bewegungsschranke, hinter @supports (Firefox und Safari behalten das Einblenden beim Laden) und mit einem Bereich, der endet, bevor der Abschnitt in der Mitte steht. Dabei hat axe einen Fehler gefunden, den ich selbst gebaut hatte: eine Scroll-Zeitachse ist umkehrbar, also stand alles unterhalb der Falz dauerhaft am Anfang der Kurve - bei opacity .35 blass, bei .85 immer noch 3,86:1 statt 7,1:1. Auf dem Scrollweg wird deshalb nur Bewegung animiert, keine Deckkraft. Benutzt wird es jetzt auch: alle drei Beitragsvorlagen bringen die Einblendung je Abschnitt mit. Geprueft: 400 Tests unter PHP 8.2 und 8.4, Editortest, Browserpruefung, axe ohne Verstoss auf Startseite, Projekteseite und Beitrag - vor und nach dem Durchscrollen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
109 lines
8.0 KiB
CSS
109 lines
8.0 KiB
CSS
.block-gallery{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:24px;margin-block:24px}.block-gallery>.block-image{min-width:0;margin:0}.block-gallery img{width:100%;aspect-ratio:4/3;object-fit:cover}.block-image figcaption{font-size:14px;line-height:1.5;padding:12px 0;color:inherit}.fx-shadow-none{box-shadow:none}.fx-shadow-soft{box-shadow:0 8px 24px #142e251f}.fx-shadow-strong{box-shadow:0 16px 40px #142e2540}.block-image{border-radius:12px}.block-image img{border-radius:inherit}.block-gallery:empty{min-height:32px}.fx-hover-zoom{overflow:hidden}.fx-hover-zoom img{transform-origin:center}.tone-ink figure{color:var(--paper)}
|
|
@media(max-width:1024px){.block-gallery{grid-template-columns:repeat(2,minmax(0,1fr))}}
|
|
@media(max-width:650px){.block-gallery{grid-template-columns:minmax(0,1fr);gap:16px}}
|
|
@media(prefers-reduced-motion:no-preference){.fx-hover-lift,.fx-hover-zoom img{transition:transform .25s ease}.fx-hover-lift:hover,.fx-hover-lift:focus-within{transform:translateY(-4px)}.fx-hover-zoom:hover img,.fx-hover-zoom:focus-within img{transform:scale(1.035)}.fx-entrance-fade{animation:kant-fade .55s ease-out backwards}.fx-entrance-rise{animation:kant-rise .55s ease-out backwards}@keyframes kant-fade{from{opacity:.35}to{opacity:1}}@keyframes kant-rise{from{opacity:.35;transform:translateY(16px)}to{opacity:1;transform:translateY(0)}}}
|
|
|
|
|
|
/* Entrance animations and hover effects, added 12.09.2026.
|
|
|
|
Every animation stays inside the reduced-motion guard: whoever asked their system for less
|
|
movement gets the finished state, not a softened animation. They play on load, because a public
|
|
page runs no script and there is nothing to observe a scroll position with - that is a
|
|
limitation, not an oversight, and it is written in the editor. */
|
|
@media (prefers-reduced-motion: no-preference) {
|
|
.fx-entrance-sink { animation: kant-sink .55s ease-out backwards }
|
|
.fx-entrance-left { animation: kant-left .55s ease-out backwards }
|
|
.fx-entrance-right { animation: kant-right .55s ease-out backwards }
|
|
.fx-entrance-zoom { animation: kant-zoom .55s ease-out backwards }
|
|
.fx-entrance-flip { animation: kant-flip .7s ease-out backwards }
|
|
.fx-entrance-blur { animation: kant-unblur .6s ease-out backwards }
|
|
.fx-delay-short { animation-delay: .15s }
|
|
.fx-delay-medium { animation-delay: .3s }
|
|
.fx-delay-long { animation-delay: .6s }
|
|
|
|
.fx-hover-sink { transition: transform .2s ease }
|
|
.fx-hover-sink:hover { transform: translateY(3px) }
|
|
.fx-hover-glow { transition: box-shadow .2s ease }
|
|
.fx-hover-glow:hover { box-shadow: 0 0 0 4px color-mix(in srgb,var(--accent) 18%,transparent), 0 10px 30px color-mix(in srgb,var(--ink) 16%,transparent) }
|
|
.fx-hover-tilt { transition: transform .2s ease }
|
|
.fx-hover-tilt:hover { transform: rotate(-1.2deg) scale(1.01) }
|
|
.fx-hover-grow-border { transition: box-shadow .2s ease }
|
|
.fx-hover-grow-border:hover { box-shadow: inset 0 0 0 3px #2c6b4f }
|
|
}
|
|
@keyframes kant-sink { from { opacity: 0; transform: translateY(-18px) } to { opacity: 1; transform: none } }
|
|
@keyframes kant-left { from { opacity: 0; transform: translateX(-24px) } to { opacity: 1; transform: none } }
|
|
@keyframes kant-right { from { opacity: 0; transform: translateX(24px) } to { opacity: 1; transform: none } }
|
|
@keyframes kant-zoom { from { opacity: 0; transform: scale(.92) } to { opacity: 1; transform: none } }
|
|
@keyframes kant-flip { from { opacity: 0; transform: perspective(800px) rotateX(-12deg) } to { opacity: 1; transform: none } }
|
|
@keyframes kant-unblur { from { opacity: 0; filter: blur(8px) } to { opacity: 1; filter: none } }
|
|
|
|
/* Beitragskarten und Knöpfe, ergänzt am 13.09.2026.
|
|
|
|
Umut hat gefragt, wo der Zeigereffekt bleibt: eine Karte, die sich beim Zeigen nicht rührt,
|
|
wirkt tot. Angehoben wird die ganze Karte, das Bild zieht leicht auf, und der Hinweis darüber
|
|
blendet ein. Alles innerhalb der Bewegungsschranke - wer weniger Bewegung eingestellt hat,
|
|
bekommt den Hinweis trotzdem, nur ohne Fahrt. */
|
|
@media (prefers-reduced-motion: no-preference) {
|
|
.post-card { transition: transform .28s ease, box-shadow .28s ease, border-color .28s ease }
|
|
/* Eine Zeile in der kompakten Liste hebt sich nicht - sie ist keine Karte. */
|
|
.post-list-kompakt .post-card:hover, .post-list-kompakt .post-card:focus-within { transform: none; box-shadow: none; border-color: var(--accent) }
|
|
/* Wechselseitig: die Karte selbst bleibt stehen, nur das Bild zieht auf. */
|
|
.post-list-wechsel .post-card:hover, .post-list-wechsel .post-card:focus-within { transform: none; box-shadow: none }
|
|
.post-list-wechsel .post-card h3 a { transition: color .2s ease }
|
|
.post-list-wechsel .post-card:hover h3 a, .post-list-wechsel .post-card:focus-within h3 a { color: var(--accent) }
|
|
.post-card:hover, .post-card:focus-within {
|
|
transform: translateY(-8px);
|
|
box-shadow: 0 18px 50px -16px color-mix(in srgb, var(--ink) 28%, transparent);
|
|
border-color: transparent;
|
|
}
|
|
.post-image img { transition: transform .5s ease }
|
|
.post-card:hover .post-image img, .post-card:focus-within .post-image img { transform: scale(1.06) }
|
|
.post-view { transition: opacity .3s ease }
|
|
.post-nav-link { transition: transform .2s ease, border-color .2s ease }
|
|
.post-nav-link:hover, .post-nav-link:focus-visible { transform: translateY(-3px); border-color: var(--accent) }
|
|
|
|
/* Der Knopf hebt sich beim Zeigen um zwei Pixel - dieselbe Geste wie auf der Karte. */
|
|
.button { transition: transform .2s ease, background-color .2s ease, border-color .2s ease }
|
|
.button:hover { transform: translateY(-2px) }
|
|
}
|
|
|
|
/* Einblenden beim Hineinscrollen, ergänzt am 13.09.2026.
|
|
|
|
Bisher liefen die Einblendungen beim Laden der Seite - was unterhalb der Falz stand, war
|
|
fertig animiert, bevor es jemand gesehen hat. Mit einer Scroll-Zeitachse läuft dieselbe
|
|
Animation genau dann, wenn das Element in den Blick kommt, und zwar ohne eine Zeile
|
|
JavaScript: `animation-timeline: view()` bindet den Ablauf an die Sichtbarkeit.
|
|
|
|
Drei Bedingungen, alle bewusst:
|
|
- Hinter der Bewegungsschranke: wer weniger Bewegung eingestellt hat, bekommt keine.
|
|
- Hinter `@supports`: Browser ohne Scroll-Zeitachse (heute Firefox und Safari) behalten die
|
|
bisherige Fassung - die Animation läuft beim Laden. Niemand sieht deshalb weniger Inhalt.
|
|
- `animation-range` endet früh (`cover 26%`): die Bewegung ist vorbei, bevor das Element in
|
|
der Mitte des Bildschirms steht. Eine Einblendung, die beim Lesen noch läuft, stört. */
|
|
@media (prefers-reduced-motion: no-preference) {
|
|
@supports (animation-timeline: view()) {
|
|
/* Eigene Kurven für den Scrollweg: **nur Bewegung, keine Deckkraft**.
|
|
Eine Scroll-Zeitachse ist umkehrbar - ein Abschnitt außerhalb des Blicks steht wieder am
|
|
Anfang. Alles unterhalb der Falz wäre also dauerhaft blass, und blasser Text ist nicht
|
|
weniger Effekt, sondern schlechterer Kontrast: #3d4d5c bei 85 Prozent ergibt 3,86:1
|
|
statt 7,1:1 - axe meldet das zu Recht. Der Weg trägt den Effekt allein. */
|
|
@keyframes kant-scroll-rise { from { transform: translateY(20px) } to { transform: none } }
|
|
@keyframes kant-scroll-fade { from { transform: translateY(10px) } to { transform: none } }
|
|
|
|
.fx-entrance-fade, .fx-entrance-rise, .fx-entrance-sink, .fx-entrance-left,
|
|
.fx-entrance-right, .fx-entrance-zoom, .fx-entrance-flip, .fx-entrance-blur {
|
|
animation-name: kant-scroll-rise;
|
|
animation-timeline: view();
|
|
animation-range: entry 10% cover 28%;
|
|
animation-duration: 1ms; /* Die Zeitachse bestimmt den Ablauf, nicht die Uhr. */
|
|
animation-fill-mode: both;
|
|
}
|
|
.fx-entrance-fade { animation-name: kant-scroll-fade }
|
|
/* Die Verzögerungsstufen sind auf einer Scroll-Zeitachse eine Verschiebung im Weg,
|
|
nicht in der Zeit - sonst würden sie gar nicht wirken. */
|
|
.fx-delay-short { animation-range: entry 16% cover 32% }
|
|
.fx-delay-medium { animation-range: entry 22% cover 36% }
|
|
.fx-delay-long { animation-range: entry 28% cover 40% }
|
|
}
|
|
}
|