No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

No se trata de lo que quieres comprar, sino de quién quieres ser. Invierte en tu educación con el precio especial

Antes: $249

Currency
$209

Paga en 4 cuotas sin intereses

Paga en 4 cuotas sin intereses
Suscríbete

Termina en:

12 Días
13 Hrs
34 Min
28 Seg

Modal: evento click con JavaScript

10/12
Recursos

Aportes 22

Preguntas 3

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

Para el ejemplo no necesariamente tienen que utilizar el !important , solo pongan que el display sea manejado únicamente por las clases .hidden y .visible

   .hidden {
        display: none;
      }

      .visible {
        display: grid;
      }

      .modal {
        width: 100%;
        height: 100%;
        background: rgba(0, 0, 0, 0.5);
        position: absolute;
        z-index: 4;
        
        place-items: center;
      }

Para no crear un evento para cada super heroe en lugar de id podriamos usar una misma clase para los 3 superheroes, y usar querySelectorAll

Cambie un poco el diseño para no tener exactamente el mismo del curso.



HTML

<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="style.css">
    <title>Document</title>
</head>
<body>
    <div class="page">
        <!-- Main Content -->
        <section class="container">
            <nav class="navbar">
                <div class="navbar__content">
                    <img src="./img/logo.svg" alt="logo spiderman">
                    <ul>
                        <li><a href="">Exclusivos</a></li>
                        <li><a href="">Nuevos</a></li>
                        <li><a href="">Gift Cards</a></li>
                        <li><a href="">Busca Una Tienda</a></li>
                    </ul>
                </div>
            </nav>

            <section class="main-content">
                <p>Diseña tu</p>
                <h1>Spiderman!</h1>
                <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Necessitatibus dolores sint nobis numquam, eos accusantium ducimus aut quisquam pariatur, consectetur labore ut hic voluptates asperiores quidem, corrupti error ullam amet.</p>
            </section>

            <section class="side-content">
                <div></div>
                <p>Spiderman</p>
                <img src="./img/spidermanAside.png" alt="">
            </section>

            <section class="footer">
                <div class="openModal">
                    <img src="./img/spidermanFooter1.png" alt="spiderman">
                </div>
                <div class="openModal">
                    <img src="./img/spidermanFooter2.png" alt="spiderman">
                </div>
                <div class="openModal">
                    <img src="./img/spidermanFooter3.png" alt="spiderman">
                </div>
            </section>
        </section>

        <!-- Loader -->
        <section class="loader">
            <div><img src="./img/load.svg" alt="imagen logo spiderman"></div>
            <div><img src="./img/load.svg" alt="imagen logo spiderman"></div>
            <div><img src="./img/load.svg" alt="imagen logo spiderman"></div>
        </section>

        <!-- Modal -->
        <section class="modal hidden">
            <div class="modal__content hidden">
                <img class="modal__content--close" src="https://img.icons8.com/external-flat-icons-inmotus-design/67/000000/external-close-basic-work-elements-flat-icons-inmotus-design.png"/>
            </div>
        </section>

    </div>
</body>
<script src="app.js"></script>
</html>

CSS

/*
    1. Posicionamiento
    2. Modelo de caja
    3. Tipografia
    4. Visuales
    5. Otros
*/

@import url("https://fonts.googleapis.com/css2?family=Roboto:wght@100&display=swap");


:root{
    --primario:#222831;
    --secundario:#393E46;
    --terciario:#00ADB5;
    --acentuar:#EEEEEE;
    --spiderman:#a71814;
}

html{
    font-size: 62.2%;
    font-family: "Roboto", sans-serif;
}
*{
    box-sizing: border-box;
    margin: 0;
    padding: 0;
    text-decoration: none;
    list-style: none;
}
body{
    font-size: 1.5rem;
    height: 100vh;
    overflow: hidden;
    background: var(--primario);
}
body,a{
    color: var(--acentuar);
}
/* LOADER */
.page{
    width: 100%;
    height: 100vh;
    position: relative;
}
.container{
    position: absolute;
    z-index: 1;
}
.loader{
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-direction: row;
    background: var(--primario);
    position: absolute;
    z-index: 3;
}
.loader div{
    width: 8rem;
    height: 8rem;
    /* border-radius: 50%; */
    margin: 1rem;
    background-image: url();
}

