fix: keep motion entrance at full opacity for contrast
Axe sampled hero/page-open text mid opacity fade (~0.58), reporting false WCAG failures. Animate transform/clip-path only. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -179,9 +179,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media (prefers-reduced-motion: no-preference) {
|
@media (prefers-reduced-motion: no-preference) {
|
||||||
|
/* Transform/clip only — never fade text opacity (axe + WCAG mid-transition). */
|
||||||
html[data-motion="enhance"] [data-motion="dossie-hero"] [data-motion-beat="seal"],
|
html[data-motion="enhance"] [data-motion="dossie-hero"] [data-motion-beat="seal"],
|
||||||
html[data-motion="enhance"] [data-motion="dossie-hero"] [data-motion-beat="cta"] {
|
html[data-motion="enhance"] [data-motion="dossie-hero"] [data-motion-beat="cta"] {
|
||||||
opacity: 0;
|
|
||||||
transform: translateY(0.5rem);
|
transform: translateY(0.5rem);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -194,11 +194,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
html[data-motion="enhance"] [data-motion="dossie-hero"].is-active [data-motion-beat] {
|
html[data-motion="enhance"] [data-motion="dossie-hero"].is-active [data-motion-beat] {
|
||||||
opacity: 1;
|
|
||||||
transform: none;
|
transform: none;
|
||||||
clip-path: inset(0 0 0 0);
|
clip-path: inset(0 0 0 0);
|
||||||
transition:
|
transition:
|
||||||
opacity var(--amare-duration-slow) var(--amare-ease-arrival),
|
|
||||||
transform var(--amare-duration-slow) var(--amare-ease-arrival),
|
transform var(--amare-duration-slow) var(--amare-ease-arrival),
|
||||||
clip-path var(--amare-duration-focal) var(--amare-ease-arrival);
|
clip-path var(--amare-duration-focal) var(--amare-ease-arrival);
|
||||||
}
|
}
|
||||||
@@ -220,29 +218,21 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
html[data-motion="enhance"] [data-reveal]:not(.is-revealed) {
|
html[data-motion="enhance"] [data-reveal]:not(.is-revealed) {
|
||||||
opacity: 0;
|
|
||||||
transform: translateY(0.5rem);
|
transform: translateY(0.5rem);
|
||||||
}
|
}
|
||||||
|
|
||||||
html[data-motion="enhance"] [data-reveal].is-revealed {
|
html[data-motion="enhance"] [data-reveal].is-revealed {
|
||||||
opacity: 1;
|
|
||||||
transform: none;
|
transform: none;
|
||||||
transition:
|
transition: transform var(--amare-duration-slow) var(--amare-ease-arrival);
|
||||||
opacity var(--amare-duration-slow) var(--amare-ease-arrival),
|
|
||||||
transform var(--amare-duration-slow) var(--amare-ease-arrival);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
html[data-motion="enhance"] [data-motion="page-open"]:not(.is-active) {
|
html[data-motion="enhance"] [data-motion="page-open"]:not(.is-active) {
|
||||||
opacity: 0;
|
|
||||||
transform: translateY(0.4rem);
|
transform: translateY(0.4rem);
|
||||||
}
|
}
|
||||||
|
|
||||||
html[data-motion="enhance"] [data-motion="page-open"].is-active {
|
html[data-motion="enhance"] [data-motion="page-open"].is-active {
|
||||||
opacity: 1;
|
|
||||||
transform: none;
|
transform: none;
|
||||||
transition:
|
transition: transform var(--amare-duration-normal) var(--amare-ease-arrival);
|
||||||
opacity var(--amare-duration-normal) var(--amare-ease-arrival),
|
|
||||||
transform var(--amare-duration-normal) var(--amare-ease-arrival);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,6 +92,20 @@ class MotionMarkupTest extends TestCase
|
|||||||
$this->assertStringContainsString('[data-chapter-index]', $appCss);
|
$this->assertStringContainsString('[data-chapter-index]', $appCss);
|
||||||
$this->assertStringContainsString('prefers-reduced-motion: no-preference', $appCss);
|
$this->assertStringContainsString('prefers-reduced-motion: no-preference', $appCss);
|
||||||
|
|
||||||
|
// Entrance motion must not fade text opacity — mid-fade fails WCAG contrast (axe).
|
||||||
|
$this->assertDoesNotMatchRegularExpression(
|
||||||
|
'/\[data-motion-beat="seal"\][^{]*\{[^}]*opacity:\s*0/s',
|
||||||
|
$appCss,
|
||||||
|
);
|
||||||
|
$this->assertDoesNotMatchRegularExpression(
|
||||||
|
'/\[data-motion="page-open"\]:not\(\.is-active\)[^{]*\{[^}]*opacity:\s*0/s',
|
||||||
|
$appCss,
|
||||||
|
);
|
||||||
|
$this->assertDoesNotMatchRegularExpression(
|
||||||
|
'/\[data-reveal\]:not\(\.is-revealed\)[^{]*\{[^}]*opacity:\s*0/s',
|
||||||
|
$appCss,
|
||||||
|
);
|
||||||
|
|
||||||
$this->assertFileExists(resource_path('js/motion.js'));
|
$this->assertFileExists(resource_path('js/motion.js'));
|
||||||
$this->assertStringContainsString("import './motion.js'", $appJs);
|
$this->assertStringContainsString("import './motion.js'", $appJs);
|
||||||
$this->assertStringContainsString('prefers-reduced-motion', (string) file_get_contents(resource_path('js/motion.js')));
|
$this->assertStringContainsString('prefers-reduced-motion', (string) file_get_contents(resource_path('js/motion.js')));
|
||||||
|
|||||||
Reference in New Issue
Block a user