How to create a reusable modal in vanilla JavaScript - javascript

I am making a website using only JavaScript, HTML, and CSS (no Bootstrap or jQuery).
I have used JavaScript to get the details of the cakes onto the page, as shown with the code below.
Now, I am looking to create a button "View recipes" to view each cake using a modal.
Currently, the button appears outside of the box. I'm still pretty new to this and would appreciate any help on how to add in a button that opens a modal that displays different recipes for each box generated from the cakeData instances.
The code below for each button and modal is hardcoded in HTML. I would like to refactor the HTML code for the button over to recipes.js where it can be associated with the cakeData instances. I'm trying to condense the code down so I'm not copying and pasting code in HTML page, as I want to put 10+ cakes as the website progresses.
// recipes.js
"use strict";
function buildCake(cake) {
const article = document.createElement('article');
article.classList.add('cake');
const h4 = document.createElement('h4');
h4.textContent = cake.name;
article.appendChild(h4);
const p = document.createElement('p');
p.textContent = cake.description;
article.appendChild(p);
const image = document.createElement('img');
image.src = cake.img;
article.appendChild(image);
return article;
}
const cakeData = [{
name: "Chocolate Cake",
img: "../img/chocolate-cake.jpg",
description: "Gooey chocolate cake",
button: ""
},
{
name: "Chocolate Drip Cake",
img: "../img/drip.jpg",
description: "Chocolate layered sponge cake"
},
{
name: "Victoria Sponge Cake",
img: "../img/VSCake.jpg",
description: "Airy sponge cake"
},
{
name: "Fondant Cake",
img: "../img/Aishteru.jpg",
description: "Airy sponge cake with fondant"
}
]
cakeData.forEach(loadCake);
function loadCake(cake) {
const mycake = buildCake(cake);
cakes.appendChild(mycake);
}
document.getElementById('cakes').appendChild(cake);
document.addEventListener('click', function(e) {
e = e || window.event;
var target = e.target || e.srcElement;
if (target.hasAttribute('data-toggle') && target.getAttribute('data-toggle') == 'modal') {
if (target.hasAttribute('data-target')) {
var m_ID = target.getAttribute('data-target');
document.getElementById(m_ID).classList.add('open');
e.preventDefault();
}
}
// Close modal window with 'data-dismiss' attribute or when the backdrop is clicked
if ((target.hasAttribute('data-dismiss') && target.getAttribute('data-dismiss') == 'modal') || target.classList.contains('modal')) {
var modal = document.querySelector('[class="modal open"]');
modal.classList.remove('open');
e.preventDefault();
}
}, false);
// scripts.js
"use-strict";
function toggleNav() {
document.getElementById("sideNav").classList.toggle('open');
}
closeNav.addEventListener('click', toggleNav);
openNav.addEventListener('click', toggleNav);
body {
background-color: #FF7E41;
font-family: sans-serif;
margin: 0;
}
h1 {
color: blanchedalmond;
font-size: 40px;
text-align: center;
padding: 30px;
}
nav {
display: flex;
flex-direction: column;
align-items: stretch;
text-align: center;
height: 100%;
width: 100%;
top: 0;
/* Stay at the top */
left: -100%;
position: fixed;
z-index: 1;
/* Stay on top */
background-color: #FF9765;
overflow-x: hidden;
transition: 2s;
opacity: 0.5;
padding: 2px;
}
nav .menu,
.menu1 {
text-align: right;
}
nav.open {
left: 0;
cursor: pointer;
font-size: 40px;
align-content: right;
opacity: 1;
}
nav a,
.menu,
.menu1 {
padding: 0.25em 0.5em;
text-decoration: none;
font-size: 25px;
color: rgb(0, 0, 0);
display: block;
transition: 2s;
}
.menu {
top: 0;
}
a {
transition: 2s ease;
padding: 2px;
}
main {
width: 85% padding: 0px 30px;
}
/* recipes.html styles */
.cake-grid {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-evenly;
align-items: center;
align-content: center;
padding: 0;
margin: 0;
}
article.cake {
border: 5px solid blanchedalmond;
padding: 10px;
width: 50%;
}
img {
width: 150px;
height: 175px;
}
/* Popup Box */
.modal {
position: fixed;
top: 0;
left: 0;
bottom: 0;
right: 0;
display: none;
overflow: auto;
background-color: #000000;
background-color: rgba(0, 0, 0, 0.7);
z-index: 9999;
}
.modal-window {
position: relative;
background-color: #FFFFFF;
width: 50%;
margin: 10% auto;
padding: 20px;
}
.modal-window.small {
width: 30%;
}
.modal-window.large {
width: 75%;
}
.close {
position: absolute;
top: 0;
right: 0;
color: rgba(0, 0, 0, 0.3);
height: 30px;
width: 30px;
font-size: 30px;
line-height: 30px;
text-align: center;
}
.close:hover,
.close:focus {
color: #000000;
cursor: pointer;
}
.open {
display: block;
}
.btn {
background-color: blanchedalmond;
border: none;
color: black;
padding: 10px;
text-align: right;
cursor: pointer;
}
<header>
<span class="menu" id="openNav">☰</span>
<nav id="sideNav">
<span class="menu1" id="closeNav">×</span>
Home
Recipes
Ingredients
About
</nav>
<h1>Recipes</h1>
</header>
<main>
<section id="cakes" class="cake-grid">
<article id="cake">
<p>
<button data-target="simpleModal_1" data-toggle="modal" class="btn">View Recipe</button>
</p>
<div id="simpleModal_1" class="modal">
<div class="modal-window">
<h3>Chocolate cake</h3>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
</div>
</div>
<p>
<button data-target="simpleModal_2" data-toggle="modal" class="btn">View Recipe</button>
</p>
<div id="simpleModal_2" class="modal">
<div class="modal-window">
<h3>Victoria sponge cake</h3>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
</div>
</div>
</article>
</section>

You have to target the .btn class. This class tells the document where to position the button. Of course, there are different ways to put the buttons inside the box. I would recommend reading this guide about CSS positioning. https://developer.mozilla.org/en-US/docs/Web/CSS/position.
// recipes.js
"use strict";
function buildCake(cake) {
const article = document.createElement('article');
article.classList.add('cake');
const h4 = document.createElement('h4');
h4.textContent = cake.name;
article.appendChild(h4);
const p = document.createElement('p');
p.textContent = cake.description;
article.appendChild(p);
const image = document.createElement('img');
image.src = cake.img;
article.appendChild(image);
return article;
}
const cakeData = [{
name: "Chocolate Cake",
img: "../img/chocolate-cake.jpg",
description: "Gooey chocolate cake",
button: ""
},
{
name: "Chocolate Drip Cake",
img: "../img/drip.jpg",
description: "Chocolate layered sponge cake"
},
{
name: "Victoria Sponge Cake",
img: "../img/VSCake.jpg",
description: "Airy sponge cake"
},
{
name: "Fondant Cake",
img: "../img/Aishteru.jpg",
description: "Airy sponge cake with fondant"
}
]
cakeData.forEach(loadCake);
function loadCake(cake) {
const mycake = buildCake(cake);
cakes.appendChild(mycake);
}
document.getElementById('cakes').appendChild(cake);
document.addEventListener('click', function(e) {
e = e || window.event;
var target = e.target || e.srcElement;
if (target.hasAttribute('data-toggle') && target.getAttribute('data-toggle') == 'modal') {
if (target.hasAttribute('data-target')) {
var m_ID = target.getAttribute('data-target');
document.getElementById(m_ID).classList.add('open');
e.preventDefault();
}
}
// Close modal window with 'data-dismiss' attribute or when the backdrop is clicked
if ((target.hasAttribute('data-dismiss') && target.getAttribute('data-dismiss') == 'modal') || target.classList.contains('modal')) {
var modal = document.querySelector('[class="modal open"]');
modal.classList.remove('open');
e.preventDefault();
}
}, false);
// scripts.js
"use-strict";
function toggleNav() {
document.getElementById("sideNav").classList.toggle('open');
}
closeNav.addEventListener('click', toggleNav);
openNav.addEventListener('click', toggleNav);
body {
background-color: #FF7E41;
font-family: sans-serif;
margin: 0;
}
h1 {
color: blanchedalmond;
font-size: 40px;
text-align: center;
padding: 30px;
}
nav {
display: flex;
flex-direction: column;
align-items: stretch;
text-align: center;
height: 100%;
width: 100%;
top: 0;
/* Stay at the top */
left: -100%;
position: fixed;
z-index: 1;
/* Stay on top */
background-color: #FF9765;
overflow-x: hidden;
transition: 2s;
opacity: 0.5;
padding: 2px;
}
nav .menu,
.menu1 {
text-align: right;
}
nav.open {
left: 0;
cursor: pointer;
font-size: 40px;
align-content: right;
opacity: 1;
}
nav a,
.menu,
.menu1 {
padding: 0.25em 0.5em;
text-decoration: none;
font-size: 25px;
color: rgb(0, 0, 0);
display: block;
transition: 2s;
}
.menu {
top: 0;
}
a {
transition: 2s ease;
padding: 2px;
}
main {
width: 85% padding: 0px 30px;
}
/* recipes.html styles */
.cake-grid {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-evenly;
align-items: center;
align-content: center;
padding: 0;
margin: 0;
}
article.cake {
border: 5px solid blanchedalmond;
padding: 10px;
width: 50%;
}
img {
width: 150px;
height: 175px;
}
/* Popup Box */
.modal {
position: fixed;
top: 0;
left: 0;
bottom: 0;
right: 0;
display: none;
overflow: auto;
background-color: #000000;
background-color: rgba(0, 0, 0, 0.7);
z-index: 9999;
}
.modal-window {
position: relative;
background-color: #FFFFFF;
width: 50%;
margin: 10% auto;
padding: 20px;
}
.modal-window.small {
width: 30%;
}
.modal-window.large {
width: 75%;
}
.close {
position: absolute;
top: 0;
right: 0;
color: rgba(0, 0, 0, 0.3);
height: 30px;
width: 30px;
font-size: 30px;
line-height: 30px;
text-align: center;
}
.close:hover,
.close:focus {
color: #000000;
cursor: pointer;
}
.open {
display: block;
}
.btn {
position: relative;
left: -280px;
top: 100px;
background-color: blanchedalmond;
border: none;
color: black;
padding: 10px;
text-align: right;
cursor: pointer;
}
<header>
<span class="menu" id="openNav">☰</span>
<nav id="sideNav">
<span class="menu1" id="closeNav">×</span>
Home
Recipes
Ingredients
About
</nav>
<h1>Recipes</h1>
</header>
<main>
<section id="cakes" class="cake-grid">
<article id="cake">
<p>
<button data-target="simpleModal_1" data-toggle="modal" class="btn">View Recipe</button>
</p>
<div id="simpleModal_1" class="modal">
<div class="modal-window">
<h3>Chocolate cake</h3>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
</div>
</div>
<p>
<button data-target="simpleModal_2" data-toggle="modal" class="btn">View Recipe</button>
</p>
<div id="simpleModal_2" class="modal">
<div class="modal-window">
<h3>Victoria sponge cake</h3>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
</div>
</div>
</article>
</section>

