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 鈥渆rror鈥 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鈥檚 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 鈥渕odal visible鈥

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

por ejemplo:

.padre .visible aqui estamos seleccionando un elemento con la clase 鈥渧isible鈥 que se encuentra dentro de otro elemento con la clase 鈥減adre鈥

.padre.visible aqui hacemos referencia a un elemento tiene las clases 鈥減adre 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')
})