EN JA ZH ES

Implementación de sliders de comparación antes/después - Diseño y optimización de UI

· 9 min de lectura

Casos de uso y requisitos de diseño del slider de comparación de imágenes

Los sliders de comparación de imágenes (Before/After Sliders) superponen dos imágenes, permitiendo a los usuarios arrastrar un divisor para inspeccionar visualmente las diferencias. Las aplicaciones incluyen antes/después de edición fotográfica, comparación de calidad de compresión, iteraciones de diseño web y cambios temporales en imágenes médicas.

Requisitos de diseño:

  • Interacción intuitiva: Los usuarios deben entender la operación sin instrucciones. El control deslizante debe comunicar visualmente que es arrastrable
  • Diseño responsivo: Soportar tanto interacciones de ratón en escritorio como táctiles en móvil. El componente se escala apropiadamente con el ancho del viewport
  • Rendimiento: Mantener 60fps durante el arrastre. Minimizar repintados y aprovechar la aceleración GPU
  • Accesibilidad: Soportar operación por teclado (teclas de flecha) y comunicar el estado a lectores de pantalla mediante atributos ARIA
  • Sincronización de imágenes: Ambas imágenes deben alinearse perfectamente en posición y tamaño. Definir el manejo para relaciones de aspecto no coincidentes

Existen tres enfoques principales de implementación: CSS clip-path, overflow: hidden con control de ancho, y renderizado Canvas. Cada uno tiene compensaciones - este artículo se centra en el enfoque clip-path por sus características superiores de rendimiento.

Estructura HTML y semántica - Marcado accesible

La estructura HTML debe considerar la semántica y accesibilidad, asegurando que los usuarios de lectores de pantalla comprendan la intención de comparación y puedan operar mediante teclado.

Estructura HTML recomendada:

<div class="comparison-slider" role="group" aria-label="Comparación de imágenes"><div class="comparison-slider__before"><img src="before.webp" alt="Antes del procesamiento" /><span class="comparison-slider__label">Antes</span></div><div class="comparison-slider__after"><img src="after.webp" alt="Después del procesamiento" /><span class="comparison-slider__label">Después</span></div><div class="comparison-slider__handle" role="slider" aria-label="Posición de comparación" aria-valuemin="0" aria-valuemax="100" aria-valuenow="50" tabindex="0"></div></div>

Consideraciones del marcado:

  • role="group": Establecido en el contenedor para indicar elementos relacionados
  • role="slider": Establecido en el control para comunicar el control deslizante a los lectores de pantalla
  • aria-valuemin/max/now: Comunica la posición actual como porcentaje, actualizado dinámicamente vía JavaScript
  • tabindex="0": Hace el control enfocable para operación por teclado
  • Atributos alt: Proporciona texto alternativo apropiado para cada imagen

Las etiquetas se posicionan con CSS position: absolute en las esquinas de la imagen, con z-index ajustado para permanecer visibles durante la operación del slider. El tamaño de fuente de las etiquetas se escala con clamp(0.75rem, 2vw, 1rem) para un comportamiento responsivo natural.

Implementación CSS - Optimización de rendimiento con clip-path

La implementación con clip-path ofrece el mejor rendimiento de arrastre porque los cambios en clip-path no activan recálculo de layout - solo se necesitan actualizaciones de capas compuestas, habilitando la aceleración GPU.

CSS principal:

.comparison-slider { position: relative; overflow: hidden; cursor: col-resize; } .comparison-slider__before, .comparison-slider__after { position: absolute; inset: 0; } .comparison-slider__before img, .comparison-slider__after img { display: block; width: 100%; height: 100%; object-fit: cover; } .comparison-slider__after { clip-path: inset(0 0 0 50%); } .comparison-slider__handle { position: absolute; top: 0; bottom: 0; left: 50%; width: 4px; background: white; transform: translateX(-50%); box-shadow: 0 0 8px rgba(0,0,0,0.3); }

Puntos de optimización de rendimiento:

  • will-change: clip-path: Establecido en el elemento After para indicar intención de animación. Añadir al inicio del arrastre, eliminar al final para evitar sobrecarga constante de memoria
  • contain: layout: Establecido en el contenedor para indicar que los cambios internos no afectan el layout externo
  • Promoción de capa GPU: transform: translateZ(0) promueve el control a una capa compuesta independiente, evitando repintados durante el movimiento

Diseño responsivo: Establece aspect-ratio: 16/9 en el contenedor con ancho 100% para cálculo automático de altura. Las imágenes usan object-fit: cover para manejar relaciones de aspecto no coincidentes de forma elegante.

Implementación JavaScript - Manejo de arrastre y procesamiento de eventos

Implementa la interacción del slider con JavaScript soportando tanto ratón como toque mediante la API unificada de Pointer Events.

Puntos principales de implementación:

  • Pointer Events API: Usa pointerdown, pointermove, pointerup para manejar ratón, toque y lápiz de forma uniforme. setPointerCapture() asegura que los eventos continúen incluso cuando el puntero se mueve fuera del control
  • Cálculo de posición: event.clientX - container.getBoundingClientRect().left da la posición relativa dentro del contenedor, dividida por el ancho del contenedor para obtener el porcentaje (0-100)
  • requestAnimationFrame: Como pointermove se dispara a alta frecuencia, agrupa las actualizaciones del DOM a una vez por frame mediante requestAnimationFrame
  • Limitación de bordes: Math.max(0, Math.min(100, percent)) previene que el slider exceda los límites del contenedor

Implementación de operación por teclado:

handle.addEventListener('keydown', (e) => { if (e.key === 'ArrowLeft') updatePosition(currentPercent - 1); if (e.key === 'ArrowRight') updatePosition(currentPercent + 1); if (e.key === 'Home') updatePosition(0); if (e.key === 'End') updatePosition(100); });

