Botón de like sobre pósters con CSS y JS

Resumen

Marcar películas como favoritas en una aplicación web requiere tres piezas que trabajan juntas: una sección visual con scroll horizontal, un botón superpuesto sobre cada póster y una lógica que diferencie el clic en la imagen del clic en el corazón. Aquí te muestro cómo armar esa interfaz reutilizando estilos existentes y resolviendo el conflicto de eventos que aparece en el camino.

Cómo maquetar la sección de películas favoritas en HTML

La sección de favoritos vive justo debajo de las categorías y replica el comportamiento de la sección de tendencias: un header con título y una lista con scroll horizontal.

La estructura base que necesitas en tu HTML es directa:

  • Una etiqueta section con id="liked" y clase liked-container.
  • Un div con clase liked-header que contenga un h2 con el texto Películas favoritas.
  • Un article con clase liked-movie-list donde JavaScript inyectará cada movie-container con su imagen.

¿Por qué usar la misma nomenclatura que en otras secciones? Porque te permite reutilizar estilos CSS existentes con solo agregar selectores separados por coma, sin reescribir reglas para padding, margin o scroll horizontal. [02:45]

Cómo reutilizar estilos CSS sin duplicar código

En lugar de escribir reglas nuevas, agregas tus clases liked-container, liked-header, liked-movie-list y liked-movie-container a los selectores que ya estilizan la sección trending.

El truco es identificar qué estilos compartir:

  • El padding horizontal y el margin-top de la clase compartida shaded.
  • El margin-bottom del trending-preview-header para separar el título del listado.
  • Los estilos de scroll horizontal del movie-list.
  • Las dimensiones y el border-radius de movie-container y de movie-img.

Un detalle importante: el padding-left que necesitas en el header no debe vivir en el contenedor general, porque rompe el scroll de las películas. Muévelo al liked-header y el problema desaparece.

Cómo crear el botón de like con JavaScript

Dentro de la función que crea cada tarjeta de película, agregas un button con document.createElement y le asignas la clase movie-btn para que aplique a cualquier sección, no solo a favoritos.

El flujo dentro de esa función queda así:

  1. Crear el movieContainer y la movieImg como ya existían.
  2. Crear movieBtn con document.createElement('button').
  3. Agregar la clase con movieBtn.classList.add('movie-btn').
  4. Escuchar el evento de clic con una arrow function que ejecute movieBtn.classList.toggle('movie-btn--liked').
  5. Insertar el botón dentro del movieContainer con appendChild.

¿Qué hace classList.toggle? Agrega una clase si no existe y la quita si ya está aplicada. Es la forma más limpia de alternar estados visuales sin escribir condicionales. [13:20]

Dejas un comentario marcando el punto donde después conectarás el guardado en local storage, pero por ahora el toggle de clase es suficiente para validar el comportamiento visual.

Cómo posicionar el corazón sobre la imagen con CSS

El botón debe flotar en la esquina superior derecha del póster. Para lograrlo necesitas dos posicionamientos coordinados.

En el movie-container aplicas position: relative para que sirva de referencia. En el movie-btn configuras:

  • position: absolute con top: 5px y right: 10px.
  • width: 30px y height: 30px para una caja cuadrada.
  • border-radius: 30px para convertirla en círculo.
  • padding: 0 y margin: 0 para limpiar los estilos por defecto del botón.

El corazón se inyecta con un pseudo-elemento ::before cuyo content contiene un emoji copiado desde Emojipedia. Cuando el botón recibe la clase movie-btn--liked, cambias el background-color a una variable CSS de morado claro y reemplazas el emoji por su versión inversa para que el contraste funcione.

Por qué el clic abre los detalles de la película y cómo solucionarlo

Al probar el botón, ocurre algo inesperado: hacer clic en el corazón también dispara la navegación a la vista de detalles. La causa es que el movie-container tiene su propio addEventListener que mueve el hash de la URL.

La solución más directa es mover ese event listener del contenedor a la imagen. Así el botón, que está superpuesto pero fuera del flujo de la imagen, no propaga el clic hacia la navegación.

¿Por qué no usar stopPropagation en el botón? Mover el listener a movieImg es más simple y declarativo: cada elemento responde solo a lo suyo, sin depender de detener eventos en cadena. [18:40]

Con ese cambio, el corazón alterna su clase sin disparar la navegación, y el clic sobre el póster sigue llevando al detalle de la película.

Habilidades y conceptos clave que aplicaste

  • Maquetación con section, article y nomenclatura BEM-like para reutilizar estilos [01:30].
  • Selectores CSS agrupados con coma para compartir reglas entre secciones [05:10].
  • Creación dinámica de elementos con document.createElement y classList.add [11:50].
  • Posicionamiento absolute dentro de un contenedor relative para superponer elementos [15:20].
  • Pseudo-elementos ::before con content para inyectar iconos sin tocar el HTML [17:05].
  • Delegación de eventos correcta moviendo el listener al elemento adecuado [18:40].

Cuéntame en los comentarios qué emoji usaste para tu botón de favoritos y si encontraste una forma distinta de evitar la propagación del clic.