fix(ecommerce): imagen principal del producto se ve borrosa en Chrome/Edge Android
Reportado en vivo por el usuario: la foto principal (y el modal de zoom interactivo) se ven borrosas en mobile, especificamente en Chrome y Edge de Android. Investigado a fondo antes de tocar nada: no es un archivo corrupto ni un problema de nuestro cache/backend -- confirmado con fetch()+createImageBitmap() (que evita <img>/srcset por completo) que el archivo real decodifica perfecto a resolución completa (1200x1200). El bug está en cómo Chromium elige el candidato del srcset con sizes="100vw" + fill a DPR alto (2.6+, cualquier Android real): currentSrc reporta la URL de un candidato grande, pero naturalWidth/Height terminan reflejando un candidato mucho más chico -- reproducido igual en Chromium headless, y consistente con lo reportado en Chrome y Edge Android reales (mismo motor). No hay forma de arreglar el algoritmo de selección de Chromium desde acá. La foto principal y el modal de zoom pasan a unoptimized: al quedar un solo recurso real por foto (sin candidatos de por medio), no hay entre qué elegir mal. Costo: la foto pesa el archivo completo en vez de una versión redimensionada -- aceptable para dos imágenes puntuales donde la nitidez importa. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_012Y4df3Z7odr9Cg8F2nw6uV
This commit is contained in:
1 parent
8d8546fd94
commit
ccaddf546c
1 file changed
+14
-2
@@ -122,12 +122,24 @@ export function ProductGallery({ images, name }: { images: string[]; name: strin
|
|||||||
onMouseMove={trackHoverZoom}
|
onMouseMove={trackHoverZoom}
|
||||||
onMouseLeave={() => setHoverZoom(null)}
|
onMouseLeave={() => setHoverZoom(null)}
|
||||||
>
|
>
|
||||||
|
{/* unoptimized a proposito: confirmado en vivo (createImageBitmap
|
||||||
|
sobre los bytes reales vs. el <img> renderizado) que a DPR
|
||||||
|
alto (2.6+, cualquier Android real) Chromium reporta
|
||||||
|
naturalWidth/Height de un candidato del srcset mucho más
|
||||||
|
chico del que dice currentSrc -- bug del propio motor de
|
||||||
|
Chromium en la selección de candidato con sizes="100vw" en
|
||||||
|
fill, no algo corrupto en el archivo ni en nuestro caché
|
||||||
|
(el archivo decodifica perfecto vía fetch+createImageBitmap
|
||||||
|
fuera de <img>). Reproducido igual en Chrome y Edge Android
|
||||||
|
(ambos Chromium) y en Chromium headless. unoptimized deja
|
||||||
|
un solo recurso real por foto -- sin candidatos entre los
|
||||||
|
que el bug pueda elegir mal. */}
|
||||||
<Image
|
<Image
|
||||||
src={selected}
|
src={selected}
|
||||||
alt={name}
|
alt={name}
|
||||||
fill
|
fill
|
||||||
priority
|
priority
|
||||||
sizes="(max-width: 1024px) 100vw, 50vw"
|
unoptimized
|
||||||
className="object-cover"
|
className="object-cover"
|
||||||
/>
|
/>
|
||||||
{/* Lupa: recuadro que marca la region ampliada -- solo cuando
|
{/* Lupa: recuadro que marca la region ampliada -- solo cuando
|
||||||
@@ -162,7 +174,7 @@ export function ProductGallery({ images, name }: { images: string[]; name: strin
|
|||||||
<div className="grid min-h-[70vh] grid-rows-[1fr_auto]">
|
<div className="grid min-h-[70vh] grid-rows-[1fr_auto]">
|
||||||
<div className="relative overflow-hidden bg-slate-950" onWheel={wheel} onPointerDown={pointerDown} onPointerMove={pointerMove} onPointerUp={pointerEnd} onPointerCancel={pointerEnd} onDoubleClick={() => applyScale(scale > 1 ? 1 : 2)} style={{ touchAction: "none", cursor: scale > 1 ? "grab" : "zoom-in" }}>
|
<div className="relative overflow-hidden bg-slate-950" onWheel={wheel} onPointerDown={pointerDown} onPointerMove={pointerMove} onPointerUp={pointerEnd} onPointerCancel={pointerEnd} onDoubleClick={() => applyScale(scale > 1 ? 1 : 2)} style={{ touchAction: "none", cursor: scale > 1 ? "grab" : "zoom-in" }}>
|
||||||
<div className="absolute inset-6 transition-transform duration-100 will-change-transform" style={{ transform: `translate3d(${offset.x}px, ${offset.y}px, 0) scale(${scale})` }}>
|
<div className="absolute inset-6 transition-transform duration-100 will-change-transform" style={{ transform: `translate3d(${offset.x}px, ${offset.y}px, 0) scale(${scale})` }}>
|
||||||
<Image src={selected} alt={name} fill sizes="95vw" className="select-none object-contain" draggable={false} />
|
<Image src={selected} alt={name} fill unoptimized className="select-none object-contain" draggable={false} />
|
||||||
</div>
|
</div>
|
||||||
<div className="pointer-events-none absolute left-5 top-5 rounded-full bg-black/65 px-3 py-1.5 text-xs font-black text-white backdrop-blur">Rueda o botones para acercar · Arrastra para mover</div>
|
<div className="pointer-events-none absolute left-5 top-5 rounded-full bg-black/65 px-3 py-1.5 text-xs font-black text-white backdrop-blur">Rueda o botones para acercar · Arrastra para mover</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in new issue
Block a user