Función de actualización del DOM:

function updatePosition(percent) { percent = Math.max(0, Math.min(100, percent)); afterEl.style.clipPath = `inset(0 0 0 ${percent}%)`; handleEl.style.left = `${percent}%`; handleEl.setAttribute('aria-valuenow', Math.round(percent)); }

Consideraciones para dispositivos táctiles: Establece touch-action: none en el contenedor para prevenir el comportamiento de desplazamiento predeterminado. Usa touch-action: pan-y en su lugar si el desplazamiento vertical debe permanecer habilitado mientras solo el movimiento horizontal activa el slider.

Funciones avanzadas - Animación, carga diferida, múltiples instancias

Mejora la experiencia del usuario con funciones avanzadas más allá de la implementación básica.

Animación inicial (onboarding):

  • Reproduce una sutil animación de oscilación al cargar la página para indicar interactividad
  • CSS: @keyframes hint { 0%,100% { left: 50% } 25% { left: 35% } 75% { left: 65% } }
  • Detiene la animación en la primera interacción del usuario (establece animation: none)
  • Usa IntersectionObserver para iniciar la animación solo cuando es visible en el viewport

Carga diferida de imágenes:

  • Los sliders de comparación típicamente están debajo del pliegue - usa loading="lazy" para carga diferida
  • Muestra un marcador de posición que preserva la relación de aspecto (caja gris) antes de la carga para prevenir CLS
  • Habilita el slider solo después de que ambas imágenes carguen: Promise.all([img1.decode(), img2.decode()]).then(enableSlider)

Gestión de múltiples instancias:

  • Al colocar múltiples sliders por página, gestiona cada instancia independientemente
  • Implementación basada en clases: class ComparisonSlider { constructor(el) { this.container = el; this.init(); } }
  • Inicialización: document.querySelectorAll('.comparison-slider').forEach(el => new ComparisonSlider(el))
  • Prevención de fugas de memoria: Implementa un método destroy() para eliminar event listeners cuando los componentes se desmontan en SPAs

Slider vertical: Usa clip-path: inset(50% 0 0 0) para división superior/inferior con control horizontal para comparaciones verticales. Un atributo data-direction="vertical" permite cambiar la dirección para máxima versatilidad.

Comparación de bibliotecas y criterios de selección

Las bibliotecas existentes ofrecen alternativas a la implementación personalizada. Elige según los requisitos del proyecto.

Comparación de bibliotecas principales:

  • img-comparison-slider (Web Component): 3.5KB gzipped. Web Component independiente del framework con etiqueta declarativa <img-comparison-slider>. Soporte completo de teclado y accesibilidad. El más ligero y recomendado
  • TwentyTwenty (jQuery): Biblioteca legacy dependiente de jQuery. Funcional pero inapropiada para proyectos sin jQuery. 5KB + jQuery 87KB de bundle
  • Cocoen: Implementación en JavaScript vanilla. 2KB gzipped, ligero con soporte táctil. Carece de funciones de accesibilidad (sin atributos ARIA)
  • React Compare Image: Componente específico de React con soporte TypeScript. Personalización basada en Props pero limitado a proyectos React

Criterios de selección: prioridad en tamaño de bundle favorece img-comparison-slider (3.5KB) o Cocoen (2KB); prioridad en accesibilidad favorece img-comparison-slider (ARIA completo); proyectos React usan React Compare Image; máxima personalización requiere implementación propia.

Elige implementación propia cuando: integres completamente en un sistema de diseño, necesites interacciones especiales (zoom de pellizco, rotación, comparación de 3+ imágenes), requisitos estrictos de rendimiento, o cuando las bibliotecas existentes tengan accesibilidad insuficiente. Siempre mide el impacto en Core Web Vitals y optimiza imágenes (WebP/AVIF, dimensionado adecuado) para evitar retrasos en LCP.

Artículos relacionados

Métodos de comparación de diferencias de imagen - Del nivel de píxel a la comparación semántica

Guía sistemática para detectar y visualizar diferencias de imagen. Cubre comparación de píxeles, similitud estructural, diferencia perceptual e implementación práctica.

Guía de implementación de imágenes responsivas - Guía completa de srcset, sizes y el elemento picture

Guía completa de implementación de imágenes responsivas. Cubre el atributo srcset, el atributo sizes, la dirección artística con el elemento picture y la generación automatizada en el pipeline de construcción.

Cómo crear mapas de imagen HTML y alternativas modernas - Guía de implementación de mapas clicables

Aprende a implementar mapas de imagen con los elementos map y area de HTML. Cubre los desafíos del diseño responsivo y alternativas modernas con SVG y CSS, con ejemplos de código prácticos.

Mejores prácticas de edición fotográfica móvil - Procesamiento eficiente de imágenes en smartphones

Técnicas para la edición eficiente de imágenes en smartphones. Cubre restricciones de procesamiento en navegadores móviles, gestión de memoria, diseño de UI táctil e implementación PWA.

Auditoría de rendimiento de imágenes web - Guía práctica para mejorar Core Web Vitals

Metodología completa de auditoría de rendimiento de imágenes web. Cubre herramientas y métricas de auditoría, optimización de LCP, prevención de CLS, optimización de tamaño de transferencia y monitoreo continuo.

Optimización del rendimiento de galerías de imágenes - Carga y renderizado eficiente de grandes colecciones

Explicación sistemática de técnicas de optimización de rendimiento para galerías de imágenes. Cubre scroll virtual, estrategias de carga diferida, generación de miniaturas, gestión de memoria y experiencia de desplazamiento fluido.

Términos relacionados