Slide the navigation rail and fade its scrim out in Firefox too
A rail that was open over the page left it on `transition: … display … allow-discrete`: the compact adaptive rail's slide-out, the slide-out of a rail that hides when collapsed, and every rail scrim's fade. Firefox does not transition `display`, even with `allow-discrete` (Chrome 117 and Safari 18 do), so there the panel and the scrim vanished on the first frame. Unlike the sheets' scrims these are drawn by attribute rules on `data-md-open`, not `x-show`, so Alpine had nothing to hold. navigation.js now marks a rail that closes `data-md-closing` — `sheet` when the panel leaves the window, `scrim` when it stands in the layout again — and drops it once the panel's `translate` and the scrim's `opacity` transitions have finished (at once under reduced motion, or when the rail opens again). navigation-rail.css keeps what is leaving displayed, and a sliding panel in its open geometry, while the attribute is set, and no longer transitions `display` anywhere, so Chrome and Safari do not hold a second time. The view sets it from `x-effect`, beside the `x-bind` that drops `data-md-open`, so both attributes change in one flush: a `$watch` a microtask later let a style read in between settle the scrim as already hidden. The collapsed branches and `--md-navigation-rail-value` are untouched. NavigationTest samples each exit part-way in the page (the compact slide, the hide-when-collapsed slide, a modal rail's scrim) and checks it ends hidden; all three fail on main in Firefox and pass in Chrome, Firefox and Safari. They wait for the entry to finish first: Firefox creates a transition on its next refresh tick, so straight after a change its computed style already reads the end value. NavigationRailTest pins the holds and that no rule transitions `display`. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
7db522826b
commit
92e560bef6
@@ -6,7 +6,8 @@
|
||||
* docs/reference/m3/components-navigation-selection-inputs.md § Navigation Rail).
|
||||
*
|
||||
* [data-md-navigation-rail="collapsed|expanded|collapsible|modal|adaptive"] data-md-open
|
||||
* [data-md-navigation-rail-scrim] modal and adaptive rails, open only
|
||||
* data-md-closing="sheet|scrim", while it exits
|
||||
* [data-md-navigation-rail-scrim] modal and adaptive rails, open or closing only
|
||||
* [data-md-navigation-rail-panel] the <nav>
|
||||
* [data-md-navigation-rail-header] never scrolls
|
||||
* [data-md-navigation-rail-menu-row] the menu button and the brand
|
||||
@@ -33,6 +34,15 @@
|
||||
* `resources/js/navigation.js` reads the same numbers, so the menu button and the drawing agree at
|
||||
* every width.
|
||||
*
|
||||
* **Closing**: nothing here transitions `display`, which Firefox cannot do even with
|
||||
* `allow-discrete`, so a panel sliding off the window and a fading scrim were cut to nothing there.
|
||||
* `resources/js/navigation.js` sets `data-md-closing` on a rail that was open over the page until
|
||||
* its exit transitions have run — `sheet` when the panel leaves the window (a compact adaptive
|
||||
* rail, or one that hides when collapsed), `scrim` when the panel stands in the layout again — and
|
||||
* the rules near the end of the file keep what is leaving displayed meanwhile, in every engine.
|
||||
* The collapsed branches do not read it: a closing rail is already collapsed, which is what
|
||||
* `--md-navigation-rail-value` says the moment it starts to close.
|
||||
*
|
||||
* The first set of branches also publishes the answer: `--md-navigation-rail-value` is `expanded`
|
||||
* on every rail and `collapsed` wherever those branches hold — M3's two rail values, Compose's
|
||||
* WideNavigationRailValue — so what an application puts in a rail reads it with
|
||||
@@ -306,16 +316,17 @@
|
||||
content, placed on the content-adjacent edge" — also its answer to a page scrolling under a
|
||||
fixed rail — and "container fill can be turned off (transparent) as long as items keep ≥3:1
|
||||
contrast" (N-22). Neither applies to a rail open over a scrim, a surface over the page. */
|
||||
[data-md-navigation-rail][data-md-divider]:not([data-md-open]) > [data-md-navigation-rail-panel] {
|
||||
[data-md-navigation-rail][data-md-divider]:not([data-md-open], [data-md-closing='sheet']) > [data-md-navigation-rail-panel] {
|
||||
border-inline-end: 1px solid var(--md-sys-color-outline-variant);
|
||||
}
|
||||
|
||||
[data-md-navigation-rail][data-md-fill='false']:not([data-md-open]) > [data-md-navigation-rail-panel] {
|
||||
[data-md-navigation-rail][data-md-fill='false']:not([data-md-open], [data-md-closing='sheet']) > [data-md-navigation-rail-panel] {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
/* Open: expanded over a scrim, in surface-container with a large corner at its inner edge. */
|
||||
[data-md-navigation-rail][data-md-open] > [data-md-navigation-rail-panel] {
|
||||
/* Open: expanded over a scrim, in surface-container with a large corner at its inner edge — and
|
||||
still, while a panel that is leaving the window slides off it (`data-md-closing="sheet"`). */
|
||||
[data-md-navigation-rail]:is([data-md-open], [data-md-closing='sheet']) > [data-md-navigation-rail-panel] {
|
||||
position: fixed;
|
||||
inset-block: 0;
|
||||
inset-inline-start: 0;
|
||||
@@ -350,8 +361,7 @@
|
||||
box-shadow: var(--md-sys-elevation-2);
|
||||
translate: -100% 0;
|
||||
transition:
|
||||
translate var(--md-sys-motion-effects-default-duration) var(--md-sys-motion-easing-emphasized-accelerate),
|
||||
display var(--md-sys-motion-effects-default-duration) allow-discrete;
|
||||
translate var(--md-sys-motion-effects-default-duration) var(--md-sys-motion-easing-emphasized-accelerate);
|
||||
|
||||
&:is([dir='rtl'], [dir='rtl'] *) {
|
||||
translate: 100% 0;
|
||||
@@ -362,8 +372,7 @@
|
||||
display: flex;
|
||||
translate: 0 0;
|
||||
transition:
|
||||
translate var(--md-sys-motion-spatial-default-duration) var(--md-sys-motion-easing-emphasized-decelerate),
|
||||
display var(--md-sys-motion-spatial-default-duration) allow-discrete;
|
||||
translate var(--md-sys-motion-spatial-default-duration) var(--md-sys-motion-easing-emphasized-decelerate);
|
||||
|
||||
@starting-style {
|
||||
translate: -100% 0;
|
||||
@@ -395,8 +404,7 @@
|
||||
display: none;
|
||||
translate: -100% 0;
|
||||
transition:
|
||||
translate var(--md-sys-motion-effects-default-duration) var(--md-sys-motion-easing-emphasized-accelerate),
|
||||
display var(--md-sys-motion-effects-default-duration) allow-discrete;
|
||||
translate var(--md-sys-motion-effects-default-duration) var(--md-sys-motion-easing-emphasized-accelerate);
|
||||
|
||||
&:is([dir='rtl'], [dir='rtl'] *) {
|
||||
translate: 100% 0;
|
||||
@@ -408,8 +416,7 @@
|
||||
display: none;
|
||||
translate: -100% 0;
|
||||
transition:
|
||||
translate var(--md-sys-motion-effects-default-duration) var(--md-sys-motion-easing-emphasized-accelerate),
|
||||
display var(--md-sys-motion-effects-default-duration) allow-discrete;
|
||||
translate var(--md-sys-motion-effects-default-duration) var(--md-sys-motion-easing-emphasized-accelerate);
|
||||
|
||||
&:is([dir='rtl'], [dir='rtl'] *) {
|
||||
translate: 100% 0;
|
||||
@@ -422,8 +429,7 @@
|
||||
display: none;
|
||||
translate: -100% 0;
|
||||
transition:
|
||||
translate var(--md-sys-motion-effects-default-duration) var(--md-sys-motion-easing-emphasized-accelerate),
|
||||
display var(--md-sys-motion-effects-default-duration) allow-discrete;
|
||||
translate var(--md-sys-motion-effects-default-duration) var(--md-sys-motion-easing-emphasized-accelerate);
|
||||
|
||||
&:is([dir='rtl'], [dir='rtl'] *) {
|
||||
translate: 100% 0;
|
||||
@@ -439,8 +445,7 @@
|
||||
display: none;
|
||||
translate: -100% 0;
|
||||
transition:
|
||||
translate var(--md-sys-motion-effects-default-duration) var(--md-sys-motion-easing-emphasized-accelerate),
|
||||
display var(--md-sys-motion-effects-default-duration) allow-discrete;
|
||||
translate var(--md-sys-motion-effects-default-duration) var(--md-sys-motion-easing-emphasized-accelerate);
|
||||
|
||||
&:is([dir='rtl'], [dir='rtl'] *) {
|
||||
translate: 100% 0;
|
||||
@@ -456,8 +461,7 @@
|
||||
display: none;
|
||||
translate: -100% 0;
|
||||
transition:
|
||||
translate var(--md-sys-motion-effects-default-duration) var(--md-sys-motion-easing-emphasized-accelerate),
|
||||
display var(--md-sys-motion-effects-default-duration) allow-discrete;
|
||||
translate var(--md-sys-motion-effects-default-duration) var(--md-sys-motion-easing-emphasized-accelerate);
|
||||
|
||||
&:is([dir='rtl'], [dir='rtl'] *) {
|
||||
translate: 100% 0;
|
||||
@@ -470,8 +474,7 @@
|
||||
display: flex;
|
||||
translate: 0 0;
|
||||
transition:
|
||||
translate var(--md-sys-motion-spatial-default-duration) var(--md-sys-motion-easing-emphasized-decelerate),
|
||||
display var(--md-sys-motion-spatial-default-duration) allow-discrete;
|
||||
translate var(--md-sys-motion-spatial-default-duration) var(--md-sys-motion-easing-emphasized-decelerate);
|
||||
|
||||
@starting-style {
|
||||
translate: -100% 0;
|
||||
@@ -486,6 +489,23 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* Closing: what leaves stays drawn while it animates out. The exits above transition `translate`
|
||||
and the scrim's `opacity` only — not `display`, which Firefox cannot transition even with
|
||||
`allow-discrete`, so the slide and the fade were cut to nothing there — and
|
||||
resources/js/navigation.js sets `data-md-closing` on the rail until those transitions have
|
||||
run: `sheet` when the panel leaves the window, `scrim` when only the scrim was over the page.
|
||||
One attribute more than every collapsed branch, so a hold outranks the `display: none` those
|
||||
branches draw. */
|
||||
[data-md-navigation-rail][data-md-hide-when-collapsed][data-md-closing='sheet'] > [data-md-navigation-rail-panel] {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
@media (width < 600px) {
|
||||
[data-md-navigation-rail='adaptive'][data-md-closing='sheet'] > [data-md-navigation-rail-panel] {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
/* The two bands the configuration above does not reach, because there it is the window and not
|
||||
the visitor that collapses the rail: below `medium` for a collapsible rail — already held at
|
||||
its collapsed width above — and `medium` itself for the adaptive one, which M3 gives a
|
||||
@@ -520,9 +540,11 @@
|
||||
display: none;
|
||||
background-color: color-mix(in srgb, var(--md-sys-color-scrim) 32%, transparent);
|
||||
opacity: 0;
|
||||
transition:
|
||||
opacity var(--md-sys-motion-effects-default-duration) var(--md-sys-motion-effects-default),
|
||||
display var(--md-sys-motion-effects-default-duration) allow-discrete;
|
||||
transition: opacity var(--md-sys-motion-effects-default-duration) var(--md-sys-motion-effects-default);
|
||||
}
|
||||
|
||||
[data-md-navigation-rail][data-md-closing] > [data-md-navigation-rail-scrim] {
|
||||
display: block;
|
||||
}
|
||||
|
||||
[data-md-navigation-rail][data-md-open] > [data-md-navigation-rail-scrim] {
|
||||
|
||||
Reference in New Issue
Block a user