nav: hamburger icon pops in late on first load (toggle is portalled after hydration)
Los mantenedores suelen responder en 1 día
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 2/5
- Tiempo estimado
- 1-3 horas
- Aptitud para principiantes
- 76/100
- Tipo de issue
- Error
- Claridad
- Bien especificado
- Estado de actividad
- Activo
- Stack tecnológico
- next.js, react, typescript
- Área
- frontend
Línea de trabajo
Lee components/layout/MobileMenu.tsx y el estado de navegación relacionado en Chrome; después, inspecciona la salida prerenderizada de pnpm build. Haz que .mm-toggle esté presente en el renderizado inicial y conserva el comportamiento actual del menú móvil; verifica que el HTML exportado lo incluya y que la superposición y el panel sigan abriéndose correctamente.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
Symptom
On a cold load below 1280px the top-right menu icon (the `.mm-toggle` hamburger) is missing from the first paint and appears only once the JS bundle has downloaded and hydrated. On a real phone on a real network that is a visible pop-in next to a wordmark that was there from the first frame.
Confirmed
Served the fresh export (pnpm build on main @ 736bdfb) from a local static server and loaded it in headless Chromium (Playwright 1.56, 390×844 viewport) with JS chunk responses delayed 400 ms to widen the pre-hydration window, recording MutationObserver events on <html> from the first script tick plus a screenshot every ~100 ms.
- The prerendered HTML contains no
mm-toggleat all:grep -c mm-toggle out/index.html→0, and the live page gives the same:curl -sL https://decdn.org/ | grep -c mm-toggle→0. - First mutations after hydration (t ≈ 861 ms in this run):
add <button .mm-toggle> parent <body> add <div .mm-overlay> parent <body> add <aside .mm-panel #mm-panel> parent <body> - Frame at 831 ms: wordmark only, empty top-right. Frame at 945 ms: hamburger present. Nothing else in the nav changes between those frames.
- Same mutation sequence at 1440×900; there the toggle is
display: nonevia the@media (min-width: 1280px)gate inglobals.css, so desktop is unaffected.
Cause
components/layout/MobileMenu.tsx renders the toggle, overlay and panel through createPortal(..., document.body) and gates the whole subtree on a useSyncExternalStore hydration flag (server snapshot false), so the prerender emits nothing and the client mounts all three only after hydration. Introduced with the drawer in #56. The portal exists so the toggle can sit above the panel (z-65 > z-60) while the wordmark stays in the nav — see the comment above const drawer in that file.
Not the cause (checked)
- Favicon: Chromium requests only
/icon.svg(neverfavicon.ico), and the.icoframes and the SVG are the same artwork on a white rounded tile, so there is no tab-icon flash in Chrome. - The
wordmark-light.svg/wordmark-dark.svgpair is requested at t ≈ 28 ms and both stay mounted, so the logo does not flash. - The try-it
SelectMenualso swaps at hydration (NativeSelect→ listbox), but it is below the fold and by design renders the same face in both.
Possible direction
Prerender the <button class="mm-toggle"> so it is in the static HTML from the first byte (e.g. render it inline in the nav, or portal it with a server-rendered fallback), and keep the hydration gate only for the overlay and panel, which are invisible until opened anyway. The toggle's data-tone and data-open come from Chrome state that already prerenders deterministically (intro / closed), so there should be no hydration mismatch.
- Lenguaje dominante
- TypeScript
- Estrellas
- 3
- Forks
- 0
- Merge medio
- 12 h 41 min
- PR fusionados (30 d)
- 70
Preparar el entorno
Este proyecto no incluye contenedor de desarrollo, Dockerfile ni guía de contribución, así que la configuración corre por tu cuenta: empieza por su README y consulta nuestra guía para la primera contribución para los pasos generales.
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de decdn/website
-
enhancement
Dificultad 2/5 1-3 horas Aptitud para principiantes 67/100
Los mantenedores suelen responder en 1 día
-
bug med-priority
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
Los mantenedores suelen responder en 1 día
-
enhancement low-priority
Dificultad 4/5 1-2 días Aptitud para principiantes 35/100
Los mantenedores suelen responder en 1 día
-
bug
Dificultad 4/5 1-2 días Aptitud para principiantes 54/100
Los mantenedores suelen responder en 1 día
-
enhancement low-priority
Dificultad 3/5 1-2 días Aptitud para principiantes 52/100
Los mantenedores suelen responder en 1 día
Todos los issues de decdn/website
Issues similares
-
clawsweeper:fix-shape-clear clawsweeper:queueable-fix clawsweeper:source-repro impact:ux-friction issue-rating: 🦞 diamond lobster no-stale P3
Dificultad 2/5 1-3 horas Aptitud para principiantes 73/100
openclaw/openclaw#182077 · 1 comentario · 1 reacción ·
Los mantenedores suelen responder en 1 día
-
aikido high security
Dificultad 2/5 1-3 horas Aptitud para principiantes 75/100
dequelabs/axe-linter-action#161 ·
-
[Feature Request] Update the DimCode agent icon to the 45:32 brand markPosiblemente ocupada @eric8810 la tomó hoy. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
Los mantenedores suelen responder en 1 día
-
[Feature]: 建议导入源后,自动切换到新导入的源Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 66/100
lyswhut/lx-music-desktop#3026 ·
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 76/100
abhigyanpatwari/GitNexus#3704 ·
Los mantenedores suelen responder en 1 día