/* LOADER - ANIMATION */
/* FONDO */
.loader{
    animation: loader 3s linear forwards;
    opacity: 1;   
    visibility: visible;
}
@keyframes loader{
    0%,95%{
        opacity: 1;   
        visibility: visible;
    }
    100%{
        opacity: 0;
        visibility: hidden;
    }
}
/* PUNTOS DE CARGA */
.loader div{
    animation: scaling 1.5s linear infinite;
    transform: scale(1);
}
.loader div:nth-child(1){
    animation-delay: 0.2s;
}
.loader div:nth-child(2){
    animation-delay: 0.5s;
}
.loader div:nth-child(3){
    animation-delay: 0.8s;
}
@keyframes scaling {
    0%,100%{
        transform: scale(1);
    }
    30%,80%{
        transform: scale(0.5);
    }
}

/* GRID PRINCIPAL */
.container{
    width: 100%;
    height: 100%;
    display: grid;
    grid-template-columns: 55% 45%;
    grid-template-rows: 20% 50% 30%;
    grid-template-areas: 
    "nav        aside"
    "section    aside"
    "footer     aside"
}

/* NAVBAR */
.navbar{
    width: 100%;
    height: 100%;
    display: flex;
    place-content: center;
    grid-area: nav;
    border-bottom: .1rem solid var(--acentuar);
}
/* POSICIONAMIENTO DE NAVBAR */
.navbar__content{
    width: 100%;
    padding: 0 0 0 8rem;
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: 2rem;
    font-weight: 300;
}
/* ORGANIZANDO EL LOGO */
.navbar__content img{
    width: 6rem;
    padding: .8rem;
    border: .1rem solid var(--acentuar);
    border-radius: 1.2rem;
    background: var(--spiderman);   
}
/* ORGANIZANDO LAS RUTAS/URL/OPCIONES DE NUESTRO MENU */
.navbar__content ul{
    width: 100%;
    margin-block-start: .8rem;
    display: flex;
    justify-content: space-between;
}
.navbar__content ul li{
    padding: .8rem;
    border-radius: 1rem;
    font-weight: 700;
}
.navbar__content ul li:first-child{
    border: .1rem solid var(--acentuar);
    color: var(--secundario);
    background: var(--terciario);
}
.navbar__content ul li:hover{
    border: .1rem solid var(--acentuar);
    background: var(--terciario);
}
.navbar__content ul li:hover > a {
    color: var(--primario);
}


/* NAVBAR - ANIMATION */
.navbar__content{
    animation: 1.5s navbar 3s ease-in-out forwards;
    transform: translateY(-20rem);
}
@keyframes navbar {
    0%{
        transform: translateY(-20rem);
    }
    100%{
        transform: translateY(0);
    }
    
}

/* MAIN CONTENT */
.main-content{
    grid-area:section ;
    display: flex;
    flex-direction: column;
    justify-content: center;
    padding: 0 0 0 8rem; 
}
.main-content p:first-child{
    margin: 0 0 -1.4rem 2.8rem;
    font-size: 3.6rem;
    font-weight: 300;
}
.main-content h1{
    margin: 0 0 2.8rem 0;
    font-size: 4.8rem;
    font-weight: 700;
}
.main-content p:last-child{
    width: 80%;
    font-weight: 100;
}

/* MAIN CONTENT - ANIMATION */
.main-content{
    animation: 1.5s main-content 3s ease-in-out forwards;
    transform: translateX(-100rem);
}
@keyframes main-content {
    0%{
        transform: translatex(-100rem);
    }
    100%{
        transform: translateY(0);
    }
    
}

/* SIDE CONTENT  */
.side-content{
    grid-area: aside;
    display: grid;
    grid-template-columns: repeat(6,1fr);
    align-items: center;
}
/* SIDE CONTENT TEXT */
.side-content p{
    font-size: 3.6rem;
    grid-row: 1 / 2;
    grid-column: 1 / 2;
    transform: rotate(-90deg);
}

/* MAIN CONTENT TEXT - ANIMATION */
.side-content p{
    animation: 1.5s side-content-text 4s ease-in-out forwards;
    opacity: 0;
}
@keyframes side-content-text {
    0%{
        opacity: 0;
    }
    100%{
        opacity: 1;
    }
    
}

/* SIDE CONTENT IMG */
.side-content img{
    width: 100%;
    grid-row: 1 / 2;
    grid-column: 2 / 6;
}

/* MAIN CONTENT IMG - ANIMATION */
.side-content img{
    animation: 1.5s side-content-img 4s ease-in-out forwards;
    transform: translateX(200rem);
}
@keyframes side-content-img {
    0%{
        transform: translateX(200rem);
    }
    80%{
        transform: translateX(-5rem);
    }
    100%{
        transform: translateX(0rem);
    }
    
}

