Creando una ventana emergente modal || HTML/CSS/Vanilla JS

Jan 27 2023
Hoy en día, es difícil navegar por Internet sin encontrarse con una página web que utiliza algún tipo de función "emergente", ya sea haciendo clic en iniciar sesión y aparece un formulario mágicamente en primer plano o seleccionando una imagen para obtener una vista más grande. Mientras trabajaba en uno de mis primeros proyectos de desarrollo web (un generador simple de comidas/recetas que utiliza datos de la API pública themealDB.

Hoy en día, es difícil navegar por Internet sin encontrarse con una página web que utiliza algún tipo de función "emergente", ya sea haciendo clic en iniciar sesión y aparece un formulario mágicamente en primer plano o seleccionando una imagen para obtener una vista más grande. Mientras trabajaba en uno de mis primeros proyectos de desarrollo web (un generador de recetas/comida simple que utiliza datos de la API pública themealDB.com ), pensé que este tipo de método sería la manera perfecta de mostrar información detallada de recetas basada en el seleccionado ¡comida! Y así comenzó mi viaje de creación de esta "ventana emergente", que ahora sé que se conoce oficialmente como modal .

¡Producto terminado!

Configurando el HTML

En mi caso, configurar un contenedor para el modal dentro de mi archivo HTML fue bastante simple, ya que JavaScript hizo el trabajo pesado para completar la información. Un simple elemento <div> con un atributo de clase será suficiente para comenzar:

<div class="meal-container">

</div>

Como mencioné, JavaScript es uno de los verdaderos héroes de esta historia. Al utilizar la manipulación DOM para crear, personalizar y agregar toda la información necesaria a mi tarjeta de recetas, pude mostrar toda la información importante al usuario con el objeto de comida específico que se obtuvo de la API (título/imagen/ingredientes/ instrucciones):

function renderMealCard(meal) {
    mealContainer.innerHTML = '';
    const img = document.createElement('img');
    const h2 = document.createElement('h2');
    const closeButton = document.createElement('img');
    const ul = document.createElement('ul');
    
    img.src = meal.strMealThumb;
    img.id = 'food-img';
    h2.textContent = meal.strMeal;
    
    closeButton.id = 'close';
    closeButton.src = './images/close.png';
    closeButton.addEventListener('click', () => {
        hideMealCard();
    });

    mealContainer.append(closeButton, h2, img, ul);

    for(let i = 1; i <= 20; i++) {
        if(meal[`strIngredient${i}`] === '' || meal[`strIngredient${i}`] === null)
            break;

        const li = document.createElement('li');
        li.textContent = `${meal[`strMeasure${i}`]}` + ` ` + `${meal[`strIngredient${i}`]}`
        ul.append(li);
    }

    let instructions = meal.strInstructions.split('\r\n');
    instructions = instructions.map(instruction => instruction.replace('\r\n', ''));
    
    for(let i = 0; i < instructions.length; i++) {
        const p = document.createElement('p');
        p.textContent = instructions[i];
        mealContainer.append(p);
    }

    const p = document.createElement('p');
    p.textContent = '.';
    p.style.opacity = '0';
    mealContainer.append(p);
}

Diseñar el Modal con CSS

Por último, pero no menos importante, ¡era hora de tomar toda la información sin procesar y hacer que ocupe el modal emergente! El primer paso fue crear una tarjeta vacía usando el <div> que había configurado.

.meal-container {
    width: 60%;
    background: rgb(235, 235, 235);
    border-radius: 20px;
    position: absolute;
    top: 0;
    left: 50%;
    transform: translate(-50%, -50%) scale(0.1);
    text-align: center;
    padding: 0px 30px 30px 30px;
    color: #000;
    visibility: hidden;
    transition: transform 0.5s, top 0.5s;
}

Esto fue posible dentro de JavaScript, donde el detector de eventos aplicó un estilo adicional al fondo para crear un efecto borroso, además de aplicar una nueva clase al modal para animarlo a la vista. El nuevo estilo se encargó de ajustar la visibilidad y aplicar la transformación:

.open-meal-container {
    background: rgb(235, 235, 235, 0.85);
    visibility: visible;
    position: fixed;
    top: 50%;
    height: 85%;
    transform: translate(-50%, -50%) scale(1);
    overflow-y: auto;
    filter: none;
    box-shadow: rgba(45, 35, 66, 0.4) 0 16px 32px, rgba(45, 35, 66, 0.3) 0 28px 52px -12px;
    border: 5px solid rgba(255, 255, 255, 0);
    padding: 0px 20px 30px 30px;
}