Logo
Comenzar Iniciar sesión
EN | ES

Cómo hacer un popup en HTML

Publicado en: 21 Ago 2025

No hace falta un framework para crear un buen popup. Con HTML semántico, un poco de CSS moderno y JavaScript puro podés construir una ventana modal rápida, accesible y lista para convertir tanto en escritorio como en móvil. En esta guía vas a programar un componente reutilizable, elegir disparadores y tiempos efectivos, y optimizarlo para usuarios reales.

Si necesitás contexto estratégico, repasá estas mejores prácticas de ventanas emergentes y elegí momentos inteligentes como se explica en cuándo mostrar una ventana emergente. Si recién empezás, este resumen de qué es una ventana emergente te ubica rápidamente.

Lo que vas a construir

Una modal que:

  • Se abre con un botón y puede dispararse por tiempo o por scroll.

  • Bloquea el scroll mientras está visible y lo restaura al cerrar.

  • Atrae el foco del teclado, lo mantiene dentro, permite cerrar con Esc y admite cerrar al tocar el overlay.

  • Anima entrada y salida sin tirones.

  • Es fácil de personalizar y reutilizar.

Si preferís un camino guiado mientras practicás, guardá la Academia de I Love PopUps y clases como cómo crear popups sin programar o cómo analizar los datos de tus popups.

Paso 1. HTML semántico

Empezá con un botón disparador y el contenedor del diálogo. Usá role="dialog" y aria-modal="true". Ocultalo con hidden para que no aparezca en el árbol de accesibilidad.


 

<button id="abrirPopup" class="btn">Ver oferta</button> <div id="popup" class="popup" role="dialog" aria-modal="true" aria-labelledby="popupTitulo" aria-describedby="popupDesc" hidden> <div class="popup__overlay" data-cerrar></div> <div class="popup__contenido" role="document"> <button class="popup__cerrar" aria-label="Cerrar popup" data-cerrar>&times;</button> <h2 id="popupTitulo">Obtené 10% en tu primera compra</h2> <p id="popupDesc">Sumate a nuestra lista para recibir consejos y novedades. Podés desuscribirte cuando quieras.</p> <form class="popup__form" action="#" method="post" novalidate> <label for="email">Email</label> <input id="email" type="email" required placeholder="tu@ejemplo.com" autocomplete="email"> <button type="submit" class="btn btn--primaria">Suscribirme</button> <small class="form-hint">Sin spam y con salida en un clic.</small> </form> </div> </div>

Para ideas de diseño y microcopys que realmente convierten, mirá estas buenas prácticas para crear popups que convierten.

Paso 2. CSS claro y adaptable

Variables para tematizar, transiciones suaves con opacity y transform, y un overlay que cubre toda la pantalla. Evitá animaciones exageradas.


 

