No tienes acceso a esta clase

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

Modal: evento click con JavaScript

10/12
Recursos

Aportes 22

Preguntas 2

Ordenar por:

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

o inicia sesión.

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

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

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.

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

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;
}

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:[email protected]&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')
}

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

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')
  )
)

2-27-22

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”

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;
  }
}

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

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:

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')
})