I did timeline by HTML and CSS. I want to do buttons for control timeline steps on JavaScript.
Timeline consists of several steps. Each step has three states:
1) Usually .timeline__step
2) Passed .timeline__step--passed
3) Active .timeline__step--active
I want to do two buttons 'Prev' and 'Next'. I can find nodes by selectors. But I can't understand how to write code that I can toggle step infinitely by arounds.
HTML:
<div class="timeline" id="timeline1">
<div class="timeline__step timeline__step--passed">
<span class="timeline__label">Step 1</span>
</div>
<div class="timeline__step timeline__step--passed">
<span class="timeline__label">Step 2</span>
</div>
<div class="timeline__step timeline__step--active">
<span class="timeline__label">Step 3</span>
</div>
<div class="timeline__step">
<span class="timeline__label">Step 4</span>
</div>
</div>
Timeline full version on codepen:
https://codepen.io/vlad3k-the-sasster/pen/rNNpBMb
To implement the Next button you should do on each button click:
Find the currently active timeline__step--active element, and remove the class from its classList
Find the next sibling element of the active element and add the class timeline__step--active
Always check if you are reaching the first/last step to avoid errors
The Prev button is similar, but in the other way around.
A quick example ( I created an example codepen as well ):
const timeline = document.getElementById('timeline1');
const btnChangeStyle = document.getElementById('toggle-style');
const btnChangeLabelPos = document.getElementById('toggle-label-pos');
const steps = timeline.querySelectorAll('.timeline__step');
function changeStyle() {
timeline.classList.toggle('timeline--points');
}
function changeLabelsPosition() {
timeline.classList.toggle('timeline--labels-underline');
}
btnChangeStyle.addEventListener('click', changeStyle);
btnChangeLabelPos.addEventListener('click', changeLabelsPosition);
document.querySelector('#next').addEventListener('click', () => {
let steps = document.querySelectorAll("#timeline1 > .timeline__step");
let passedSteps = document.querySelectorAll("#timeline1 > .timeline__step--passed");
let firstStep = document.querySelector("#timeline1 > .timeline__step:first-child");
let activeStep = document.querySelector("#timeline1 > .timeline__step--active");
let nextStep;
if(steps.length == passedSteps.length) {
return;
}
if(activeStep) {
activeStep.classList.remove('timeline__step--active');
activeStep.classList.add('timeline__step--passed');
nextStep = activeStep.nextElementSibling
}
if(nextStep) {
nextStep.classList.add('timeline__step--active');
} else if(passedSteps.length === 0) {
firstStep.classList.add('timeline__step--active');
}
});
document.querySelector('#prev').addEventListener('click', () => {
let passedSteps = document.querySelectorAll("#timeline1 > .timeline__step--passed");
let lastStep = document.querySelector("#timeline1 > .timeline__step:last-child");
let activeStep = document.querySelector("#timeline1 > .timeline__step--active");
let prevStep;
if(passedSteps.length === 0) {
return;
}
if(activeStep) {
activeStep.classList.remove('timeline__step--active');
activeStep.classList.remove('timeline__step--passed');
prevStep = activeStep.previousElementSibling;
}
if(prevStep) {
prevStep.classList.add('timeline__step--active');
} else if(passedSteps.length === steps.length) {
lastStep.classList.remove('timeline__step--passed');
lastStep.classList.add('timeline__step--active');
}
});
body {
margin-top: 50px;
}
/* Timeline */
.timeline {
position: relative;
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
height: 30px;
margin-bottom: 50px; /* optional property */
}
.timeline__step {
position: relative;
text-align: center;
flex-grow: 1;
height: 2px;
background-color: lightgrey;
}
.timeline__step::before,
.timeline__step:last-child::after {
content: "";
position: absolute;
top: 50%;
left: 0;
display: block;
height: 11px;
width: 11px;
background-color: #ffffff;
border: 2px solid lightgray;
border-radius: 50%;
box-sizing: border-box;
box-shadow: 0 0 0 2px #fff;
transform: translate(-50%, -50%);
}
.timeline__step:first-child::before {
transform: translate(0%, -50%);
}
.timeline__step:last-child::after {
left: auto;
right: 0;
transform: translate(0%, -50%);
}
.timeline__label {
position: absolute;
left: 50%;
bottom: 10px;
transform: translateX(-50%);
}
.timeline__step--passed,
.timeline__step--passed::before,
.timeline__step--passed:last-child::after {
background-color: green;
border-color: green;
}
.timeline__step--active,
.timeline__step--active::before {
background-color: orange;
border-color: orange;
}
/* Timeline points style (SASS Syntax) */
.timeline--points {
.timeline__step:first-child {
.timeline__label {
transform: translateX(0);
}
}
.timeline__step:last-child {
position: absolute;
right: 0;
width: 100%;
background: none;
&::before {
left: auto;
right: 0;
transform: translate(0, -50%);
}
&::after {
display: none;
}
.timeline__label {
left: auto;
right: 0;
transform: translateX(0);
}
}
.timeline__label {
position: absolute;
left: 0;
transform: translateX(-50%);
}
.timeline__step--active {
background: lightgray;
}
}
/* Timeline label position (SASS Syntax) */
.timeline--labels-underline {
.timeline__label {
bottom: auto;
top: 10px;
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/css/bootstrap.min.css" rel="stylesheet"/>
<title>Document</title>
</head>
<body>
<div class="container">
<div class="timeline" id="timeline1">
<div class="timeline__step timeline__step--passed">
<span class="timeline__label">Step 1</span>
</div>
<div class="timeline__step timeline__step--passed">
<span class="timeline__label">Step 2</span>
</div>
<div class="timeline__step timeline__step--active">
<span class="timeline__label">Step 3</span>
</div>
<div class="timeline__step">
<span class="timeline__label">Step 4</span>
</div>
<div class="timeline__step">
<span class="timeline__label">Step 5</span>
</div>
</div>
<button id="toggle-style" type="button" class="btn btn-outline-primary">Toggle style</button>
<button id="toggle-label-pos" type="button" class="btn btn-outline-primary">Toggle label position</button>
<button id="prev" class="btn btn-primary">< Prev</button>
<button id="next" class="btn btn-primary">Next ></button>
</div>
</body>
</html>
Related
I have an automatic sliding carousel which is working fine except that when it reach the last image then it just freeze on the last image instead of auto slide to the first image. I just can't remake my javascript code alone. Strange but autosliding to the first image was working a few months ago. I had nothing change to the code but seems after last updates of chrome its just not working correctly neither on pc neither on mobile devices. Here is my javascript code:
const carousels = document.querySelectorAll('.img-carousel');
const prevBtn = document.querySelectorAll('.prev');
const nextBtn = document.querySelectorAll('.next');
let carsouselImages = document.querySelectorAll('.img-carousel div');
//Next Carousel
carousels.forEach((carousel, index)=>{
const nextCarousel = () => {
if(carsouselImages[carsouselImages.length - 1]) {
carousel.scrollTo(0, 0);
}
carousel.scrollBy(300, 0);
};
nextBtn[index].addEventListener('click', e => {
nextCarousel();
});
//Prev Carousel
const prevCarousel = () => {
if(carsouselImages[0]) {
carousel.scrollTo(4800,0);
}
carousel.scrollBy(-300, 0);
};
prevBtn[index].addEventListener('click', e => {
prevCarousel();
});
// Auto carousel
const auto = true; // Auto scroll
const intervalTime = 5000;
let sliderInterval;
if (auto) {
sliderInterval = setInterval(nextCarousel, intervalTime);
};
carousel.addEventListener('mouseover', (stopInterval) => {
clearInterval(sliderInterval);
});
carousel.addEventListener('mouseleave', (startInterval) => {
if (auto) {
sliderInterval = setInterval(nextCarousel, intervalTime);
}
});
//for mobile events
carousel.addEventListener('touchstart', (stopIntervalT) => {
clearInterval(sliderInterval);
});
carousel.addEventListener('touchend', (startIntervalT) => {
if (auto) {
sliderInterval = setInterval(nextCarousel, intervalTime);
}
});
//Debounce
var previousCall;
window.addEventListener('resize', () => {
if (previousCall >= 0) {
clearTimeout(previousCall);
}
});
});
Here are css and html codes if needed:
/** img-carousel **/
#imgages-carousel {
display: grid;
align-items: center;
justify-items: center;
padding: 40px 0px;
}
#imgages-carousel1 {
display: grid;
align-items: center;
justify-items: center;
padding: 40px 0px;
}
.img-carousel-container {
width: 800px;
position: relative;
}
.img-carousel {
display: flex;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
scroll-snap-type: x mandatory;
scroll-behavior: smooth;
padding-bottom: 5px;
}
.img-carousel div {
flex: none;
scroll-snap-align: start;
width: 800px;
position: relative;
}
.img-carousel div img {
display: block;
width: 100%;
object-fit: cover;
}
.img-carousel div p {
position: absolute;
top: 0;
right: 10px;
background: rgba(0,0,0,0.5);
color: #fff;
padding: 5px;
border-radius: 10px;
}
.img-carousel-container button {
position: absolute;
top: calc(50% - 15px);
transform: translateY(-50%);
border: none;
background-color: rgba(255, 193, 7, 0.7);
color: #000;
cursor: pointer;
padding: 10px 15px;
border-radius: 50%;
outline: none;
opacity: 0;
transition: all ease-in-out 0.5s;
}
.prev {
left: 10px;
}
.next {
right: 10px;
}
.img-carousel-container:hover button {
opacity: 1;
}
.img-carousel-container button:hover {
background-color: #ffc107;
}
/** custom scrollbar **/
.img-carousel::-webkit-scrollbar {
width: 10px;
height: 10px;
}
.img-carousel::-webkit-scrollbar-thumb {
background: #ffc107;
border-radius: 10px;
}
.img-carousel::-webkit-scrollbar-track {
background: transparent;
}
.img-carousel-container:hover .img-carousel::-webkit-scrollbar-thumb {
visibility: visible;
}
#media screen and (max-width: 800px) {
.img-carousel-container {
width: 100%;
}
.img-carousel div {
width: 100%;
}
}
html:
<!-- section images carousel -->
<section id="imgages-carousel">
<div class="img-carousel-container">
<div class="img-carousel">
<div>
<img src="https://source.unsplash.com/9Nok_iZEgLk/800x450">
<p>1/6</p>
</div>
<div>
<img src="https://source.unsplash.com/4v7ubW7jz1Q/800x450">
<p>2/6</p>
</div>
<div>
<img src="https://source.unsplash.com/rtCujH697DU/800x450">
<p>3/6</p>
</div>
<div>
<img src="https://source.unsplash.com/ELv8fvulR0g/800x450">
<p>4/6</p>
</div>
<div>
<img src="https://source.unsplash.com/LoPGu6By90k/800x450">
<p>5/6</p>
</div>
<div>
<img src="https://source.unsplash.com/Ndz3w6MCeWc/800x450">
<p>6/6</p>
</div>
</div>
<button class="prev"><i class="fas fa-chevron-left fa-2x"></i></button>
<button class="next"><i class="fas fa-chevron-right fa-2x"></i></button>
</div>
</section>
<section id="imgages-carousel1">
<div class="img-carousel-container">
<div class="img-carousel">
<div>
<img src="https://source.unsplash.com/9Nok_iZEgLk/800x450">
<p>1/6</p>
</div>
<div>
<img src="https://source.unsplash.com/4v7ubW7jz1Q/800x450">
<p>2/6</p>
</div>
<div>
<img src="https://source.unsplash.com/rtCujH697DU/800x450">
<p>3/6</p>
</div>
<div>
<img src="https://source.unsplash.com/ELv8fvulR0g/800x450">
<p>4/6</p>
</div>
<div>
<img src="https://source.unsplash.com/LoPGu6By90k/800x450">
<p>5/6</p>
</div>
<div>
<img src="https://source.unsplash.com/Ndz3w6MCeWc/800x450">
<p>6/6</p>
</div>
</div>
<button class="prev"><i class="fas fa-chevron-left fa-2x "></i></button>
<button class="next"><i class="fas fa-chevron-right fa-2x "></i></button>
</div>
</section>
I have 2 collapsible nested inside each other
When clicking on Test 7, it closes both the BRAND and test 7 accordions
I have this JavaScript code where "mobile-nav_accordion-contentbox" is the className of the parent element (BRAND)
const mobile_navbar_accordion = document.getElementsByClassName("mobile-nav_accordion-contentbox");
for (let i = 0; i < mobile_navbar_accordion.length; i++) {
let checkbox = mobile_navbar_accordion[i];
checkbox.addEventListener("click", (e) => {
e.currentTarget.classList.toggle("active");
})
}
Solutions I tried:
Adding e.stopPropagation(); inside the click event
Replacing e.currentTarget with e.target but the click event is never working on the parent element, I tested this with the following code
if (e.target == e.currentTarget) console.log("clicked on parent");
else console.log("clicked on children")
I also tried
if(e.target == this) console.log("clicked on parent")
else console.log("clicked on children")
In both cases it returned "clicked on children"
I replaced e.currentTarget with this
this.classList.toggle('..')
And in the console I received this error
pointer-events: none;
In css for the children box, also for children title + content separately but it caused 2 issues, first stopping (Test 5, Test 6) from firing the link event. However it still didn't stop closing the parent when clicking on children box or children elements
const mobile_navbar_accordion = document.getElementsByClassName("mobile-nav_accordion-contentbox");
const mobile_navbar_accordion_grandchildren = document.getElementsByClassName("mobile-nav_accordion-contentbox__grandchildren");
for (let i = 0; i < mobile_navbar_accordion.length; i++) {
let checkbox = mobile_navbar_accordion[i];
checkbox.addEventListener("click", (e) =>
e.currentTarget.classList.toggle("active")
)
}
for (let i = 0; i < mobile_navbar_accordion_grandchildren.length; i++) {
let checkbox = mobile_navbar_accordion_grandchildren[i];
checkbox.addEventListener("click", (e) =>
e.currentTarget.classList.toggle("active")
)
}
ul{
list-style: none;
}
a{
color: black;
text-decoration: none;
padding: 10px 0;
}
.mobile-nav_accordion,
.mobile-nav_accordion__grandchildren{
width: 600px;
}
.mobile-nav_accordion .mobile-nav_accordion-contentbox,
.mobile-nav_box {
position: relative;
margin-bottom: 1.5rem;
width: 100%;
}
.mobile-nav_accordion-contentbox__grandchildren {
position: relative;
width: 100%;
}
.mobile-nav_accordion .mobile-nav_accordion-contentbox .mobile-nav_accordion-contentbox-label,
.mobile-nav_accordion__grandchildren .mobile-nav_accordion-contentbox__grandchildren .mobile-nav_accordion-contentbox-label__grandchildren{
position: relative;
width: 100%;
padding: 20px 0;
}
/* For + sign after each collapsible title */
.mobile-nav_accordion .mobile-nav_accordion-contentbox .mobile-nav_accordion-contentbox-label::before,
.mobile-nav_accordion__grandchildren .mobile-nav_accordion-contentbox__grandchildren .mobile-nav_accordion-contentbox-label__grandchildren::before
{
content: "+";
position: absolute;
right: 0;
top: 50%;
transform: translateY(-50%);
font-size: 18px;
}
.mobile-nav_accordion .mobile-nav_accordion-contentbox.active .mobile-nav_accordion-contentbox-label::before,
.mobile-nav_accordion__grandchildren .mobile-nav_accordion-contentbox__grandchildren.active .mobile-nav_accordion-contentbox-label__grandchildren::before
{
content: "-";
}
.mobile-nav_accordion .mobile-nav_accordion-contentbox .mobile-nav_accordion-contentbox-content,
.mobile-nav_accordion__grandchildren .mobile-nav_accordion-contentbox__grandchildren .mobile-nav_accordion-contentbox-content__grandchildren
{
position: relative;
height: 0;
overflow: hidden;
padding: 0 0.5rem;
transition-property: all;
transition-duration: 0.1s !important;
transition-timing-function: linear;
}
.mobile-nav_accordion-contentbox-content__grandchildren{
padding-left: 1rem;
}
.mobile-nav_accordion .mobile-nav_accordion-contentbox.active .mobile-nav_accordion-contentbox-content,
.mobile-nav_accordion__grandchildren .mobile-nav_accordion-contentbox__grandchildren.active .mobile-nav_accordion-contentbox-content__grandchildren{
height: max-content;
padding: 0.5rem;
}
.mobile-nav__links,
.mobile-nav_accordion-contentbox-label__grandchildren h5{
font-size: 13px;
margin-top: 1rem;
color: #3c3c3c;
}
<div class="mobile-nav_accordion">
<div class="mobile-nav_accordion-contentbox">
<label class="mobile-nav_accordion-contentbox-label">
BRAND
</label>
<div class="mobile-nav_accordion-contentbox-content">
<ul class="navigation-item-children--top-level">
<li>
<a class="mobile-nav__links" href="#">
<span>
Hello World 1
</span>
</a>
<!-- HERE GOES THE GRANDCHILDS -->
<div class="mobile-nav_accordion__grandchildren">
<div class="mobile-nav_accordion-contentbox__grandchildren">
<label class="mobile-nav_accordion-contentbox-label__grandchildren">
Test 1
</label>
<div class="mobile-nav_accordion-contentbox-content__grandchildren">
<ul>
<li>
<a class="mobile-nav__links" href="#">
Hello world
</a>
</li>
</ul>
</div>
</div>
</div>
</li>
</ul>
</div>
</div>
</div>
I think you can basically change your script to the provided version below.
const mobile_navbar_accordion = document.getElementsByClassName("mobile-nav_accordion-contentbox-label");
const mobile_navbar_accordion_grandchildren = document.getElementsByClassName("mobile-nav_accordion-contentbox-label__grandchildren");
for (let i = 0; i < mobile_navbar_accordion.length; i++) {
let checkbox = mobile_navbar_accordion[i];
checkbox.addEventListener("click", function(e){
// getting the parent element to add active
e.currentTarget.closest('.mobile-nav_accordion-contentbox').classList.toggle("active")
})
}
for (let i = 0; i < mobile_navbar_accordion_grandchildren.length; i++) {
let checkbox = mobile_navbar_accordion_grandchildren[i];
checkbox.addEventListener("click", function(e){
e.stopPropagation();
// getting the parent element to add active
e.currentTarget.closest('.mobile-nav_accordion-contentbox__grandchildren').classList.toggle("active")
} )
}
ul{
list-style: none;
}
a{
color: black;
text-decoration: none;
padding: 10px 0;
}
.mobile-nav_accordion,
.mobile-nav_accordion__grandchildren{
width: 600px;
}
.mobile-nav_accordion .mobile-nav_accordion-contentbox,
.mobile-nav_box {
position: relative;
margin-bottom: 1.5rem;
width: 100%;
}
.mobile-nav_accordion-contentbox__grandchildren {
position: relative;
width: 100%;
}
.mobile-nav_accordion .mobile-nav_accordion-contentbox .mobile-nav_accordion-contentbox-label,
.mobile-nav_accordion__grandchildren .mobile-nav_accordion-contentbox__grandchildren .mobile-nav_accordion-contentbox-label__grandchildren{
position: relative;
width: 100%;
padding: 20px 0;
}
/* For + sign after each collapsible title */
.mobile-nav_accordion .mobile-nav_accordion-contentbox .mobile-nav_accordion-contentbox-label::before,
.mobile-nav_accordion__grandchildren .mobile-nav_accordion-contentbox__grandchildren .mobile-nav_accordion-contentbox-label__grandchildren::before
{
content: "+";
position: absolute;
right: 0;
top: 50%;
transform: translateY(-50%);
font-size: 18px;
}
.mobile-nav_accordion .mobile-nav_accordion-contentbox.active .mobile-nav_accordion-contentbox-label::before,
.mobile-nav_accordion__grandchildren .mobile-nav_accordion-contentbox__grandchildren.active .mobile-nav_accordion-contentbox-label__grandchildren::before
{
content: "-";
}
.mobile-nav_accordion .mobile-nav_accordion-contentbox .mobile-nav_accordion-contentbox-content,
.mobile-nav_accordion__grandchildren .mobile-nav_accordion-contentbox__grandchildren .mobile-nav_accordion-contentbox-content__grandchildren
{
position: relative;
height: 0;
overflow: hidden;
padding: 0 0.5rem;
transition-property: all;
transition-duration: 0.1s !important;
transition-timing-function: linear;
}
.mobile-nav_accordion-contentbox-content__grandchildren{
padding-left: 1rem;
}
.mobile-nav_accordion .mobile-nav_accordion-contentbox.active .mobile-nav_accordion-contentbox-content,
.mobile-nav_accordion__grandchildren .mobile-nav_accordion-contentbox__grandchildren.active .mobile-nav_accordion-contentbox-content__grandchildren{
height: max-content;
padding: 0.5rem;
}
.mobile-nav__links,
.mobile-nav_accordion-contentbox-label__grandchildren h5{
font-size: 13px;
margin-top: 1rem;
color: #3c3c3c;
}
<div class="mobile-nav_accordion">
<div class="mobile-nav_accordion-contentbox">
<label class="mobile-nav_accordion-contentbox-label">
BRAND
</label>
<div class="mobile-nav_accordion-contentbox-content">
<ul class="navigation-item-children--top-level">
<li>
<a class="mobile-nav__links" href="#">
<span>
Hello World 1
</span>
</a>
<!-- HERE GOES THE GRANDCHILDS -->
<div class="mobile-nav_accordion__grandchildren">
<div class="mobile-nav_accordion-contentbox__grandchildren">
<label class="mobile-nav_accordion-contentbox-label__grandchildren">
Test 1
</label>
<div class="mobile-nav_accordion-contentbox-content__grandchildren">
<ul>
<li>
<a class="mobile-nav__links" href="#">
Hello world
</a>
</li>
</ul>
</div>
</div>
</div>
</li>
</ul>
</div>
</div>
</div>
So i don't have a clue how to work this out.
I want to have it work like so: If you click on one paw the modal opens and if you click on the second paw the modal of paw 1 closes. What do i have to add to the script to make it work? Right now the modal opens in th ebackground of the curretn active modal.
<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">
<title>Document</title>
<style type="text/css">
.infobox {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) scale(0);
transition: 200ms ease-in-out;
z-index: 200;
background-color: #D0D0CE;
width: 500px;
max-width: 80%;
}
.infobox.active {
transform: translate(-50%, -50%) scale(1);
}
#overlay {
position: fixed;
opacity: 0;
transition: 200ms ease-in-out;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, .7);
pointer-events: none;
}
#overlay.active {
opacity: 1;
pointer-events: all;
}
.title {
padding: 0 10px 0 0;
display: flex;
justify-content: space-between;
align-items: center;
}
.close-button {
cursor: pointer;
border: none;
outline: none;
background: none;
font-size: 1.25rem;
font-weight: bold;
}
.infoheadline {
text-transform: uppercase;
font-family: 'Roboto Condensed', sans-serif;
padding-left: 5px;
}
.infotext {
padding: 10px 15px;
font-family: 'Roboto', sans-serif;
}
.linesmall {
width: 20%;
height: 5px;
margin-left: 10px;
background-color: #FABB00;
}
.paw {
width: 42px;
height: 42px;
padding: 16px;
z-index: 1;
filter: drop-shadow(0px 0px 5px #ffffff);
}
</style>
</head>
<body>
<!--Pfote 1 Start-->
<div class="item one">
<div id="overlay"></div>
<input type="image" data-modal-target="#info1" src="https://media.visioneleven.com/JW/116_Nachhaltigkeit_Wiesen/image_assets/paw.png" alt="Pfote" class="paw">
<div id="info1" class="infobox eins">
<div class="title">
<h3 class="infoheadline">3.500 mal tierischer</h3>
<button data-close-button class="close-button">×</button>
</div>
<div class="linesmall"></div>
<p class="infotext">Wiesen bieten Lebensraum für rund 3.500 Tierarten – z. B. Vögel, Käfer, Spinnen, Heuschrecken, Schmetterlinge, Bienen, Hummeln ...</p>
</div>
</div>
<!--Pfote 1 Ende-->
<!--Pfote 2 Start-->
<div class="item two">
<div id="overlay"></div>
<input type="image" data-modal-target="#info2" src="https://media.visioneleven.com/JW/116_Nachhaltigkeit_Wiesen/image_assets/paw.png" alt="Pfote" class="paw">
<div id="info2" class="infobox zwei">
<div class="title">
<h3 class="infoheadline">588 Mrd. mal klimafreundlicher</h3>
<button data-close-button class="close-button">×</button>
</div>
<div class="linesmall"></div>
<p class="infotext">Allein in Deutschland speichern Wiesen ca. 588 Milliarden Tonnen CO<sub>2</sub> – und entziehen sie damit der Atmosphäre. (Zum Vergleich: Unsere Wälder speichern ca. 372 Mrd. t).</p>
</div>
</div>
<!--Pfote 2 Ende-->
<script type="text/javascript">
//Start Modal One
const openModalButtonOne = document.querySelectorAll('[data-modal-target]')
const closeModalButtonOne = document.querySelectorAll('[data-close-button]')
const overlayOne = document.getElementById('overlay')
openModalButtonOne.forEach(button => {
button.addEventListener('click', () => {
const info1 = document.querySelector(button.dataset.modalTarget)
openModal(info1)
})
})
overlayOne.addEventListener('click', () => {
const info1 = document.querySelectorAll('.infobox.active')
info1.forEach(info1 => {
closeModal(info1)
})
})
closeModalButtonOne.forEach(button => {
button.addEventListener('click', () => {
const info1 = button.closest('.infobox')
closeModal(info1)
})
})
function openModal(info1) {
if (info1 == null) return
info1.classList.add('active')
overlayOne.classList.add('active')
}
function closeModal(info1) {
if (info1 == null) return
info1.classList.remove('active')
overlayOne.classList.remove('active')
}
//Start Modal Two
const openModalButtonTwo = document.querySelectorAll('[data-modal-target]')
const closeModalButtonTwo = document.querySelectorAll('[data-close-button]')
const overlayTwo = document.getElementById('overlay')
openModalButtonTwo.forEach(button => {
button.addEventListener('click', () => {
const info2 = document.querySelector(button.dataset.modalTarget)
openModal(info2)
})
})
overlayTwo.addEventListener('click', () => {
const info2 = document.querySelectorAll('.infobox.active')
info2.forEach(info2 => {
closeModal(info2)
})
})
closeModalButtonTwo.forEach(button => {
button.addEventListener('click', () => {
const info2 = button.closest('.infobox')
closeModal(info2)
})
})
function openModal(info2) {
if (info2 == null) return
info2.classList.add('active')
overlayTwo.classList.add('active')
}
function closeModal(info2) {
if (info2 == null) return
info2.classList.remove('active')
overlayTwo.classList.remove('active')
}
</script>
</body>
</html>```
I think you tried to overcomplicate the stuff. Here's a modified version of your code that behaves as expected:
<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" />
<title>Document</title>
<style type="text/css">
.infobox {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) scale(0);
transition: 200ms ease-in-out;
z-index: 200;
background-color: #d0d0ce;
width: 500px;
max-width: 80%;
}
.infobox.active {
transform: translate(-50%, -50%) scale(1);
}
#overlay {
position: fixed;
opacity: 0;
transition: 200ms ease-in-out;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.7);
pointer-events: none;
}
#overlay.active {
opacity: 1;
pointer-events: all;
}
.title {
padding: 0 10px 0 0;
display: flex;
justify-content: space-between;
align-items: center;
}
.close-button {
cursor: pointer;
border: none;
outline: none;
background: none;
font-size: 1.25rem;
font-weight: bold;
}
.infoheadline {
text-transform: uppercase;
font-family: "Roboto Condensed", sans-serif;
padding-left: 5px;
}
.infotext {
padding: 10px 15px;
font-family: "Roboto", sans-serif;
}
.linesmall {
width: 20%;
height: 5px;
margin-left: 10px;
background-color: #fabb00;
}
.paw {
width: 42px;
height: 42px;
padding: 16px;
z-index: 1;
filter: drop-shadow(0px 0px 5px #ffffff);
}
</style>
</head>
<body>
<div id="overlay"></div>
<!--Pfote 1 Start-->
<div class="item one">
<input
type="image"
data-modal-target="#info1"
src="https://media.visioneleven.com/JW/116_Nachhaltigkeit_Wiesen/image_assets/paw.png"
alt="Pfote"
class="paw"
/>
<div id="info1" class="infobox eins">
<div class="title">
<h3 class="infoheadline">3.500 mal tierischer</h3>
<button data-close-button class="close-button">×</button>
</div>
<div class="linesmall"></div>
<p class="infotext">
Wiesen bieten Lebensraum für rund 3.500 Tierarten – z. B. Vögel,
Käfer, Spinnen, Heuschrecken, Schmetterlinge, Bienen, Hummeln ...
</p>
</div>
</div>
<!--Pfote 1 Ende-->
<!--Pfote 2 Start-->
<div class="item two">
<input
type="image"
data-modal-target="#info2"
src="https://media.visioneleven.com/JW/116_Nachhaltigkeit_Wiesen/image_assets/paw.png"
alt="Pfote"
class="paw"
/>
<div id="info2" class="infobox zwei">
<div class="title">
<h3 class="infoheadline">588 Mrd. mal klimafreundlicher</h3>
<button data-close-button class="close-button">×</button>
</div>
<div class="linesmall"></div>
<p class="infotext">
Allein in Deutschland speichern Wiesen ca. 588 Milliarden Tonnen
CO<sub>2</sub> – und entziehen sie damit der Atmosphäre. (Zum
Vergleich: Unsere Wälder speichern ca. 372 Mrd. t).
</p>
</div>
</div>
<!--Pfote 2 Ende-->
<script type="text/javascript">
//Start Modal One
const openModalButtons = document.querySelectorAll("[data-modal-target]");
const closeModalButtons = document.querySelectorAll(
"[data-close-button]"
);
const overlay = document.querySelector("#overlay");
const closeActiveModals = () => {
const info = document.querySelectorAll(".infobox.active");
info.forEach((info) => {
closeModal(info);
});
};
openModalButtons.forEach((button) => {
button.addEventListener("click", () => {
closeActiveModals();
const info = document.querySelector(button.dataset.modalTarget);
openModal(info);
});
});
overlay.addEventListener("click", closeActiveModals);
closeModalButtons.forEach((button) => {
button.addEventListener("click", () => {
const info = button.closest(".infobox");
closeModal(info);
});
});
function openModal(info) {
if (info == null) return;
info.classList.add("active");
overlay.classList.add("active");
}
function closeModal(info) {
if (info == null) return;
info.classList.remove("active");
overlay.classList.remove("active");
}
</script>
</body>
</html>
Note that you don't need to add event listeners twice as you're querying the DOM with querySelectorAll and then iterating through them to add event listeners. Also, for the same exact reason, you don't need to add all of the functions such as openModal twice neither.
Just don't try to make it complicated. It's very simple.
easy solution handle the click event on overlay, and stop click event propagation from the modal itself
I am only attempting to do a simple modal, and nothing is working right accept the HTML and CSS,
Javascript acts like it is not connected to the HTML sheet at all.
It has a button that i am supposed to click and the event handler should make the popup open but instead, the popup shows up immediately after the page loads, which is totally contrary to my script. Here is the code:
const pop = document.getElementById('pop')
const x = document.getElementById('x')
const overlay = document.getElementById('overlay')
const modal = document.getElementById('modal')
const open = function() {
modal.classList.remove('hidden');
overlay.classList.remove('hidden');
}
const close = function() {
modal.classList.add('hidden');
overlay.classList.add('hidden');
}
pop.addEventListener('click', open, false);
x.addEventListener('click', close, false);
overlay.addEventListener('click', close, false);
.pop {
padding: 10px 15px;
background: #4e8b8f;
border: none;
border-radius: 1.2px;
font-family: Impact;
color: black;
margin-top: 10px;
cursor: pointer;
}
.modal {
background-color: #4e8b8f;
border-radius: 1.3px;
padding: 1rem;
width: 15rem;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 6;
font-family: Impact;
}
.x {
position: absolute;
top: 0;
right: 0;
background-color: transparent;
border: none;
border-radius: 1px;
color: red;
font-size: 10px;
cursor: pointer;
}
.overlay {
position: absolute;
top: 0;
left: 0;
background-color: rgba(0, 0, 0, 0.7);
backdrop-filter: blur(3px);
border-radius: 2px;
height: 100%;
width: 100%;
z-index: 5;
}
.hidden {
display: none;
}
<!DOCTYPE html>
<html>
<!-----tab header---------------->
<head>
<title>Jalloh Web Construction Home</title>
<link href=Afri-culture.css rel="stylesheet">
<script src="Afri-culture.js"></script>
<link rel="shortcut icon" type="image/jpg" href="jalloh white.jpg">
<meta charset="utf-8" />
</head>
<header name="container">
<!-----nav bar------>
<div class="container">
<img id="clarkweb" src="jalloh.jpg" alt="jalloh web construction">
<nav>
<ul>
<!----- <li>Home</li>----->
<li>About Me</li>
<li>My Hobbies</li>
<li>Contact Me</li>
</ul>
</nav>
</div>
</header>
<h1>Welcome To My Portfolio</h1>
<button class="pop" id="pop">Enter</button>
<div class="modal hidden">
<br>
<button class="x" id="x">x</button>
<img src="smokegif.gif" id="smoke">
<h3>Under Construction</h3>
</div>
<div class="overlay hidden"></div>
<body id=body>
<br>
</body>
</div>
</div>
</div>
<hr>
<div class="container2">
<footer>
<img id="clarktwo" src="jalloh white.jpg" alt="clark web">
</footer>
</div>
</html>
You use document.getElementById('modal'):
const pop = document.getElementById('pop')
...
const modal = document.getElementById('modal')
const open = function() {
modal.classList.remove('hidden');
overlay.classList.remove('hidden');
}
...
pop.addEventListener('click', open, false);
But you don't have id="modal" inside set for it:
<div class="modal hidden">
#rock {
display: none;
position: relative;
left: 49.4%
}
#paper {
display: none;
position: relative;
left: 49%;
bottom: 81px;
}
#scissors {
display: none;
position: relative;
left: 48.14%;
bottom: 162px;
}
#shoot {
display: none;
position: relative;
left: 48.7%;
bottom: 243px;
}
I'm trying to get these h2 elements to fade in then out one after the other after the click of one of three buttons, but my JQuery isn't working for the fade in portion (I'm trying to take this in pieces since I'm new to JavaScript and JQuery). Here's my script:
$(document).ready(function(){
$("button").click(function(){
$("#rock").fadeIn();
$("#paper").fadeIn();
$("#scissors").fadeIn("slow");
$("#shoot").fadeIn(3000);
});
});
<div class="selections">
<button class="selection" data-selection="rock">🗻</button>
<button class="selection" data-selection="paper">📜</button>
<button class="selection" data-selection="scissors">✂</button>
</div>
<h2 class="chant" id="rock">Rock</h2>
<h2 class="chant" id="paper">Paper</h2>
<h2 class="chant" id=scissors>Scissors</h2>
<h2 class="chant" id="shoot">Shoot!</h2>
`
To accomplish your initial goal, everything is fine except: You need to hide your h2's initially, which you can do with the hidden attribute.
I'll probably get in trouble for this, but I thought I would show one way to complete this game. The code is commented below.
If you want to only reveal the associate button h2, access the data() of that element
$(document).ready(function() {
let choices = ['rock', 'paper', 'scissors']; // our choices
$("button").click(function() {
$('.chant').hide(); // hide all h2s for the round
$("#" + $(this).data("selection")).fadeIn(); // my selection - $(this).data("selection") grabs the data-selection attribute of the button ( $(this) ) which was clicked
let computer = choices[Math.floor(Math.random() * 3)]; // a random computer choice
$("#computer").html(computer.toUpperCase()).fadeIn("slow"); // new element #computer takes random value as html and fades in
// our chooser logic - we compare the index positions of the 2 choices
let msg, diff = choices.indexOf($(this).data("selection")) - choices.indexOf(computer);
if (diff === 0) msg = "Its a Tie";
else if (diff > 0 || diff === -2) msg = "You Won!";
else msg = "Shoot!";
$("#shoot").html(msg).fadeIn(3000);
// $("#paper").fadeIn();
// $("#scissors").fadeIn("slow");
// $("#shoot").fadeIn(3000);
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="selections">
<button class="selection" data-selection="rock">🗻</button>
<button class="selection" data-selection="paper">📜</button>
<button class="selection" data-selection="scissors">✂</button>
</div>
<h2 class="chant" hidden id="rock">Rock</h2>
<h2 class="chant" hidden id="paper">Paper</h2>
<h2 class="chant" hidden id="scissors">Scissors</h2>
<h2 class="chant" hidden id="computer"></h2>
<h2 class="chant" hidden id="shoot">Shoot!</h2>
You don't need to start them display:none. Instead you could just start them without text and then .hide() them and set the .text() right before they .fadeIn().
I kind of went with the other answer and assumed you're trying to make a game. Didn't realize you can make hours of fun in so few lines of code.
$('.selections button').click(function() {
let player = this.getAttribute('data-selection'),
ai = ['rock', 'paper', 'scissors'][Math.round(Math.random() * 2)],
outcome = player === ai ? 'TIE' :
((player === 'rock' && ai === 'scissors') ||
(player === 'paper' && ai === 'rock') ||
(player === 'scissors' && ai === 'paper')) ? 'WIN' :
'LOST';
$('.chant').hide();
$('.chant.player').text(player).fadeIn();
$('.chant.ai').text(ai).fadeIn('slow');
$('.chant.outcome').text(outcome).fadeIn(3000);
});
<div class="selections">
<button data-selection="rock">🗻</button>
<button data-selection="paper">📜</button>
<button data-selection="scissors">✂</button>
</div>
<h2 class="chant player"></h2>
<h2 class="chant ai"></h2>
<h2 class="chant outcome"></h2>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Or if you want to make absolutely sure that they fade in in sequence, .fadeIn() allows for an on complete callback, so you could nest them:
$('.chant.player').text(player).fadeIn(function() {
$('.chant.ai').text(ai).fadeIn('slow', function() {
$('.chant.outcome').text(outcome).fadeIn(3000);
});
});
I went with the document.ready function and used the .fadeIn .fadeOut effects. I hid each h2 element individually in my html and came to this solution. The only issue I'm having now is the screen expands and moves some elements when the script is ran.
//Displays the chant 'Rock Paper Scissors Shoot!' after one of the buttons is clicked
$(document).ready(function(){
$('button').click(function(){
$('#rock').fadeIn(500).delay(1000).fadeOut(500);
$('#paper').delay(2000).fadeIn(500).delay(1000).fadeOut(500);
$('#scissors').delay(4000).fadeIn(500).delay(1000).fadeOut(500);
$('#shoot').delay(6000).fadeIn(500);
});
});
#import
url('https://fonts.googleapis.com/css2?family=Big+Shoulders+Stencil+Display:wght#100&display=swap');
*{
font-family: "Big Shoulders Stencil Display", sans-serif;
}
body {
background-size: contain;
background-color: #A80289;
}
.game {
margin: 40px 0 0 0;
font-size: 55px;
text-align: center;
letter-spacing: 3px;
}
.selections {
display: flex;
justify-content: center;
margin: 20px 0 0 0;
}
button {
padding: 0 20px 0 20px;
}
.selection {
background: none;
border: none;
font-size: 50px;
cursor: pointer;
transition: 100ms;
}
.selection:hover {
transform: scale(1.2);
}
.chant {
border: none;
font-size: 40px;
font-weight: bold;
letter-spacing: 3px;
}
#rock {
position: relative;
left: 49.4%
}
#paper {
position: relative;
left: 49%;
}
#scissors {
position: relative;
left: 48.14%;
}
#shoot {
position: relative;
left: 48.7%;
}
.winner {
margin: 1rem;
display: grid;
justify-content: center;
grid-template-columns: repeat(2, .2fr);
justify-items: center;
align-items: center;
position: relative;
top: 100px;
font-size: 25px;
letter-spacing: 2px;
font-weight: bold;
}
.winner-score {
margin: 0 0 0 8px;
font-size: 75%;
}
.result-selection {
opacity: .5;
font-size: 20px;
}
.result-selection.winner {
opacity: 1;
font-size: 30px;
position: relative;
top: 0;
}
/*Media Queries*/
/*Tablets and smaller*/
#media(max-width: 768px) {
.game {
margin: 40px 0 0 0;
font-size: 45px;
text-align: center;
letter-spacing: 3px;
}
.selection {
font-size: 40px;
}
.chant {
font-size: 40px;
letter-spacing: 3px;
}
#rock {
position: relative;
left: 48%
}
#paper {
position: relative;
left: 47.62%;
}
#scissors {
position: relative;
left: 45.7%;
}
#shoot {
position: relative;
left: 46.5%;
}
.winner {
font-size: 24px;
}
}
/*Mobile*/
#media(max-width: 500px) {
.game {
margin: 40px 0 0 0;
font-size: 40px;
text-align: center;
letter-spacing: 3px;
}
.selection {
font-size: 35px;
}
.chant {
font-size: 40px;
letter-spacing: 3px;
}
#rock {
position: relative;
left: 47.26%
}
#paper {
position: relative;
left: 46.27%;
}
#scissors {
position: relative;
left: 43.19%;
}
#shoot {
position: relative;
left: 45%;
}
.winner {
font-size: 22px;
}
}
<!DOCTYPE html>
<html lang="en" {IF CLASSES}class="classes"{/IF}>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script type="text/javascript" src="myscript.js"></script>
<link rel="stylesheet" type="text/css" href="css/style.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css" integrity="sha512-iBBXm8fW90+nuLcSKlbmrPcLa0OT92xO1BIsZ+ywDWZCvqsWgccV3gFoRBv0z+8dLJgyAHIhR35VZc2oM/gI1w==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<link rel="preconnect" href="https://fonts.gstatic.com">
<title>Rock Paper Scissors</title>
<meta charset="UTF-8">
<meta name="viewpoint" content="width=device-width, initial-scale=1.0">
</head>
<body>
<div class="game">
<h1>Rock Paper Scissors</h1>
</div>
<div class="selections">
<button class="selection" data-selection="rock">🗻</button>
<button class="selection" data-selection="paper">📜</button>
<button class="selection" data-selection="scissors">✂</button>
</div>
<h2 class="chant" hidden id="rock">Rock</h2>
<h2 class="chant" hidden id="paper">Paper</h2>
<h2 class="chant" hidden id=scissors>Scissors</h2>
<h2 class="chant" hidden id="shoot">Shoot!</h2>
<div class="winner">
<div>
Player
<span class="winner-score" data-your-score>0</span>
</div>
<div data-final-column>
Computer
<span class="winner-score" data-computer-score>0</span>
</div>
<!--
<div class="result-selection winner">✂</div>
<div class="result-selection">📜</div>
-->
</div>
</body>
</html>