:root { --popup-bg: #ffffff; --overlay-bg: rgba(0, 0, 0, 0.5); --radius: 12px; --max-w: 520px; --gap: 16px; } .popup[hidden] { display: none; } .popup__overlay { position: fixed; inset: 0; background: var(--overlay-bg); opacity: 0; transition: opacity 200ms ease; } .popup__contenido { position: fixed; inset: 0; display: grid; place-items: center; padding: 24px; } .popup__contenido > * { width: min(var(--max-w), calc(100vw - 32px)); background: var(--popup-bg); border-radius: var(--radius); box-shadow: 0 10px 30px rgba(0,0,0,.15); padding: 24px; transform: translateY(20px) scale(.98); opacity: 0; transition: transform 220ms ease, opacity 220ms ease; } .popup.abierto .popup__overlay { opacity: 1; } .popup.abierto .popup__contenido > * { transform: translateY(0) scale(1); opacity: 1; } .popup__cerrar { position: absolute; top: 10px; right: 12px; background: transparent; border: 0; font-size: 24px; cursor: pointer; } .popup__form { display: grid; gap: var(--gap); margin-top: 8px; } .btn { cursor: pointer; padding: 10px 16px; border: 1px solid #111; background: #fff; } .btn--primaria { background: #111; color: #fff; border-color: #111; }

Paso 3. JavaScript para abrir, cerrar y atrapar el foco

El script:

  • Alterna hidden y la clase .abierto.

  • Recuerda qué elemento tenía el foco y lo restaura al cerrar.

  • Atrapa el foco dentro del diálogo.

  • Cierra con overlay o con Esc.


 

<script> (() => { const popup = document.getElementById('popup'); const abrir = document.getElementById('abrirPopup'); const overlay = popup.querySelector('.popup__overlay'); const cerrarBtns = popup.querySelectorAll('[data-cerrar]'); let ultimoFoco = null; function focusables(container) { return [...container.querySelectorAll( 'a[href], button:not([disabled]), textarea, input, select, [tabindex]:not([tabindex="-1"])' )].filter(el => el.offsetParent !== null); } function abrirPopup() { ultimoFoco = document.activeElement; popup.hidden = false; popup.classList.add('abierto'); document.documentElement.style.overflow = 'hidden'; const f = focusables(popup); if (f.length) f[0].focus(); document.addEventListener('keydown', onKey); popup.addEventListener('keydown', atraparFoco); } function cerrarPopup() { popup.classList.remove('abierto'); popup.hidden = true; document.documentElement.style.overflow = ''; document.removeEventListener('keydown', onKey); popup.removeEventListener('keydown', atraparFoco); if (ultimoFoco) ultimoFoco.focus(); } function onKey(e) { if (e.key === 'Escape') cerrarPopup(); } function atraparFoco(e) { if (e.key !== 'Tab') return; const f = focusables(popup); if (!f.length) return; const primero = f[0], ultimo = f[f.length - 1]; if (e.shiftKey && document.activeElement === primero) { ultimo.focus(); e.preventDefault(); } else if (!e.shiftKey && document.activeElement === ultimo) { primero.focus(); e.preventDefault(); } } abrir.addEventListener('click', abrirPopup); overlay.addEventListener('click', cerrarPopup); cerrarBtns.forEach(el => el.addEventListener('click', cerrarPopup)); // Disparadores opcionales // 1) Después de 10 segundos setTimeout(() => { /* abrirPopup(); */ }, 10000); // 2) Al 50% de scroll const onScroll = () => { const scrolled = (window.scrollY + window.innerHeight) / document.documentElement.scrollHeight; if (scrolled > 0.5) { // abrirPopup(); window.removeEventListener('scroll', onScroll); } }; window.addEventListener('scroll', onScroll, { passive: true }); })(); </script>

Para decidir el momento exacto, apoyate en cómo utilizar ventanas emergentes en tu web y en el análisis del impacto de un popup en tu sitio web.

Accesibilidad que ayuda a convertir

  • Roles y labels correctos: role="dialog" aria-modal="true" con aria-labelledby y aria-describedby.

  • Soporte de teclado completo: mover el foco al abrir, atraparlo y devolverlo al cerrar. Esc debe cerrar.

  • Foco visible: no elimines outlines sin reemplazarlos por un estilo claro.

  • Botón de cierre accesible y grande.

  • Preferencias de movimiento: considerá @media (prefers-reduced-motion: reduce) para reducir animaciones.

Para más hábitos que elevan usabilidad y resultados, mirá cómo aprovechar al máximo I Love PopUps.

UX y contenido que generan resultados

  • Beneficio concreto y específico. Incentivos claros suelen ganar.

  • Formularios cortos. Pedir solo email suele rendir más.

  • Timing contextual. En páginas informativas, suele funcionar mejor un disparador por scroll o salida. Ver ejemplos en cuándo mostrar una ventana emergente.

  • Cierre fácil. Botón visible y overlay que acepta clic.

  • No apiles modales.

  • Móvil primero. Objetivos táctiles grandes, espaciado generoso y texto legible.

  • Coherencia visual con la marca. Para ideas prácticas, repasá estas mejores prácticas de ventanas emergentes.

Recetas de disparadores habituales

Intención de salida en escritorio


 

(function() { let disparado = false; function salida(e) { if (disparado) return; if (e.clientY <= 0) { // abrirPopup(); disparado = true; window.removeEventListener('mouseout', salida); } } window.addEventListener('mouseout', salida); })();

Mostrar después de cierta interacción


 

let interacciones = 0; function quizasMostrar() { interacciones += 1; if (interacciones === 2) { // abrirPopup(); document.removeEventListener('click', quizasMostrar); document.removeEventListener('scroll', quizasMostrar); } } document.addEventListener('click', quizasMostrar, { passive: true }); document.addEventListener('scroll', quizasMostrar, { passive: true });

Una sola vez por sesión


 

if (!sessionStorage.getItem('nl-popup')) { setTimeout(() => { // abrirPopup(); sessionStorage.setItem('nl-popup', '1'); }, 8000); }

Medir y mejorar con A/B testing

Cambios pequeños en el título, imagen o timing pueden mover mucho la aguja. La forma más rápida de aprender es hacer test A/B en tus popups. Probá una variable por vez, corré el test el tiempo suficiente y quedate con el ganador para luego iterar.

Cuando tengas datos, practicá cómo analizar los datos de tus popups: mirá vistas, CTR, envíos del formulario y resultados posteriores como compras o registros.

Integrarlo en tu sitio

Si tu sitio usa un constructor o plantillas, podés insertar el HTML en el layout y cargar el script global. Si preferís pegar un único snippet, esta guía sobre cómo instalar un script en tu sitio web te ayuda a ubicar el código sin romper el renderizado inicial.

Errores comunes a evitar

  • Ocultar o minimizar demasiado el botón de cierre.

  • Repetir el mismo popup varias veces en la misma sesión.

  • Disparar demasiado pronto cuando la persona aún se orienta.

  • Validaciones que bloquean la navegación por teclado.

  • Animaciones excesivas que ignoran prefers-reduced-motion.

Para profundizar

Publicá tu primera versión, juntá datos una semana y volvé a iterar. Los popups funcionan cuando se sienten oportunos, relevantes y respetuosos.

Signature

I Love PopUps Staff

Este artículo fue escrito por el equipo de I Love PopUps, una plataforma pensada para facilitar la creación y gestión de banners y popups sin complicaciones técnicas. Nuestro objetivo es ayudar a agencias y dueños de tiendas online a captar más atención y mejorar sus conversiones con herramientas simples, efectivas y fáciles de implementar.