Is there any way to make a div appear stacked on top of another one, by clicking on a button/image?
The problem I have:
I want a poster to appear if I click on it in the selector.
I want it to stay, once I click on another poster, which then will stack on top of the previous one.
Is it possible to make this a loop, so no matter how often I click different objects the old divs will always stay below the newest one?
(See pictures attached)
and so on...
Thanks in advance!
CodePudding user response:
- Create a
div
calledpreview
, and makes itsposition
relative
. This is necessary because this creates a new stacking context. - Create another container that will hold the list of images to choose from. I choose a
section
with an unordered list which will contain these images as list elements. - Set
overflow-x
auto
, so a scrollbar appears once the amount of images exceed the container width. - In your stylesheet, select the images which are child of our
preview
div, and make theirposition
absolute
, with atop
margin of0
. This makes sure that all images are stacked in the same x-y direction. This works because thepreview
div also hasdisplay: flex
, withalign-items: center
as well asjustify-content: center
. - In your script file, select these list images - I called them
posters
.
const posters = document.querySelectorAll(".poster");
- Create two variables called
zIndex
( = 1) androtated
( = true). - Attach an event listener to each of the poster image inside this list of images, using a
for...of
loop.
for (const poster of posters) {
poster.addEventListener("click", () => onPosterClicked(poster));
}
- In this event handler, we select the
preview
div, and clone the clicked image usingcloneNode()
method. We also give itclass
ofshown
so, our styling for images insidepreview
work. - We then increment the z-index, and assign this incremented z-index to this cloned image's style.
cloned.style.zIndex = zIndex;
- For decorational purposes, we switch between rotated and non-rotated transforms, so each image new image added is rotated differently to our previous image.
if (rotated) {
cloned.style.transform = "rotate(-5deg)";
}
rotated = !rotated;
Note: We can achieve this rotation directly through CSS, by using nth-child
selectors.
- Finally, we append this cloned image to our
preview
div.
preview.appendChild(cloned);
The complete code looks like this:
function onPosterClicked(poster) {
const preview = document.querySelector(".preview");
const cloned = poster.cloneNode();
cloned.classList = "shown";
cloned.style.zIndex = zIndex;
if (rotated) {
cloned.style.transform = "rotate(-5deg)";
}
rotated = !rotated;
preview.appendChild(cloned);
}
const posters = document.querySelectorAll(".poster");
let zIndex = 1;
let rotated = true;
for (const poster of posters) {
poster.addEventListener("click", () => onPosterClicked(poster));
}
*,
*::before,
*::after {
box-sizing: border-box;
padding: 0;
margin: 0;
}
body {
width: 100%;
min-height: 100vh;
display: flex;
flex-direction: column;
}
.preview {
width: 100%;
height: 70vh;
display: flex;
align-items: center;
justify-content: center;
position: relative;
}
.shown {
height: 100%;
position: absolute;
top: 0;
border: 2px solid black;
}
.list {
width: 100%;
padding: 4rem 2rem;
}
.list ul {
display: flex;
flex-flow: row nowrap;
gap: 5px;
overflow-x: auto;
list-style: none;
}
.poster {
max-height: 300px;
object-fit: cover;
}
<body>
<div >
<img src="https://picsum.photos/seed/picsum/200/300" alt="test image" />
</div>
<section >
<ul>
<li>
<img src="https://picsum.photos/seed/picsum/200/300" alt="sample poster image" />
</li>
<li>
<img src="https://picsum.photos/seed/picsum/200/300" alt="sample poster image" />
</li>
<li>
<img src="https://picsum.photos/seed/picsum/200/300" alt="sample poster image" />
</li>
<li>
<img src="https://picsum.photos/seed/picsum/200/300" alt="sample poster image" />
</li>
<li>
<img src="https://picsum.photos/seed/picsum/200/300" alt="sample poster image" />
</li>
<li>
<img src="https://picsum.photos/seed/picsum/200/300" alt="sample poster image" />
</li>
<li>
<img src="https://picsum.photos/seed/picsum/200/300" alt="sample poster image" />
</li>
<li>
<img src="https://picsum.photos/seed/picsum/200/300" alt="sample poster image" />
</li>
</ul>
</section>
<script async defer src="main.js"></script>
</body>
CodePudding user response:
I will cut down the explaination to some documentations such as how to create an element through JS. Teachign every single step would blow the scope of Stackoverflow.
If you know how to create an element through JS you need a variable such as counter
in my code that is raised by every single time you run the script with: counter = counter 1
You set a z-index through JS with element.style.zIndex = variable
and thanks to the rising counter it will set the new element over the other element (z-axis-wise).
To rotate the element you can use transform: rotate()
which I randomized by calling a variable: rotation = Math.round(Math.random() * 40 - 20);
which will randomize a number between -20
and 20
.
var preview = document.querySelector('.preview'),
counter = '1';
picture = ''
function addRed() {
picture = 'red';
addPicture();
}
function addGreen() {
picture = 'green';
addPicture();
}
function addBlue() {
picture = 'blue';
addPicture();
}
function addYellow() {
picture = 'yellow';
addPicture();
}
function addPicture() {
var img = document.createElement('img'),
rotation = Math.round(Math.random() * 40 - 20);
switch (picture) {
case 'red':
img.src = 'https://via.placeholder.com/350.jpg/FF0000';
break;
case 'green':
img.src = 'https://via.placeholder.com/350.jpg/00FF00';
break;
case 'blue':
img.src = 'https://via.placeholder.com/350.jpg/0000FF';
break;
case 'yellow':
img.src = 'https://via.placeholder.com/350.jpg/FFFF00';
break;
}
img.style.position = 'absolute';
img.style.top = '50%';
img.style.left = '50%';
img.style.transform = 'translate(-50%, -50%) rotate(' rotation 'deg)';
img.style.zIndex = counter;
preview.appendChild(img);
var counter = counter 1;
}
.container {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-gap: 10px;
}
.preview {
grid-column: 1 / -1;
aspect-ratio: 1 / 1;
position: relative;
}
.selector {
padding: 10px;
}
.selector > img {
display: block;
object-fit: contain;
width: 100%;
}
<div >
<div ></div>
<div ><img src="https://via.placeholder.com/100.jpg/FF0000" onclick="addRed()"></div>
<div ><img src="https://via.placeholder.com/100.jpg/00FF00" onclick="addGreen()"></div>
<div ><img src="https://via.placeholder.com/100.jpg/0000FF" onclick="addBlue()"></div>
<div ><img src="https://via.placeholder.com/100.jpg/FFFF00" onclick="addYellow()"></div>
</div>