/* SIDE CONTENT DIV */
.side-content div{
    width: 100%;
    height: 100%;
    grid-row: 1 / 2;
    grid-column: 4 / 7;
    background: var(--acentuar);
}

/* FOOTER */
.footer{
    display: flex;
    justify-content: space-evenly;
    align-items: flex-end;
    border-radius: 0 8rem 0 0;
    background: var(--acentuar);
}

/* FOOTER - ANIMATION */
.footer{
    animation: 1.5s footer 4s ease-in-out forwards;
    transform: translateY(200rem);
}
@keyframes footer{
    0%{
        transform: translateY(200rem);
    }
    100%{
        transform: translateY(0rem);
    }
    
}
/* FOOTER DIV */
.footer div {
    display: flex;
    justify-content: center;
    width: 12rem;
    height: 50%;
    border-radius: 2rem 2rem 0 0;
    background-color: var(--terciario);
}

/* FOOTER DIV - ANIMATION */
.footer div {
    animation: 1.5s footer-div 5s ease-in-out forwards;
    transform: translateY(200rem);
}
.footer div:nth-child(1){
    animation-delay: 5s;
}
.footer div:nth-child(2){
    animation-delay: 5.3s;
}
.footer div:nth-child(3){
    animation-delay: 5.6s;
}
@keyframes footer-div{
    0%{
        transform: translateY(200rem);
    }
    100%{
        transform: translateY(0rem);
    }
    
}

/* FOOTER IMG */
.footer div img{
    width: 16rem;
    position: absolute;
    bottom: 6.5rem;
    transform: translateY(0rem) scale(1);
    transition: transform 0.5s ease-in-out;
}
.footer div:hover > img{
    cursor: pointer;
    transform: translateY(-2rem) scale(1.3);
    transition: transform 0.3s ease-in-out;
}

/* FOOTER IMG - ANIMATION */
.footer div img{
    animation: 1.5s footer-img 6.5s ease-in-out forwards;
    transform: translateY(200rem);
}
.footer div:nth-child(1) > img{
    animation-delay: 6s;
}
.footer div:nth-child(2) > img{
    animation-delay: 6.3s;
}
.footer div:nth-child(3) > img{
    animation-delay: 6.6s;
}
@keyframes footer-img{
    0%{
        transform: translateY(200rem);
    }
    100%{
        transform: translateY(0rem);
    }
    
}

/* MODAL */
.hidden{
    display: none;
}
.visible{
    display: grid;
}
.modal{
    place-items: center;
    width: 100%;
    height: 100%;
    position: absolute;
    background: rgba(0, 0, 0, 0.5);
    z-index: 3;
}
.modal__content{
    width: 50%;
    height: 50%;
    background:var(--secundario);
}

JS

const modal = document.querySelector('.modal')
const modalContent = document.querySelector('.modal__content')
const openModal = document.querySelectorAll('.openModal')
const closeModal = document.querySelector('.modal__content--close')

openModal.forEach((btnModal) =>
    btnModal.addEventListener('click', () => {
        openModalFunction(modal)
        openModalFunction(modalContent)
    }) 
)

closeModal.addEventListener('click', () => {
    closeModalFunction(modal)
    closeModalFunction(modalContent)
})

const openModalFunction = function  (objModal){
    objModal.classList.remove('hidden')
    objModal.classList.add('visible')
}
const closeModalFunction = function  (objModal){
    objModal.classList.remove('visible')
    objModal.classList.add('hidden')
}

considero que sería más sencillo solo agregar y quitar la clase hidden y así solo en JS agregas y quitas esa clase para no tener que utilizar Important o remove y add en una misma función. 💚

Mi solución con un metodo forEach y querySelectorAll

¿Quién más pensó que sería buena idea que Estefany haga el curso de JS tambien 😍?

Creo que no es necesario el uso del !important en la clase modal, solo es no agregar el parámetro grid y dejarle esa tarea a la clase visible, solo en modal usar el place-items.

Modal: evento click con JavaScript

Código de la clase: https://github.com/paolojoaquin/lego-superheroes/tree/Clase/10-evento-click-con-javascript
Según entendí por @erickgomez (gracias 😄).
1.- NO hace falta poner !important, porque recordemos que es una mala práctica.
2.- Estaba bien como la profesora lo estaba haciendo, el único “error” fue de que inicializamos nuestra clase modal diferente de none osea le decíamos que aparezca en el DOM.
3.- Para arreglar esto debíamos quitar el display:grid o cambiarlo por display:none de nuestra clase .modal , quedando:
Antes:

.modal {
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.5);
    position: absolute;
    z-index: 4;
    display: grid;
    place-items: center;
}

Después:

.modal {
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.5);
    position: absolute;
    z-index: 4;
    /* display: none; */
    place-items: center;
}

no hace falta usar el important con mejorar la especificidad basta.

.modal.hidden{
display: none;
}

.modal.visible{
display: grid;
}

.modal{
width: 100%;
height: 100%;
background: rgba(0,0,0, 0.5);
position: absolute;
z-index: 4;

display: grid;
place-items: center;

}

.modal.visible es cuando elemento tiene la clases “modal visible”

.modal.hidden es cuando el elemento tiene las clases
"modal hidden"

por ejemplo:

.padre .visible aqui estamos seleccionando un elemento con la clase “visible” que se encuentra dentro de otro elemento con la clase “padre”

.padre.visible aqui hacemos referencia a un elemento tiene las clases “padre visible”

Consejo 😃

Actualmente estoy trabajando para un proyecto de factoring como frontend developer y puedo decir que si es mala practica el !Important ,no considero excepciones al respecto , debido a desarrolladores pasados me he topado con código de CSS muy dificil de manipular o directamente inmanipulable esto debido a !important regados por ahí ,recordemos que el código debe ser siempre reusable y escalable ,así que bajo ninguna circunstancia usen !important ,no notaran el problema si no hasta que el proyecto tenga miles y miles de líneas de código en solo estilos

Solucioné de la siguiente manera los eventos de click para cada imagen.

Coloqué una clase a cada div del footer :

<section class="footer">
        <div class="buttonImage" id="button1">
          <img src="https://i.ibb.co/tKWqw8J/spiderman.png" alt="spiderman">
        </div>

        <div class="buttonImage" id="button2">
          <img src="https://i.ibb.co/Xzsdvgg/robin.png" alt="robin">
        </div>

        <div class="buttonImage" id="button3">
          <img src="https://i.ibb.co/M18p91c/batman.webp" alt="batman">
        </div>
      </section>

Y los usé desde Javascript trayendolos con un querySelectorAll(). Lo que me retorna un NodeList para así poder usar el metodo forEach() y recorrerlos escribiendo un solo evento para cada uno.

const modal = document.querySelector('.modal')
const allButtonsImages = document.querySelectorAll('.buttonImage')
const closeButton = document.querySelector('.modal__content--close')

allButtonsImages.forEach(simpleButton => {
  simpleButton.addEventListener('click', ()=>{
    modal.classList.remove('hidden')
    modal.classList.add('visible')
  })
})

closeButton.addEventListener('click', () => {
  modal.classList.remove('visible')
  modal.classList.add('hidden')
})

HTML semantico y accesible:

<section class="modal hidden">
	<div class="modal__content">
		<button
			class="modal__close-btn"
			id="modal__close-btn"
			title="button to close modal"
		></button>
	</div>
</section>

.
Estilos usando Sass:

.
JS

No es necesario el !important adema’s he agregado a que cuando le demos click en el back del modal se cierre también:

HTML

<!-- modal -->
            <section class="modal modal--hidden">
                <div class="modal__content">
                    <img class="modal__content--close" src="https://img.icons8.com/windows/50/000000/macos-close.png" alt="Cerrar Modal">
                </div>
                <div class="back-modal" id="back-modal"></div>
            </section>

CSS

.modal {
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 0.5);
    position: fixed;
    z-index: 5;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    display: grid;
    place-items: center;
}

.modal--hidden {
    display: none;
}

.modal--visible {
    display: grid;
}

.modal__content {
    background-color: white;
    width: 50%;
    height: 50%;
    z-index: 7;
    position: relative;
}

.modal .back-modal {
    width: 100%;
    height: 100%;
    position: fixed;
    z-index: 6;
}
.modal .modal__content--close {
    cursor: pointer;
    position: absolute;
    right: 0;
}

JS

const modal = document.querySelector('.modal');
const button1 = document.querySelector('#button1');
const backModal = document.querySelector('#back-modal');
const closeModal = document.querySelector('.modal__content--close');

button1.addEventListener('click', () => {
    modal.classList.remove('modal--hidden');
    modal.classList.add('modal--visible');
});

closeModal.addEventListener('click', () => {
    modal.classList.add('modal--hidden');
    modal.classList.remove('modal--visible');
});

backModal.addEventListener('click', () => {
    modal.classList.add('modal--hidden');
    modal.classList.remove('modal--visible');
});