Related

How to prevent my hamburger icon disappearing from screen when changing the screen width?

So, I am currently building a website with HTML, CSS, and VanillaJS and the hamburger icon for the mobile menu does not work, because although I set it to a fixed position, when I am checking the responsivity of the screen on different device screen widths by decreasing the width itself the icon slips away and it just moves towards the left side of the page.
Is there any way to prevent this from happening?
//PICTURES
First, the hamicon can be seen
But as I start decreasing the width of the screen it disappears
//HERE IS MY HTML CODE
<!DOCTYPE html>
<html lang="en">
<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="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<link rel="stylesheet" href="gallery.css">
<title>Eckert Művek Galéria</title>
</head>
<body>
<div class="floating-btn show-btn" aria-label="up button" role="button">
<img src="assets/svg_files/chevron-up-solid.svg" alt="up img" />
</div>
<header>
<nav>
<div class="logo">
<img class="header-logo" src="assets/icons/114533_321471.png" alt="">
</div>
<ul id="desktop-menu">
<li class="nav-item">Főoldal</li>
<li class="nav-item">Rólunk</li>
<li class="nav-item">Szolgáltatások</li>
<li class="nav-item">Miért mi?</li>
<li class="nav-item">Galéria</li>
<li class="nav-item">Kapcsolatok</li>
</ul>
<!--HAMBURGER ICON-->
<div class="header-right-gap">
<button class="hamburger" aria-label="hamburger button">
<div class="line line-1"></div>
<div class="line line-2"></div>
<div class="line line-3"></div>
</button>
</div>
</nav>
<!--MOBILE MENU-->
<div class="mobile-menu">
<ul class="m-menu">
<li >Főoldal</li>
<li >Rólunk</li>
<li >Szolgáltatások</li>
<li >Miért mi?</li>
<li >Galéria</li>
<li >Kapcsolat</li>
</ul>
</div>
</header>
<main class="carousel-container">
<div class="carousel-images">
<img src="assets\images\pavebrick\buckgrey.jpg" alt="img-1">
<img src="assets\images\pavebrick\colorful.jpg" alt="img-2">
<img src="assets\images\pavebrick\greybigplace.jpg" alt="img-3">
<img src="assets\images\pavebrick\colbig.jpg" alt="img-4">
<img src="assets\images\pavebrick\wheelgrey.jpg" alt="img-5">
<img src="assets\images\pavebrick\yardrock.jpg" alt="img-6">
</div>
<div class= "btn-container">
<div class="btn btn-left">
<img src="assets/svg_files/arrow-left-solid.svg" alt="left-arrow">
</div>
<div class="btn btn-right">
<img src="assets/svg_files/arrow-right-solid.svg" alt="right-arrow">
</div>
</div>
</main>
<footer>
<div class="footer-container">
<div class="footer-top">
<nav>
<ul>
<li>Főoldal</li>
<li>Rólunk</li>
<li>Szolgáltatások</li>
<li>Miért mi?</li>
<li>Galéria</li>
<li>Kapcsolatok</li>
</ul>
</nav>
<div class="text-container">
<h4>Ttitle-1</h4>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit.
Dicta modi laborum quibusdam quis natus debitis qui dolor
voluptatibus ab sit, cum saepe enim unde doloribus veniam
numquam perspiciatis optio impedit.</p>
</div>
<div class="text-container">
<h4>Ttitle-1</h4>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit.
Dicta modi laborum quibusdam quis natus debitis qui dolor
voluptatibus ab sit, cum saepe enim unde doloribus veniam
numquam perspiciatis optio impedit.</p>
</div>
</nav>
</div>
<!--Social media icons-->
<div class="social-media-icons">
<div class="sm-container" id="insta">
<div class="sm-icon">
</div>
</div>
<div class="sm-container" id="github">
<div class="sm-icon">
</div>
</div>
<div class="sm-container" id="facebook">
<div class="sm-icon">
</div>
</div>
<div class="sm-container" id="linkedin">
<div class="sm-icon">
</div>
</div>
</div>
<!--Social media icons-->
<div class="footer-bottom">
<p>© Eckert Művek Kft. Minden jog fenntartva.</p>
</div>
</div>
</footer>
<script src="gallery.js"></script>
</body>
</html>
//AND HERE IS MY CSS CODE
/CSS RESET/
*, *::after, *::before { box-sizing: border-box; margin: 0; padding: 0; }
:root { --font-size: 18px; --bg-color-flt-btn: yellow; }
body { width: 100%; height: 100%; }
.floating-btn { position: fixed; bottom: 3.5vh; right: 0; width: 50px; height: 50px; z-index: 100; background-color: var(--bg-color-flt-btn); border-radius: 50%; padding: 10px; box-shadow: 0 0 5px hsla(0, 0%, 0%, hsla(0,0%,0%,0.5)); cursor: pointer; margin-right: 1rem; border: 1px solid #000; }
.show-btn { display: block; }
a { text-decoration: none; color: inherit; }
/HEADER STYLE/
header { width: 100%; height: 120px; background-color: black; color: white; display: flex; align-items: center; position: fixed; top: 0; left: 0; z-index: 10; }
/Srcollbar/
::-webkit-scrollbar{ width: 15px; background: #000; }
::-webkit-scrollbar-thumb { background: yellow; border-radius: 10px; border: 1px solid black; }
::-webkit-scrollbar-thumb:active { background: orangered; }
nav, .footer-container { width: min(90%, 1200px); display: flex; margin-inline: auto; position: relative;
}
nav { justify-content: space-between; /display: flex; flex-direction: flex-end; font-size: 30px;/
}
.nav-item a { color: var(--clr-nav-item-main); list-style: none; text-transform: uppercase; font-size: 20px; font-weight: bold; height: 100%; text-decoration: none; position: relative; margin: .5em .8em; padding: 10px;
}
/újonnan adtam hozzá 2023.01.12./ /nav a { position: relative; z-index: 1; justify-content: space-evenly; height: 100%; }/
nav ul { display: flex; gap: 1rem; width: 100%; justify-content: center; margin-top: 3.5rem;
/*margin-top: 2rem;*/
}
nav ul li { text-transform: uppercase; list-style: none;
}
.nav-item a::before, .nav-item a::after { content: ''; height: 14px; width: 14px; position: absolute; transition: all .35s ease; opacity: 0; }
nav a::before { content: ''; right: 0; top: 0; border-top: 3px solid #ffed4b; border-right: 3px solid #fdcd3b; transform: translate(-100%, 50%); /-100%, 50%/ }
.nav-item a:after { content: ''; left: 0; bottom: 0; border-bottom: 3px solid #fdcd3b; border-left: 3px solid #ffed4b; transform: translate(100%, -50%); /100%, -50%/ }
.nav-item a:hover:before, .nav-item a:hover:after{ transform: translate(0,0); opacity: 1; }
nav ul li a:hover { color: yellow; }
/Logo/
.logo img { position: absolute; width: 150px; height: 90px; margin-top: -2rem; margin-left: 70rem; left: 0; top: 0; }
/CAROUSEL SSTYLE/ /ha négy képünk van akkor ez 200 vw lesz/
.carousel-container { position: relative; width: 100%; height: 100vh; overflow: hidden;
}
`
/*transform: translateX(-200vw);*/
.carousel-images { transition: all 0.8s ease; width: 600vw; /700-zal és 800-zal is működik/ display: flex; height: 100%;
}
.carousel-images img { width: 100vw; height: 100%; object-fit: cover; }
.btn-container { position: absolute; display: flex; width: 100px; justify-content: space-between; bottom: 10vh; left: calc(50% - 75px); }
.btn { width: 40px; height: 40px; border: 2px solid #000; background-color: #fff; padding: 10px; border-radius: 10px;
}
.btn:hover { cursor: pointer; }
.btn img { width: 100%; height: 100%; }
/FOOTER STYLE/
footer { width: 100%; background-color: #000; padding-block: 4rem; color: white; }
.footer-container { flex-direction: column;
}
.footer-container nav ul { flex-direction: column; }
.footer-top { width: 100%; display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem;
}
.footer-bottom { margin-top: 3rem; text-align: center;
}
/SOCIAL MEDIA ICONS/
.social-media-icons { width: 100%; display: flex; justify-content: center; align-items: center; flex-direction: row;
}
.sm-container { display: flex; justify-content: center; flex-direction: row; gap: 2rem; padding:1rem; border: 1px black; }
.fa { border-radius: 50%; }
.fa-instagram { background: #125688; color: white; padding: 1rem;
}
.fa-github { background: white; color: black; padding: 1rem;
}
.fa-facebook { background: #4267B2; color: white; padding: 1rem; }
.fa-linkedin { background: #3B5998; color: white; padding: 1rem; }
/MOBILE MENU/ .mobile-menu { display: none; }
.mobile-menu { display: flex; width: 100%; /.line a szülő tehát 40px a width/ height: calc(100vh - 80px); align-items: center; justify-content: center; position: absolute; top: 80px; left: 0; background-color: black; transform: translate(-100%); transition: all 0.4s ease; z-index: 100; }
.mobile-menu-on { display: flex; /**/ transform: translate(0); }
.m-menu { display: flex; flex-direction: column; gap: 2rem; text-align: center; font-size: 1.4rem; list-style: none; }
/hamburger icon/
.hamburger { display: none; position: fixed; width: 50px; height: 50px; border: none; background-color: transparent; margin-left: -60rem; margin-top: -2rem;
/* margin-left: -4rem; margin-top: -1.5rem;*/
}
.hamburger:hover { border: 6px solid; border-color: yellow; width: 43px; /margin-left: 4px; transform: scale(1.2);/ } .hamburger:hover .line.line-1 { /display: none;/ transform: rotate(45deg) translateY(7.5px); background-color: yellow;
}
.hamburger:hover .line.line-2 {
display: none;
}
.hamburger:hover .line.line-3 {
/*display: none;*/
transform: rotate(-45deg) translateY(-7.5px);
background-color: yellow;
}
.line {
transition: all .4s ease;
width: 40px;
height: 5px;
background-color: white;
margin-block: 5px;
border-radius: 10px;
}
/RESPONSIVE VERSION/
#media (max-width: 1200px) {
.hamburger { display: block; }
#desktop-menu { display: none; }
}
#media (max-width: 900px) {
footer nav ul {
flex-direction: column;
}
footer nav ul li a { font-size: 15px; padding: 15px; } }
#media (max-width: 750px) { .footer-container { display: flex; flex-wrap: wrap; }
footer nav ul li a { font-size: 10px; padding: 15px; }
.text-container p { font-size: 10px; } }
#media (max-width: 600px) {
}
//AND MY JS CODE
// MOBILE MENU
const header = document.querySelector('header')
const btn = document.querySelector('.hamburger')
const menu = document.querySelector('.mobile-menu')
const line1 = document.querySelector('.line-1')
const line2 = document.querySelector('.line-2')
const line3 = document.querySelector('.line-3')
/*let navUl = docuemnt.querySelector('ul')*/
// FLOATING BUTTON
const floatingBtn = document.querySelector('.floating-btn');
window.addEventListener('scroll', ()=> {
if (document.documentElement.scrollTop > 400) {
floatingBtn.classList.add('show-btn')
} else {
floatingBtn.classList.remove('show-btn')
}
})
floatingBtn.addEventListener('click', () => {
document.documentElement.scrollTop = 0
})
//SCROLLING EFFECT
window.addEventListener('scroll', () => {
if (document.documentElement.scrollTop > 100) {
header.style.display = 'none'
} else {
header.style.display = 'block'
// navUl.style.marginTop = '32px'
}
})
btn.addEventListener('click', () => {
menu.classList.toggle('mobile-menu-on')
line1.classList.toggle('line-1-on')
line2.classList.toggle('line-2-on')
line3.classList.toggle('line-3-on')
})
//CAROUSEL
const btnLeft = document.querySelector('.btn-left');
const btnRight = document.querySelector('.btn-right');
const images = document.querySelector('.carousel-images');
let index = 0; // első kép
// képek mozgásának automatizálása (slide effect)
setInterval(()=> {
//slide(1) vagy függvényt teesszük csak be az alsó 5 sor helyett
if (index === 5) {
index = 0;
} else {
index++
}
images.style.transform = `translateX(-${100*index}vw)`
}, 5000)
console.log('.carousel-images')
const slide = (direction) => {
if (direction === 'left') {
if (index === 0) {
index = 5;
} else {
index--
}
} else if (direction === 'right') {
if (index === 5) {
index = 0;
} else {
index++
}
}
images.style.transform = `translateX(-${100*index}vw)`
}
btnLeft.addEventListener('click', () => {
//slide('left') vagy -1
if (index === 0) {
index = 5;
} else {
index--
}
images.style.transform = `translateX(-${100*index}vw)`
})
// ha az index 2 (4. elem) de az nincs, akkor ugrik vissza az első képre
btnRight.addEventListener('click', () => {
//slide('right') 1
if (index === 5) {
index = 0;
} else {
index++
}
images.style.transform = `translateX(-${100*index}vw)`
})
document.querySelector('#contact-form').addEventListener('submit', (e) => {
e.preventDefault();
e.target.elements.name.value = '';
e.target.elements.email.value = '';
e.target.elements.message.value = '';
});
Well, originally the hamicon was placed on the right side of the header. Since I have changed it, this kind of problem has arisen somewhy. I am still a beginner, but it is not the first time I am doing this, but still, I was unable to detect the source of the problem.
If somebody could give me some hints I would appreciate it!
Thank you very much in advance!

Carousel slides appear beneath each other on click

I'm using HTML/CSS and vanilla JS. I'm trying to create a simple carousel. However, whenever I click the 'next' button, the following slides show up under the last one. I'm not sure why this is happening. Code snippets are below. Can someone explain why this is happening?
By the way, I have not optimized this page for media queries yet, so it might look a little weird on smaller screens.
const buttons = document.querySelectorAll("[data-carousel-btn]");
buttons.forEach((button) => {
button.addEventListener("click", () => {
const offset = button.dataset.carouselBtn === "next" ? 1 : -1;
const slidesContainer = button
.closest("[data-carousel]")
.querySelector("[data-carousel-slides");
const slides = slidesContainer.querySelectorAll("[data-carousel-slide]");
const activeSlide = slidesContainer.querySelector("[data-active]");
const activeSlideIndex = [...slides].indexOf(activeSlide);
const nextSlideIndex = activeSlideIndex + offset;
if (nextSlideIndex < 0) {
slides[slides.length + nextSlideIndex].dataset.active = true;
return delete activeSlide.dataset.active;
}
if (nextSlideIndex >= slides.length) {
slides[0].dataset.active = true;
return delete activeSlide.dataset.active;
}
slides[nextSlideIndex].dataset.active = true;
return delete activeSlide.dataset.active;
});
});
.carouselContainer {
width: 1000px;
height: 500px;
position: relative;
display: flex;
justify-content: center;
border-style: dashed;
border-color: #010043;
}
.carouselContainer>ul {
padding: 0;
margin: 0;
list-style: none;
}
.slide {
display: flex;
width: 400px;
height: 500px;
justify-content: center;
align-items: center;
inset: 0;
opacity: 0;
transition-property: opacity;
transition-duration: 200ms;
transition-timing-function: ease-in-out;
transition-delay: 200ms;
border-style: dashed;
border-color: var(--magenta6);
}
.slide[data-active] {
opacity: 1;
z-index: 1;
transition-delay: 0ms;
}
.slideContent {
display: flex;
justify-content: space-between;
align-items: center;
flex-direction: column;
width: 300px;
height: 425px;
border-style: dashed;
border-color: #010043;
}
.slideContent .slideImg {
margin: 0;
width: 200px;
height: 200px;
border-radius: 100px;
z-index: 10px;
}
.slideContent .slideTxt {
border: magenta;
border-style: dashed;
height: 500px;
}
.carousel-button {
position: absolute;
background: none;
border: none;
outline: none;
font-size: 4rem;
top: 50%;
transform: translateY(-50%);
z-index: 2;
color: rgba(255, 255, 255, 0.5);
cursor: pointer;
padding: 0 0.5rem;
border-radius: 0.25rem;
background-color: rgba(0, 0, 0, 0.1);
transition: 0.5s;
}
.carousel-button:hover,
.carousel-button:focus {
background-color: rgba(0, 0, 0, 0.3);
color: #fff;
}
.carousel-button[data-carousel-btn="prev"] {
left: 1rem;
}
.carousel-button[data-carousel-btn="next"] {
right: 1rem;
}
<section class="row4 animateOnScroll" style="margin: 0 100px 100px 100px;">
<h2>don't just take it from us!</h2>
<div class="carouselContainer" data-carousel>
<button class="carousel-button" data-carousel-btn="prev">
❮
</button>
<button class="carousel-button" data-carousel-btn="next">
❯
</button>
<div class="carouselSlides">
<ul data-carousel-slides>
<li class="slide" data-carousel-slide data-active>
<div class="slideContent">
<div>
<img class="slideImg" src="./assets/imgPlaceholder.jpg">
</div>
<div class="slideTxt">
<div class="slideDesc">
<p style="color:black;">hello</p>
</div>
</div>
</div>
</li>
<li class="slide" data-carousel-slide>
<div class="slideContent">
<div>
<img class="slideImg" src="./assets/imgPlaceholder.jpg">
</div>
<div class="slideTxt">
<div class="slideDesc">
<p style="color:black;">hello</p>
</div>
</div>
</div>
</li>
<li class="slide" data-carousel-slide>
<div class="slideContent">
<div>
<img class="slideImg" src="./assets/imgPlaceholder.jpg">
</div>
<div class="slideTxt">
<div class="slideDesc">
<p style="color:black;">hello</p>
</div>
</div>
</div>
</ul>
</div>
</div>
</section>
part of your problem is your ul element is unstyled, its child li elements are going to stack as they normally do on top of each other. giving the ul element display: flex; will put your li's side by side.
If I were you, I would review each nested element of my tree and figure out its purpose, then remove it if not necessary. for example, div.carouselSlides does not seem like its serving any purpose that the ul could not do itself, at least in this small example.
Also, looking at an established project for implementation ideas (or just using it) might be a good idea . https://swiperjs.com/ is very established with powerful config options
Basically there should be 2 containers:
The element that is the parent of the <button>s and the "frame" that holds each slide. In the example it is article.box.
The element that is the parent of each div.slide in the example is section.frame.
Each container should be position: relative and all children of said containers should be position: absolute. Doing so will:
provide precision positioning of the <button>s and section.frame within the perimeters of article.box
allow all div.slide to hide underneath the visible layers (z-index:0+) with z-index: -1 and be visible with .active class at z-index: 1.
The JavaScript is optional, it's just written better but function should be basically the same.
View in full page mode, the image placeholder service does not have dynamic images.
const data = [
{img:"https://placem.at/people?random=1", cap:"People 1"},
{img:"https://placem.at/places?random=1", cap:"Places 2"},
{img:"https://placem.at/things?random=1", cap:"Things 3"}
];
const slides = genSlides(data);
const box = document.querySelector('.box')
const buttons = box.querySelectorAll("button");
buttons.forEach((button) => {
button.addEventListener("click", function(event) {
const offset = button.classList.contains("next") ? 1 : -1;
const active = box.querySelector(".active");
const actIdx = slides.indexOf(active);
const nextIdx = actIdx + offset;
active.classList.remove("active");
if (nextIdx < 0) {
return slides[slides.length + nextIdx].classList.add("active");
}
if (nextIdx >= slides.length) {
return slides[0].classList.add("active");
}
return slides[nextIdx].classList.add("active");
});
});
function genSlides(array) {
const frame = document.querySelector(".frame");
array.forEach(slide => {
frame.insertAdjacentHTML("beforeend", `
<div class="slide">
<figure>
<img src="${slide.img}" width="480">
<figcaption class="cap">${slide.cap}</figcaption>
</figure>
</div>`);
});
const slides = Array.from(frame.querySelectorAll(".slide"));
slides[0].classList.add("active");
return slides;
}
.box {
display: flex;
justify-content: center;
align-items: center;
position: relative;
width: 96vw;
min-height: 96vh;
border: 3px dashed #000;
}
.frame {
display: flex;
flex-flow: column nowrap;
justify-content: center;
align-items: center;
/* The element that is the parent of all .slide should be relative so the
slides, which are absolute positioned, can sit within .frame's perimeter */
position: relative;
}
.slide {
display: flex;
width: 100%;
height: 100%;
justify-content: center;
align-items: center;
/* All slides should be out of normal flow */
position: absolute;
/* All slides should be in the layer "under" the visible layer (z-index: 0+) */
z-index: -1;
opacity: 0;
animation: opacity 0.7s ease-in;
}
.active {
opacity: 1;
z-index: 1;
}
figure {
display: flex;
flex-flow: column nowrap;
justify-content: center;
align-items: center;
max-height: 100%;
margin: 0;
padding: 0;
border-style: 1px dashed #000;
}
img {
object-fit: contain;
}
.cap {
min-width: 100%;
text-align: center;
white-space: pre;
}
button {
display: inline-flex;
justify-content: center;
align-items: center;
position: absolute;
top: 50%;
z-index: 2;
padding: 0 0.5rem;
border: none;
border-radius: 0.25rem;
outline: none;
font-size: 4rem;
color: rgba(255, 255, 255, 0.5);
background: none;
background-color: rgba(0, 0, 0, 0.1);
transform: translateY(-50%);
transition: 0.5s;
cursor: pointer;
}
button:hover,
button:focus {
color: #fff;
background-color: rgba(0, 0, 0, 0.3);
}
button:active {
color: rgba(0, 0, 0, 0.5);
background: none;
}
.prev {
left: 1rem;
}
.next {
right: 1rem;
}
<main>
<h2>Content Title</h2>
<article class="box">
<button class="prev">❮</button>
<button class="next">❯</button>
<section class="frame"></section>
</article>
</main>

Delete button not working after adding another entry to my Library object

I have a problem that my delete button (the yellow one) works perfectly on preloaded book library items, but it isn't on the new entry when I add a book and want to delete it... I also want you to ask what it would be the easiest way to delete books also from myLibrary array... Thanks.
I've attached my code here. Any help will be appreciated. Thanks in advance.
//DOM
const bookForm = document.querySelector(".book-form");
// Calling a form when clicking on add book button
function openNav() {
document.getElementById("myNav").style.height = "100%";
console.log("dsafsa");
}
function closeNav() {
document.getElementById("myNav").style.height = "0%";
}
// where the books will be saved...
let myLibrary = [{
title: "Harry Potter - and the Philosopher's Stone",
author: "J. K. Rowling",
pages: 223,
readStatus: "no",
},
{
title: "The Hobbit",
author: "J.R.R. Tolkien",
pages: 304,
readStatus: "yes",
},
];
// book object
function Book(title, author, pages, readStatus) {
(this.title = title),
(this.author = author),
(this.pages = pages),
(this.readStatus = readStatus);
}
let i = "";
// render the book on page load...
function render() {
const books = myLibrary;
books.forEach((book) => {
addNewBookUI(book);
});
}
render();
document.querySelector(".book-form").addEventListener("submit", (e) => {
// prevent actual submit
e.preventDefault();
// get values
const title = document.querySelector("#title").value;
const author = document.querySelector("#author").value;
const pages = document.querySelector("#pages").value;
const readStatus = document.querySelector('input[name="yes_no"]:checked')
.value;
// prevent empty fields ...
if (title === "" || author === "" || pages === "0") {
alert("Missing data");
} else {
const book = new Book(title, author, pages, readStatus);
myLibrary.push(book);
addNewBookUI(book);
clearFormFields()
}
});
function addNewBookUI(book) {
if (book.readStatus === "yes") {
i = "checked";
} else {
i = "";
}
const main = document.querySelector(".main");
const bookCard = document.createElement("div");
bookCard.classList.add("book-card");
bookCard.innerHTML = `<div class="delete_button"><button class="delete btn"><i class="fa fa-trash">
</i></button></div><div class="title">${book.title}</div><div class="author">${book.author}
</div><div class="pages">${book.pages}</div><div class="read_status">Read: <input type="checkbox" id="yes" name="readstatus" value="yes" ${i}>
</div>`;
main.appendChild(bookCard);
}
// clear form fields after submit
function clearFormFields() {
const myForm = document.getElementById("myForm");
myForm.reset();
}
// Add event listener to all deleteButton
const deleteButton = document.querySelectorAll(".delete");
// deletes book UI;
deleteButton.forEach((el) => {
el.addEventListener("click", function () {
el.parentElement.parentElement.remove()
console.log("sas")
})
})
*,
*::before,
*::after {
box-sizing: border-box;
}
body {
font-family: 'Roboto', sans-serif;
margin: 0;
padding: 0;
}
header {
color: #ffffff;
display: flex;
font-size: 1.4rem;
justify-content: space-between;
align-items: center;
background-color: #155999;
border-bottom: #172f4f solid 10px;
}
.logo {
margin-left: 10px;
}
header button {
background-color: #183153;
border: none;
text-align: left;
font-size: 0.9rem;
border-radius: 5px;
color: #ffffff;
padding: 10px 50px;
margin-right: 10px;
cursor: pointer;
}
.plus-sign {
padding-right: 7px;
}
.main {
position: absolute;
width: 100%;
height: 100%;
background-color: #183153;
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
}
.book-card {
text-align: center;
font-weight: 1000;
display: flex;
flex-direction: column;
justify-content: space-evenly;
width: 250px;
height: 350px;
border-radius: 10px;
background-color: #155999;
margin-left: 20px;
margin-top: 10px;
color: #ffffff;
border: #172f4f solid 8px;
line-height: 30px;
position: relative;
padding-left: 7px;
padding-right: 7px;
box-shadow: 10px 4px 22px -5px rgba(21, 89, 153, 1);
}
.overlay {
height: 0%;
width: 100%;
position: fixed;
z-index: 1;
top: 0;
left: 0;
background-color: rgb(21, 89, 153);
background-color: rgba(21, 89, 153, 0.7);
overflow-y: hidden;
transition: 0.5s;
}
.overlay-content {
position: relative;
top: 25%;
width: 100%;
text-align: center;
margin-top: 30px;
display: flex;
flex-direction: column;
font-size: 30px;
}
.overlay a {
padding: 8px;
text-decoration: none;
font-size: 36px;
color: #ffffff;
display: block;
transition: 0.3s;
}
.overlay a:hover,
.overlay a:focus {
color: #c3c6d1;
}
.overlay .closebtn {
position: absolute;
top: 20px;
right: 45px;
font-size: 60px;
}
#media screen and (max-height: 450px) {
.overlay {
overflow-y: auto;
}
.overlay a {
font-size: 20px
}
.overlay .closebtn {
font-size: 40px;
top: 15px;
right: 35px;
}
}
.book-card div {
margin-top: 15px;
}
/* Style buttons */
.btn {
background-color: #ffd43b;
/* Blue background */
border: none;
/* Remove borders */
color: red;
/* White text */
padding: 12px 16px;
/* Some padding */
font-size: 16px;
/* Set a font size */
cursor: pointer;
/* Mouse pointer on hover */
border-radius: 50%;
position: absolute;
top: -20px;
right: -15px;
}
/* Darker background on mouse-over */
.btn:hover {
background-color: #183153;
}
.delete_button {
top: 0;
right: 0;
}
form div {
margin-top: 15px;
font-family: 'Roboto', sans-serif;
color: white;
font-weight: bold;
font-size: 30px;
margin-bottom: 10px;
}
.radiobutton {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.form-flex {
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
}
.form-flex input {
width: 50%;
border-radius: 5px;
height: 30px;
margin-top: 5px
}
.form-flex input::placeholder {
text-align: center;
}
input[type=submit] {
background-color: #183153;
border: none;
text-align: left;
font-size: 0.9rem;
border-radius: 5px;
color: #ffffff;
padding: 10px 50px;
margin-top: -30px;
cursor: pointer;
}
.radiobutton p {
margin-top: 10px;
margin-bottom: 30px;
}
.flexbuttons {
display: flex;
margin-top: -50px;
margin-bottom: -25px;
}
input[type="text"] {
font-size: 24px;
text-align: center;
}
<!-- The overlay -->
<div id="myNav" class="overlay">
<!-- Button to close the overlay navigation -->
×
<!-- Overlay content -->
<div class="overlay-content">
<form id="myForm" class="book-form">
<div class="form-flex">
<label for="title">Book name:</label>
<input type="text" id="title" name="title" placeholder="Book name...">
</div>
<div class="form-flex">
<label for="author">Book author:</label>
<input type="text" id="author" name="author" placeholder="Book author...">
</div >
<div class="form-flex">
<label for="pages">Pages:</label>
<input type="number" id="pages" placeholder="0" name="pages">
</div>
<div class="radiobutton">
<p>Have you read a book?</p>
<div class="flexbuttons">
<div>
<p><input type="radio" id="huey" name="yes_no" value="yes" checked>
<label for="huey">yes</label>
</p>
</div>
<div>
<p><input type="radio" id="no" name="yes_no" value="no">
<label for="dewey">no</label>
</p>
</div>
</div>
</div>
<div><input type="submit" value="Add Book"></div>
</form>
</div>
</form>
</div>
</div>
</div>
<header>
<div class="logo">
<h1><i class="fa fa-book" aria-hidden="true"></i>
</i>Library
</h1>
</div>
<div class="button">
<button onclick="openNav()" class="add-book">
<i class="fa fa-plus plus-sign"></i>
Add book</button>
</div>
</header>
<div class="main">
</div>
<script src="./index.js" defer></script>
<script src="https://use.fontawesome.com/30a34909cc.js"></script>
You assigned the click event at loading time to all existing buttons with class=="delete". This will naturally not include the ones you might add dynamically at a later stage.
If you want all ".delete" buttons to have the click-event attached to them you need to do a "delegated event attachment" (edited, removes myLibrary element too now):
// Add event listener to all current and future deleteButtons
document.querySelector('.main').onclick=ev=>{
let el= ev.target.classList.contains('fa-trash')? ev.target.parentElement : ev.target.classList.contains('delete') ? ev.target : false;
if (el) {
let card=el.parentElement.parentElement; // book-card DOM element
// remove myLibrary array-element here:
myLibrary.splice( [...card.parentElement.children].indexOf(card) ,1);
console.log(myLibrary)
// remove card DOM element:
card.remove()
}
}
This will bind the click event handler to the .main div and will react only if the clicked element has a class=='fa-trash' or class=='delete'. In the first case it will "move up" one level (assign the parent element, i. e. the button to el), otherwise the clicked element is the button itself. If none of these classes are found, el becomes false and nothing happens. Otherwise the "Grandparent" of el is removed with `el.parentElement.parentElement.remove()' .
And please try and make your MCVE a little smaller next time, as it no fun to handle this amount of code in a small Stackoverflow snippet window! A true MCVE will get you more and faster responses!
Below is a working snippet, check it out:
//DOM
const bookForm = document.querySelector(".book-form");
// Calling a form when clicking on add book button
function openNav() {
document.getElementById("myNav").style.height = "100%";
console.log("dsafsa");
}
function closeNav() {
document.getElementById("myNav").style.height = "0%";
}
// where the books will be saved...
let myLibrary = [
{
title: "Harry Potter - and the Philosopher's Stone",
author: "J. K. Rowling",
pages: 223,
readStatus: "no",
},
{
title: "The Hobbit",
author: "J.R.R. Tolkien",
pages: 304,
readStatus: "yes",
},
];
// book object
function Book(title, author, pages, readStatus) {
(this.title = title),
(this.author = author),
(this.pages = pages),
(this.readStatus = readStatus);
}
let i = "";
// render the book on page load...
function render() {
const books = myLibrary;
books.forEach((book) => {
addNewBookUI(book);
});
}
render();
document.querySelector(".book-form").addEventListener("submit", (e) => {
// prevent actual submit
e.preventDefault();
// get values
const title = document.querySelector("#title").value;
const author = document.querySelector("#author").value;
const pages = document.querySelector("#pages").value;
const readStatus = document.querySelector('input[name="yes_no"]:checked')
.value;
// prevent empty fields ...
if (title === "" || author === "" || pages === "0") {
alert("Missing data");
} else {
const book = new Book(title, author, pages, readStatus);
myLibrary.push(book);
addNewBookUI(book);
clearFormFields()
}
});
function addNewBookUI(book) {
if (book.readStatus === "yes") {
i = "checked";
} else {
i = "";
}
const main = document.querySelector(".main");
const bookCard = document.createElement("div");
bookCard.classList.add("book-card");
bookCard.innerHTML = `<div class="delete_button"><button class="delete btn"><i class="fa fa-trash">
</i></button></div><div class="title">${book.title}</div><div class="author">${book.author}
</div><div class="pages">${book.pages}</div><div class="read_status">Read: <input type="checkbox" id="yes" name="readstatus" value="yes" ${i}>
</div>`;
main.appendChild(bookCard);
}
// clear form fields after submit
function clearFormFields() {
const myForm = document.getElementById("myForm");
myForm.reset();
}
// Add event listener to all deleteButton
document.querySelector('.main').onclick=ev=>{
let el= ev.target.classList.contains('fa-trash')? ev.target.parentElement : ev.target.classList.contains('delete') ? ev.target : false;
if (el) {
let card=el.parentElement.parentElement;
myLibrary.splice( [...card.parentElement.children].indexOf(card) ,1);
console.log(myLibrary)
card.remove()
}
}
*, *::before, *::after {
box-sizing: border-box;
}
body {
font-family: 'Roboto', sans-serif;
margin: 0;
padding: 0;
}
header {
color: #ffffff;
display: flex;
font-size: 1.4rem;
justify-content: space-between;
align-items: center;
background-color:#155999;
border-bottom: #172f4f solid 10px;
}
.logo {
margin-left: 10px;
}
header button {
background-color: #183153;
border: none;
text-align: left;
font-size: 0.9rem;
border-radius: 5px;
color: #ffffff;
padding: 10px 50px;
margin-right: 10px;
cursor: pointer;
}
.plus-sign {
padding-right: 7px;
}
.main {
position: absolute;
width: 100%;
height: 100%;
background-color: #183153;
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
}
.book-card {
text-align: center;
font-weight: 1000;
display: flex;
flex-direction: column;
justify-content: space-evenly;
width: 250px;
height: 350px;
border-radius: 10px;
background-color: #155999;
margin-left: 20px;
margin-top:10px;
color: #ffffff;
border: #172f4f solid 8px;
line-height: 30px;
position: relative;
padding-left: 7px;
padding-right: 7px;
box-shadow: 10px 4px 22px -5px rgba(21,89,153,1);
}
.overlay {
height: 0%;
width: 100%;
position: fixed;
z-index: 1;
top: 0;
left: 0;
background-color: rgb(21,89,153);
background-color: rgba(21,89,153,0.7);
overflow-y: hidden;
transition: 0.5s;
}
.overlay-content {
position: relative;
top: 25%;
width: 100%;
text-align: center;
margin-top: 30px;
display: flex;
flex-direction: column;
font-size: 30px;
}
.overlay a {
padding: 8px;
text-decoration: none;
font-size: 36px;
color: #ffffff;
display: block;
transition: 0.3s;
}
.overlay a:hover, .overlay a:focus {
color: #c3c6d1;
}
.overlay .closebtn {
position: absolute;
top: 20px;
right: 45px;
font-size: 60px;
}
#media screen and (max-height: 450px) {
.overlay {overflow-y: auto;}
.overlay a {font-size: 20px}
.overlay .closebtn {
font-size: 40px;
top: 15px;
right: 35px;
}
}
.book-card div {
margin-top:15px;
}
/* Style buttons */
.btn {
background-color: #ffd43b; /* Blue background */
border: none; /* Remove borders */
color: red; /* White text */
padding: 12px 16px; /* Some padding */
font-size: 16px; /* Set a font size */
cursor: pointer; /* Mouse pointer on hover */
border-radius: 50%;
position:absolute;
top:-20px;
right:-15px;
}
/* Darker background on mouse-over */
.btn:hover {
background-color: #183153;
}
.delete_button {
top:0;
right:0;
}
form div {
margin-top: 15px;
font-family: 'Roboto', sans-serif;
color:white;
font-weight: bold;
font-size: 30px;
margin-bottom: 10px;
}
.radiobutton {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.form-flex {
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
}
.form-flex input {
width: 50%;
border-radius: 5px;
height: 30px;
margin-top: 5px
}
.form-flex input::placeholder {
text-align: center;
}
input[type=submit] {
background-color: #183153;
border: none;
text-align: left;
font-size: 0.9rem;
border-radius: 5px;
color: #ffffff;
padding: 10px 50px;
margin-top: -30px;
cursor: pointer;
}
.radiobutton p {
margin-top:10px;
margin-bottom: 30px;
}
.flexbuttons {
display: flex;
margin-top: -50px;
margin-bottom: -25px;
}
input[type="text"]
{
font-size:24px;
text-align: center;
}
JS:
//DOM
const bookForm = document.querySelector(".book-form");
<!-- The overlay -->
<div id="myNav" class="overlay">
<!-- Button to close the overlay navigation -->
×
<!-- Overlay content -->
<div class="overlay-content">
<form id="myForm" class="book-form">
<div class="form-flex">
<label for="title">Book name:</label>
<input type="text" id="title" name="title" placeholder="Book name...">
</div>
<div class="form-flex">
<label for="author">Book author:</label>
<input type="text" id="author" name="author" placeholder="Book author...">
</div >
<div class="form-flex">
<label for="pages">Pages:</label>
<input type="number" id="pages" placeholder="0" name="pages">
</div>
<div class="radiobutton">
<p>Have you read a book?</p>
<div class="flexbuttons">
<div><p><input type="radio" id="huey" name="yes_no" value="yes" checked>
<label for="huey">yes</label></p>
</div>
<div><p><input type="radio" id="no" name="yes_no" value="no">
<label for="dewey">no</label></p>
</div>
</div>
</div>
<div><input type="submit" value="Add Book"></div>
</form>
</div>
</form>
</div>
</div>
</div>
<header>
<div class="logo">
<h1><i class="fa fa-book" aria-hidden="true"></i>
</i>Library</h1>
</div>
<div class="button">
<button onclick="openNav()" class="add-book">
<i class="fa fa-plus plus-sign"></i>
Add book</button>
</div>
</header>
<div class="main">
</div>
<script src="./index.js" defer></script>
<script src="https://use.fontawesome.com/30a34909cc.js"></script>

Custom menu items are not clickable

I need the menu items to look like they are now (like in iOS), but so far I have two big problems.
First, when I try to click on one of the links, it's not possible because of my linear-gradient. And second, when I click the down arrow to explore other menu items, all the gradient does not work.
How can I make it work properly?
I have also made a codepen for this
document.querySelectorAll('.slide').forEach(function (next) {
next.addEventListener('click', function () {
var container = this.parentElement.querySelector('.select');
sideScroll(container, 'bottom', 20, 25, 15);
});
});
document.querySelectorAll('.slideBack').forEach(function (back) {
back.addEventListener('click', function () {
var container = this.parentElement.querySelector('.select');
sideScroll(container, 'top', 20, 25, 15);
});
});
function sideScroll(element, direction, speed, distance, step) {
scrollAmount = 0;
var slideTimer = setInterval(function () {
if (direction == 'top') {
element.scrollTop -= step;
} else {
element.scrollTop += step;
}
scrollAmount += step;
if (scrollAmount >= distance) {
window.clearInterval(slideTimer);
}
}, speed);
}
* {
background: #80acdc;
}
.larger {
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
.larger .select {
width: 240px;
height: 270px;
display: flex;
flex-direction: column;
text-align: center;
overflow-y: hidden;
-ms-overflow-style: scroll;
scrollbar-width: none;
position: relative;
}
.larger .select::after {
content: '';
position: absolute;
display: block;
width: 100%;
height: 100%;
top: 0;
left: 0;
background-image: linear-gradient(#80acdc, transparent, #80acdc);
}
.larger .select a {
color: white;
margin: 3.5px 0;
}
.larger .select a:first-child {
margin-top: 0;
}
.larger #slide {
position: absolute;
left: 47%;
bottom: 38px;
color: #fff;
font-size: 15px;
cursor: pointer;
}
.larger #slideBack {
position: absolute;
top: 38px;
left: 47%;
color: #fff;
font-size: 15px;
cursor: pointer;
}
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.11.2/css/all.min.css">
<div class="container">
<div class="row">
<div class="col-lg-3">
<div class="larger">
<div class="select">
Action Lorem
Test Text
Action Lorem
Test Text
Action Lorem
Test Text
Action Lorem
Test Text
Action Lorem
Test Text
Action Lorem
Test Text
Action Lorem
Test Text
Action Lorem
Test Text
</div>
<i id="slideBack" class="slideBack fas fa-chevron-up"></i>
<i id="slide" class="slide fas fa-chevron-down"></i>
</div>
</div>
</div>
</div>
For the gradient to allow interaction with the underling elements you can use pointer-events: none
Your gradient is absolute positioned with top: 0 so it goes together with the scroll. In order to fix this you can set the position of the gradient to fixed (but then it will be stretched to the sizes of the vewport). The better way would be to wrap the list of the options with another container so the scroll won't influence the gradient position.. Something like this:
<div class="select-wrap">
<div class="select">
...
</div>
</div>
.larger .select-wrap {
width: 240px;
height: 270px;
}
.larger .select-wrap .select {
height: 100%;
display: flex;
flex-direction: column;
text-align: center;
overflow-y: hidden;
-ms-overflow-style: scroll;
scrollbar-width: none;
position: relative;
}
.larger .select-wrap::after {
content: '';
position: absolute;
display: block;
width: 100%;
height: 100%;
top: 0;
left: 0;
background-image: linear-gradient(#80acdc, transparent, #80acdc);
pointer-events: none; /* this allows for the mouse clicks go through */
}
document.querySelectorAll('.slide').forEach(function(next) {
next.addEventListener('click', function() {
var container = this.parentElement.querySelector('.select');
sideScroll(container, 'bottom', 20, 25, 15);
});
});
document.querySelectorAll('.slideBack').forEach(function(back) {
back.addEventListener('click', function() {
var container = this.parentElement.querySelector('.select');
sideScroll(container, 'top', 20, 25, 15);
});
});
function sideScroll(element, direction, speed, distance, step) {
scrollAmount = 0;
var slideTimer = setInterval(function() {
if (direction == 'top') {
element.scrollTop -= step;
} else {
element.scrollTop += step;
}
scrollAmount += step;
if (scrollAmount >= distance) {
window.clearInterval(slideTimer);
}
}, speed);
}
* {
background: #80acdc;
}
.larger {
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
.larger .select-wrap {
width: 240px;
height: 270px;
}
.larger .select-wrap .select {
height: 100%;
display: flex;
flex-direction: column;
text-align: center;
overflow-y: hidden;
-ms-overflow-style: scroll;
scrollbar-width: none;
position: relative;
}
.larger .select-wrap::after {
content: '';
position: absolute;
display: block;
width: 100%;
height: 100%;
top: 0;
left: 0;
background-image: linear-gradient(#80acdc, transparent, #80acdc);
pointer-events: none;
}
.larger .select a {
color: white;
margin: 3.5px 0;
}
.larger .select a:first-child {
margin-top: 0;
}
.larger #slide {
position: absolute;
left: 47%;
bottom: 38px;
color: #fff;
font-size: 15px;
cursor: pointer;
}
.larger #slideBack {
position: absolute;
top: 38px;
left: 47%;
color: #fff;
font-size: 15px;
cursor: pointer;
}
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.11.2/css/all.min.css">
<div class="container">
<div class="row">
<div class="col-lg-3">
<div class="larger">
<div class="select-wrap">
<div class="select">
Action Lorem
Test Text
Action Lorem
Test Text
Action Lorem
Test Text
Action Lorem
Test Text
Action Lorem
Test Text
Action Lorem
Test Text
Action Lorem
Test Text
Action Lorem
Test Text
</div>
</div>
<i id="slideBack" class="slideBack fas fa-chevron-up"></i>
<i id="slide" class="slide fas fa-chevron-down"></i>
</div>
</div>
</div>
</div>

why does the fancybox slideshow stop?

I've made a carousel-slider here and here
but there is a problem.
Here are 3 levels:
1 carousel
2 card with slideshow
3 popup with photo from the card
2nd and 3rd are done through the fancybox. 3rd is called from the 2nd (on the feed it is visible).
After closing the popup, the slideshow in the card stops (where the description is).
What is the issue here?
$('.gallery_slider').owlCarousel({
loop: true,
nav: false,
dots: true,
autoplay: true,
autoplayTimeout: 5000,
autoplaySpeed: 2000,
autoplayHoverPause:false,
items: 1,
protect: true,
responsive:{
600:{
}
}
});
$('.product-item').fancybox({
baseClass: 'fancybox-gallery',
animationEffect: "fade",
animationDuration: 300,
margin: 0,
gutter: 0,
loop: true,
slideShow: {
autoStart: true,
speed: 1000
},
zoom: false,
idleTime: false,
thumbs: {
autoStart : true,
axis : 'x'
},
touch: {
vertical: false
},
buttons: [
'close'
],
afterLoad : function() {
$('.fancybox-gallery .fancybox-image').fancybox({
baseClass: 'fancy-images',
animationEffect: "fade",
animationDuration: 300,
buttons: [
"close"
],
afterLoad : function(instance, current) {
setTimeout(function() {
instance.close();
}, 2000);
},
afterClose: function() {
$('.product-item').trigger('play.fancybox.autoStart');
},
baseTpl:
'<div class="fancybox-container" role="dialog" tabindex="-1">' +
'<div class="fancybox-bg"></div>' +
'<div class="fancybox-inner">' +
'<div class="modal-close" href="javascript:;" onclick="$.fancybox.close();"><svg viewBox="0 0 40 40"><path d="M10,10 L30,30 M30,10 L10,30"></path></svg></div>'+
'<div class="fancybox-infobar">' +
"<span data-fancybox-index></span> / <span data-fancybox-count></span>" +
"</div>" +
'<div class="fancybox-toolbar">{{buttons}}</div>' +
'<div class="fancybox-navigation">{{arrows}}</div>' +
'<div class="fancybox-stage"></div>' +
'<div class="fancybox-caption"></div>' +
"</div>" +
"</div>"
});
$('.gallery_slider').trigger('stop.owl.autoplay');
},
afterClose: function() {
$('.gallery_slider').trigger('play.owl.autoplay');
},
baseTpl:
'<div class="fancybox-container" role="dialog" tabindex="-1">' +
'<div class="fancybox-bg"></div>' +
'<div class="fancybox-inner">' +
'<div class="fancybox-infobar">' +
"<span data-fancybox-index></span> / <span data-fancybox-count></span>" +
"</div>" +
'<div class="fancybox-toolbar">{{buttons}}</div>' +
'<div class="fancybox-navigation">{{arrows}}</div>' +
'<div class="fancybox-stage"></div>' +
'<div class="fancybox-caption"></div>' +
"</div>" +
"</div>"
});
/* gallery */
#gallery {
width: 100%;
background: url(../img/back3.png);
background-size: cover;
padding: 52px 0 100px;
font-family: "MonlyBold";
margin-bottom: 10px;
position: relative;
}
#gallery .wrap {
display: flex;
justify-content: center;
flex-wrap: wrap;
margin: 0 auto;
}
.gallery_menu {
background: #000;
width: 33%;
height: 150px;
margin: 12px;
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
position: relative;
overflow: hidden;
}
.gallery_menu:after{
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: black;
opacity: 0.5;
z-index: 1;
}
.gallery_menu a {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
color: #e4e4e4;
font-size: 4em;
position: relative;
z-index: 2;
}
.gallery_menu:nth-child(n) {
transition: background-size 1.5s;
}
.gallery_menu:nth-child(n):hover {
background-size: 120%;
}
.gallery_menu:hover:after {
opacity: 0.3;
}
.gallery_menu:nth-child(1) {
background: url(../img/photos/tiffani/27.jpg) center center;
background-size: 100%;
}
.gallery_menu:nth-child(2) {
background: url(../img/photos/fuzing/IMG_9636-21-03-18-07-42.jpeg.jpg) center center;
background-size: 100%;
}
.gallery_menu:nth-child(3) {
background: url(../img/photos/facets/fac.jpg) center center;
background-size: 100%;
}
.gallery_menu:nth-child(4) {
background: url(../img/photos/gravirovka/grav.jpg) center center;
background-size: 100%;
}
.gallery_menu:nth-child(5) {
background: url(../img/photos/mixed/IMG_9715-21-03-18-07-42.jpeg.jpg) center center;
background-size: 100%;
}
.gallery_menu:nth-child(6) {
background: url(../img/photos/psevdo/IMG_0924.JPG) center center;
background-size: 100%;
}
#gallery-1,#gallery-2 {
width: 70%;
height: 500px;
display: none;
}
.gallery_text {
width: 40%;
float: right;
}
.gallery_text p {
color: #000;
}
#gallery .h1 {
margin-bottom: 8px;
}
#gallery .h3{
text-decoration: underline;
margin-top: 20px;
}
.owl-carousel button.owl-dot {
width: 10px;
height: 10px;
border-radius: 20px;
margin: 5px;
border: .5px solid #ddd;
background: #ddd;
}
.owl-carousel button.owl-dot.active {
background: #000;
border: .5px solid #000;
}
/* grid */
/* Style your page (the product list) */
.og-grid {
display: flex;
flex-wrap: wrap;
justify-content: center;
max-width: 1200px;
margin: 0 auto;
}
.product {
margin: 10px;
display: flex;
justify-content: center;
align-items: center;
overflow: hidden;
max-width: 300px;
max-height: 200px;
}
.product .product-images,
.product .product-form {
display: none;
}
.product-item img{
max-width: 100%;
}
/* Reposition and redesign fancyBox blocks */
/* This elements contains both blocks */
.fancybox-gallery .fancybox-inner {
opacity: 0;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
margin: auto;
width: calc(100% - 40px);
height: calc(100% - 40px);
max-width: 900px;
max-height: 400px;
background: #ddd;
}
.fancybox-gallery .fancybox-infobar {
display: none;
}
/* Left block will contain the gallery */
.fancybox-gallery .fancybox-stage {
width: 50%;
}
/* Right block - close button and the form */
.fancybox-gallery .fancybox-caption-wrap {
width: 50%;
height: 100%;
top: 0;
right: 0;
left: auto;
bottom: auto;
background: none;
}
.fancybox-gallery .fancybox-caption {
position: absolute;
/* display: flex; */
border: none;
width: 50%;
right: 0;
top: 0;
}
/* Set position and colors for close button */
.fancybox-gallery .fancybox-button--close {
position: absolute;
top: 0;
right: 0;
background: #F0F0F0;
color: #222;
padding: 7px;
}
.fancybox-gallery .fancybox-button:hover {
color: #111;
background: #e4e4e4;
}
.fancybox-gallery .fancybox-button svg path {
stroke-width: 1;
}
/* Set position of the form */
.fancybox-gallery .fancybox-inner .product-form {
overflow: auto;
position: absolute;
top: 50px;
right: 0;
bottom: 50px;
left: 0;
padding: 0 50px;
text-align: center;
}
.fancybox-gallery .fancybox-caption h3 {
font-weight: 300;
font-size: 52px;
padding: 40px 0 10px;
margin-bottom: 10px;
color: #2c2c2c;
font-family: "MonlyBold";
}
.fancybox-gallery .fancybox-caption p {
font-weight: 400;
font-size: 22px;
line-height: 24px;
color: #6b6b6b;
font-family: "MonlyBold";
}
.fancybox-gallery .fancybox-image, .fancybox-gallery .fancybox-spaceball {
padding: 30px;
max-width: 600px;
max-height: 600px;
display: block!important;
}
/* Tweak fade animation */
.fancybox-gallery .fancybox-inner {
opacity: 1;
transition: opacity .3s;
}
.fancybox-gallery .fancybox-is-open .fancybox-inner {
opacity: 1;
}
.fancybox-gallery .fancybox-is-closing .fancybox-fx-fade {
opacity: 1 !important; /* Prevent double-fading */
}
/* Bullet navigation design */
.fancybox-gallery .fancybox-navigation button {
z-index: 100001;
}
.fancybox-gallery .fancybox-thumbs {
top: 450px;
width: calc(100% - 60px);
max-width: 880px;
bottom: 0;
left: 0;
right : 0;
height: 95px;
padding: 10px 5px 0px 0px;
box-sizing: border-box;
margin: auto;
background: #ddd;
overflow: hidden;
box-shadow: 10px 10px 0 #ddd, -10px -10px #ddd,10px -10px 0 #ddd, -10px 10px #ddd;
}
.fancybox-gallery .fancybox-show-thumbs .fancybox-inner {
right: 0;
bottom: 95px;
}
/* -------------------- */
.fancy-images .fancybox-image,
.fancy-images .fancybox-spaceball {
max-width: 80%;
max-height: 80%;
width: auto;
height: auto;
margin-left: 24%;
bottom: 0;
left: 0;
right : 0;
top: 0;
margin: auto;
}
<div class="gallery_slider owl-carousel">
<ul class="og-grid">
<div class="product">
<a class="product-item" href="https://www.telegraph.co.uk/content/dam/pets/2017/01/06/1-JS117202740-yana-two-face-cat-news_trans_NvBQzQNjv4BqJNqHJA5DVIMqgv_1zKR2kxRY9bnFVTp4QZlQjJfe6H0.jpg?imwidth=450"
data-caption="
<h3>text</h3>
"
data-fancybox="quick-view-2"
data-type="image"
>
<img src="https://www.telegraph.co.uk/content/dam/pets/2017/01/06/1-JS117202740-yana-two-face-cat-news_trans_NvBQzQNjv4BqJNqHJA5DVIMqgv_1zKR2kxRY9bnFVTp4QZlQjJfe6H0.jpg?imwidth=450" />
</a>
</div>
<div class="product">
<a class="product-item" href="https://www.catster.com/wp-content/uploads/2017/11/A-Siamese-cat.jpg"
data-caption="
<h3>text</h3>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Nesciunt libero voluptatem beatae </p>
"
data-fancybox="quick-view-2"
data-type="image"
>
<img src="https://www.catster.com/wp-content/uploads/2017/11/A-Siamese-cat.jpg" />
</a>
</div>
</ul>
<ul class="og-grid">
<div class="product">
<a class="product-item" href="https://www.telegraph.co.uk/content/dam/pets/2017/01/06/1-JS117202740-yana-two-face-cat-news_trans_NvBQzQNjv4BqJNqHJA5DVIMqgv_1zKR2kxRY9bnFVTp4QZlQjJfe6H0.jpg?imwidth=450"
data-caption="
<h3>text</h3>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Nesciunt libero voluptatem beatae</p>
"
data-fancybox="quick-view-2"
data-type="image"
>
<img src="https://www.telegraph.co.uk/content/dam/pets/2017/01/06/1-JS117202740-yana-two-face-cat-news_trans_NvBQzQNjv4BqJNqHJA5DVIMqgv_1zKR2kxRY9bnFVTp4QZlQjJfe6H0.jpg?imwidth=450" />
</a>
</div>
<div class="product">
<a class="product-item" href="https://www.catster.com/wp-content/uploads/2017/11/A-Siamese-cat.jpg"
data-caption="
<h3>text</h3>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Nesciunt libero voluptatem beatae </p>
"
data-fancybox="quick-view-2"
data-type="image"
>
<img src="https://www.catster.com/wp-content/uploads/2017/11/A-Siamese-cat.jpg" />
</a>
</div>
</ul>
<ul class="og-grid">
<div class="product">
<a class="product-item" href="https://www.telegraph.co.uk/content/dam/pets/2017/01/06/1-JS117202740-yana-two-face-cat-news_trans_NvBQzQNjv4BqJNqHJA5DVIMqgv_1zKR2kxRY9bnFVTp4QZlQjJfe6H0.jpg?imwidth=450"
data-caption="
<h3>text</h3>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Nesciunt libero voluptatem beatae</p>
"
data-fancybox="quick-view-2"
data-type="image"
>
<img src="https://www.telegraph.co.uk/content/dam/pets/2017/01/06/1-JS117202740-yana-two-face-cat-news_trans_NvBQzQNjv4BqJNqHJA5DVIMqgv_1zKR2kxRY9bnFVTp4QZlQjJfe6H0.jpg?imwidth=450" />
</a>
</div>
<div class="product">
<a class="product-item" href="https://www.catster.com/wp-content/uploads/2017/11/A-Siamese-cat.jpg"
data-caption="
<h3>text</h3>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Nesciunt libero voluptatem beatae </p>
"
data-fancybox="quick-view-2"
data-type="image"
>
<img src="https://www.catster.com/wp-content/uploads/2017/11/A-Siamese-cat.jpg" />
</a>
</div>
</ul>
</div>
I could not reproduce the issue with the above statement, Which browser are you checking from?
For sliders like owlCarousel, you need to initialise fancybox like this:
$().fancybox({
selector : '.owl-item:not(.cloned) a',
});
Demo - https://codepen.io/fancyapps/pen/mqvOoz
$('.product-item').trigger('play.fancybox.autoStart');
was needed

Categories

Resources