Buenas comunidad, aquí les dejo una forma diferente de realizar los eventos click sin escribir tantas lineas de código y para todos los buttons.


	<section class="footer">
                <div  onclick="visibleModal()">
                    <img src="https://i.ibb.co/tKWqw8J/spiderman.png" alt="spiderman">
                </div>

                <div  onclick="visibleModal()">
                    <img src="https://i.ibb.co/Xzsdvgg/robin.png" alt="robin">
                </div>

                <div  onclick="visibleModal()">
                    <img src="https://i.ibb.co/M18p91c/batman.webp" alt="batman">
                </div>
            </section>

Y el script es el siguiente

const modal = document.querySelector('.modal');
const buttonClose = document.querySelector('.modal-content-close');

const visibleModal = () => {
    modal.classList.remove('hidden')
    modal.classList.add('visible')
}

buttonClose.addEventListener('click', () => {
    modal.classList.remove('visible')
    modal.classList.add('hidden')
})

Recuerden que el css el navegador procesa los estilos desde el primero hasta el ultimo, si primero colocan los estilos del .hidden y luego .vissible, al momento de renderizar siempre quedaran los del .visible porque es el ultimo en cargar

Para no hacer un EventListener para cada boton se puede hacer asi ===>> ```js const modal = document.querySelector('.modal'); const heroes = document.querySelectorAll('#button1'); const close = document.querySelector('.modal-content--close') for (const hero of heroes) { hero.addEventListener('click', () => { modal.classList.remove('hidden'); modal.classList.add('visible'); }) } close.addEventListener('click', () => { modal.classList.remove('visible'); modal.classList.add('hidden'); }) ```

Por si quieres cerrar tu ventana dando click en la parte gris, te dejo el codigo.

<code> 
modal.addEventListener('click',(event)=>{
    if(!modal__content.contains(event.target)){
        modal.classList.remove("visible");
        modal.classList.add("hidden");
    }
})

Si necesitan íconos para sus proyectos, pueden visitar la página de evericons.

Para no crear variables por cada superhéroe, podemos usar el método querySelectorAll y después de ello un forEach para darles el addEventListener.

const modal_triggers = document.querySelectorAll('.footer__images')

modal_triggers.forEach(
  e => e.addEventListener(
    'click', () => modal.classList.remove('hidden')
  )
)

Buenas, así me quedo a mí por si alguien le interesa

JavaScript

const images = document.querySelectorAll('.img');
const modal = document.querySelector('.modal')

images.forEach(image => {
  image.addEventListener("click", () => {
    modal.classList.remove('hidden')
    modal.classList.add('visible')
  })
});

const close = document.querySelector('.icon-close')

close.addEventListener('click', () => {
  modal.classList.remove('visible')
  modal.classList.add('hidden')
})

HTML

<div>
	<img class="img"  src="/public/assets/joker.png" width="160px" alt="image joker lego">
</div>
<div>
	<img class="img" src="../public/assets/deadpool.png" width="200px" alt="image deadpool lego">
</div>
<div>
	<img class="img" src="../public/assets/spiderman.png" width="200px" alt="image spiderman lego">
</div>

Sass

.hidden {
  display: none;
}

.visible {
  display: flex;
  align-items: center;
  justify-content: center;
}

.modal {
  width: 100%;
  height: 100%;
  background-color: rgb(0, 0, 0, 0.5);
  position: absolute;
  z-index: 4;
}

.modal-content {
  position: relative;
  background-color: $color-primary;
  width: 50%;
  height: 50%;

  img {
    position: absolute;
    right: 15px;
    top: 15px;
    width: 35px;
    cursor: pointer;
  }
}

En JavaScript existe un concepto que es muy importante y se pregunta mucho en las entrevistas y es: Event Delegation , es una tecnica que involucra añadir un Event Listener al padre del elemento en lugar del añadirselo a los elementos descendientes.

Lo que hice fue añadirle el evento click al padre .footer__content y con el target logro detectar a cual elemento hijo se le esta haciendo click. Esto me permite que ahorrar mucho codigo y por si algun motivo quiero añadir otro personaje no tengo que añadirle un evento a cada hijo.

// HTML CODE
<section class="footer__content">
  <div>
    <img src="./assets/spiderman.png" alt="spiderman">
  </div>
  <div>
    <img src="./assets/robin.png" alt="robin">
  </div>
  <div>
    <img src="./assets/batman.webp" alt="batman">
  </div>
</section>
// JAVASCRIPT CODE
const button = document.querySelector('.footer__content');
const modal = document.querySelector('.modal');

button.addEventListener('click', handleModal)

function handleModal(e) {
    const element = ['DIV', 'IMG'];
    const target = e.target.tagName;
    
    if (element.includes(target)) {
        modal.classList.remove('hidden');
    }
}

para mas informacion: