I’m trying to make a Netflix clone for my first project.
The problem -
When i click on any of the images i want the container to move to that image’s location.
I don’t quite understand how the container moves top/right/left/down without buttons and how the image location stays the same when you click on a different image.
(This might be an inaccurate description because i don’t understand how it works).
About Netflix - Homepage - this shows the slider i want to replicate
HTML
<div class="new-releases-container">
<div class="new-releases-height">
<div class="new-releases-transform">
<button class="new-releases-btn-left js-new-releases-btn-left">
<span>
<i class="fa fa-arrow-left" aria-hidden="true"></i>
</span>
</button>
<button class="new-releases-btn-right js-new-releases-btn-right">
<span>
<i class="fa fa-arrow-right" aria-hidden="true"></i>
</span>
</button>
<div class="new-releases-wrapper js-new-releases-wrapper">
<div class="new-releases-column-wrapper js-column-wrapper">
</div>
</div>
</div>
</div>
</div>
CSS
body {
background-color: black;
overflow: hidden;
}
* {
box-sizing: border-box;
}
/* New on netflix title */
.New-on-Netflix-releases {
position: relative;
z-index: 1;
box-shadow: 50px 30px 70px 50px rgb(0, 0, 0);
}
.New-on-Netflix-releases-title {
width: 75%;
margin: auto;
}
.New-on-Netflix-releases h2 {
font-size: 60px;
margin: 0 0 8px;
}
.New-on-Netflix-releases a {
font-size: 40px;
text-decoration: none;
color: red;
font-weight: bolder;
}
.New-on-Netflix-releases a:hover {
color: white;
text-decoration: underline;
transition: 0.3s ease-in-out;
}
/* All releases slider */
.new-releases-container {
position: relative;
margin-top: 5px;
direction: ltr;
}
.new-releases-height {
height: 720px;
}
.new-releases-transform {
width: 100vw;
height: 720px;
margin: auto;
position: relative;
overflow: hidden;
}
/* Netflix releases slider buttons */
.new-releases-btn-left {
border: 1px solid rgb(229, 9, 20);
font-size: 30px;
background-color: rgb(229, 9, 20);
color: white;
padding: 18px 16px;
cursor: pointer;
position: absolute;
top: 30%;
z-index: 5;
}
.new-releases-btn-right {
border: 1px solid rgb(229, 9, 20);
font-size: 30px;
background-color: rgb(229, 9, 20);
color: white;
padding: 18px 16px;
cursor: pointer;
position: absolute;
right: 18px;
top: 30%;
z-index: 5;
}
.new-releases-btn-left:hover,
.new-releases-btn-right:hover {
background-color: transparent;
}
/* Netflix releases slider */
.new-releases-wrapper {
/* width: 6100px; */
transform: translate3d(var(--x, -5%), var(--y, -20%), 0px);
transform-origin: left top;
position: absolute;
transition: 0.5s;
}
.new-releases-column-wrapper {
display: grid;
grid-template-columns: repeat(16, 1fr);
gap: 20px;
transform: rotate3d(1, 1, 1, 13deg);
transform-origin: left top;
align-items: center;
}
.new-releases-column {
display: grid;
gap: 20px;
transition: 800ms;
}
.new-releases-image-filler {
position: relative;
}
.new-releases-image-filler::after {
content: "";
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.8);
}
.new-releases-image {
width: 100%;
object-fit: cover;
vertical-align: bottom;
}
.new-releases-image-wrapper {
position: relative;
cursor: pointer;
border: 0;
padding: 0;
display: inherit;
opacity: 0.2;
transition: 0.6s;
}
.new-releases-image-wrapper:hover {
background-color: rgba(0, 0, 0, 0.2);
opacity: 0.5;
}
.new-releases-image-wrapper::after {
content: "";
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
/* Selects active class */
.new-releases-active {
cursor: default;
opacity: 1;
}
.new-releases-active:hover {
opacity: 1;
}
JavaScript
const imageOrderMiddle = [
["Emily in Paris", "Outer Banks", "Emily in Paris", "The Umbrella Academy", "Beverly Hills Cop: Axel F", "Bridgerton", "Atlas", "3 Body Problem", "Damsel", "Avatar The Last Airbender", "Lupin", "Outer Banks", "Emily in Paris", "Outer Banks"],
["Beverly Hills Cop: Axel F", "The Umbrella Academy", "Beverly Hills Cop: Axel F", "Bridgerton", "Atlas", "3 Body Problem", "Damsel", "Avatar The Last Airbender", "Lupin", "Outer Banks", "Emily in Paris", "The Umbrella Academy", "Beverly Hills Cop: Axel F", "The Umbrella Academy"],
["Atlas", "Bridgerton", "Atlas", "3 Body Problem", "Damsel", "Avatar The Last Airbender", "Lupin", "Outer Banks", "Emily in Paris", "The Umbrella Academy", "Beverly Hills Cop: Axel F", "Bridgerton", "Atlas", "Bridgerton"],
["Damsel", "3 Body Problem", "Damsel", "Avatar The Last Airbender", "Lupin", "Outer Banks", "Emily in Paris", "The Umbrella Academy", "Beverly Hills Cop: Axel F", "Bridgerton", "Atlas", "3 Body Problem", "Damsel", "3 Body Problem"],
["Lupin", "Avatar The Last Airbender", "Lupin", "Outer Banks", "Emily in Paris", "The Umbrella Academy", "Beverly Hills Cop: Axel F", "Bridgerton", "Atlas", "3 Body Problem", "Damsel", "Avatar The Last Airbender", "Lupin", "Avatar The Last Airbender"],
["Emily in Paris", "Outer Banks", "Emily in Paris", "The Umbrella Academy", "Beverly Hills Cop: Axel F", "Bridgerton", "Atlas", "3 Body Problem", "Damsel", "Avatar The Last Airbender", "Lupin", "Outer Banks", "Emily in Paris", "Outer Banks"],
["Beverly Hills Cop: Axel F", "The Umbrella Academy", "Beverly Hills Cop: Axel F", "Bridgerton", "Atlas", "3 Body Problem", "Damsel", "Avatar The Last Airbender", "Lupin", "Outer Banks", "Emily in Paris", "The Umbrella Academy", "Beverly Hills Cop: Axel F", "The Umbrella Academy"],
["Atlas", "Bridgerton", "Atlas", "3 Body Problem", "Damsel", "Avatar The Last Airbender", "Lupin", "Outer Banks", "Emily in Paris", "The Umbrella Academy", "Beverly Hills Cop: Axel F", "Bridgerton", "Atlas", "Bridgerton"],
["Damsel", "3 Body Problem", "Damsel", "Avatar The Last Airbender", "Lupin", "Outer Banks", "Emily in Paris", "The Umbrella Academy", "Beverly Hills Cop: Axel F", "Bridgerton", "Atlas", "3 Body Problem", "Damsel", "3 Body Problem"],
["Lupin", "Avatar The Last Airbender", "Lupin", "Outer Banks", "Emily in Paris", "The Umbrella Academy", "Beverly Hills Cop: Axel F", "Bridgerton", "Atlas", "3 Body Problem", "Damsel", "Avatar The Last Airbender", "Lupin", "Avatar The Last Airbender"],
["Emily in Paris", "Outer Banks", "Emily in Paris", "The Umbrella Academy", "Beverly Hills Cop: Axel F", "Bridgerton", "Atlas", "3 Body Problem", "Damsel", "Avatar The Last Airbender", "Lupin", "Outer Banks", "Emily in Paris", "Outer Banks"]
];
const fillerImgOrderTop = [
["Damsel", "3 Body Problem", "The Umbrella Academy", "Damsel", "3 Body Problem", "Outer Banks", "Emily in Paris", "Atlas", "Avatar The Last Airbender", "Lupin", "Beverly Hills Cop: Axel F", "Bridgerton", "Damsel", "3 Body Problem"],
["Avatar The Last Airbender", "Damsel", "3 Body Problem", "Avatar The Last Airbender", "Damsel", "The Umbrella Academy", "Bridgerton", "Atlas", "Lupin", "Beverly Hills Cop: Axel F", "Emily in Paris", "Outer Banks", "Avatar The Last Airbender", "Damsel"]
];
const fillerImgOrderBottom = [
["Avatar The Last Airbender", "Damsel", "3 Body Problem", "Avatar The Last Airbender", "Damsel", "The Umbrella Academy", "Bridgerton", "Atlas", "Lupin", "Beverly Hills Cop: Axel F", "Emily in Paris", "Outer Banks", "Avatar The Last Airbender", "Damsel"],
["Damsel", "3 Body Problem", "The Umbrella Academy", "Damsel", "3 Body Problem", "Outer Banks", "Emily in Paris", "Atlas", "Avatar The Last Airbender", "Lupin", "Beverly Hills Cop: Axel F", "Bridgerton", "Damsel", "3 Body Problem"],
["Avatar The Last Airbender", "Damsel", "3 Body Problem", "Avatar The Last Airbender", "Damsel", "The Umbrella Academy", "Bridgerton", "Atlas", "Lupin", "Beverly Hills Cop: Axel F", "Emily in Paris", "Outer Banks", "Avatar The Last Airbender", "Damsel"]
];
const imageMap = {
"Outer Banks": "https://images.ctfassets.net/4cd45et68cgf/6moW3v0XmYQYGTCt9zQSQ4/fc3f2f09c8fa6a086e95135be6da5766/Outer_Banks-Box_Art-0a2fa780-808e-11ed-a028-0e2c4adfb8d9.jpg?w=450",
"Emily in Paris": "https://images.ctfassets.net/4cd45et68cgf/5ptejvcnahIO9mzzvAXPGX/8115d8e802a35a1fdb0a06f9d6d7447d/Emily_in_Paris-Box_Art-7a2aa8f0-3eba-11ef-9bdf-0afff3e0c591.jpg?w=450",
"The Umbrella Academy": "https://images.ctfassets.net/4cd45et68cgf/xugUueKmXMYdMhGWTrwJ6/05c00ac09f4b791e71e458e93893b23a/boxshot-d6808131-d53d-11ec-a614-0ea8a2086911-en.jpg?w=450",
"Damsel": "https://images.ctfassets.net/4cd45et68cgf/7uvQ0UMfH4n7d9xiiGTnCj/059a28dfcf5bbc7ca4d7a26e472b459c/Damsel-Box_Art-eea2c160-b704-11ee-a719-0abb786df99d.jpg?w=450",
"3 Body Problem": "https://images.ctfassets.net/4cd45et68cgf/39dnQDghHBLoKdIjELB23B/cd5b8e09fab920218cdbec0d209a531f/3_Body_Problem-Box_Art-18643110-7f73-11ee-8c7d-0eb591653dd5.jpg?w=450",
"Atlas": "https://images.ctfassets.net/4cd45et68cgf/2xy10L701hbNRABCQMyU8k/3e87222f018421c40d1132eecedc7a4c/Atlas-Box_Art-401a0780-ddb9-11ee-b549-0ede983d3081.jpg?w=450",
"Avatar The Last Airbender": "https://images.ctfassets.net/4cd45et68cgf/3TnrASKnE6xGdChdThdzEv/4a0e49f823e5664de6c8a79c101442dd/Avatar_The_Last_Airbender-Box_Art-ec2a71c0-b72d-11ee-99ea-1238dc406fbf.jpg?w=450",
"Lupin": "https://images.ctfassets.net/4cd45et68cgf/1vcVmffymDuzq1jKUAW1O7/927d3133b64b16aa5c821de3e65244e4/Lupin-Box_Art-3c07b700-a8ce-11eb-98b9-0e979d30cfcb.jpg?w=450",
"Beverly Hills Cop: Axel F": "https://images.ctfassets.net/4cd45et68cgf/6JT97CtytL91EcuAuSAnLw/54f4d7c0525a63e9edd0b6027693280b/boxshot-877e1290-18ad-11ef-b798-12a47e3ef511-en_BADGE-recently.added-en.jpg?w=450",
"Bridgerton": "https://images.ctfassets.net/4cd45et68cgf/22yRHWBxmnIjER17uUFb20/97fd1bdbb442c7c629f0bc40162f035f/Season_3-Box_Art-55136bc0-fe7c-11ee-a20e-0e9b8162e1d7.jpg?w=450",
};
const newReleasesColumnWrapper = document.querySelector(".js-column-wrapper");
function createFillerColumns(columnOrder) {
//Loop through array to generate correct number of columns
columnOrder.forEach(order => {
//Create filler image wrapper
const newReleaseColumn = document.createElement("div");
newReleaseColumn.className = "new-releases-column";
//Loop through each array to generate correct number of elements
order.forEach(newRelease => {
const newReleaseFiller = document.createElement("div");
newReleaseFiller.className = "new-releases-image-filler";
const newReleaseFillerImg = document.createElement("img");
newReleaseFillerImg.className = "new-releases-image";
//Match urls with corresponding show names
newReleaseFillerImg.src = imageMap[newRelease];
newReleaseFillerImg.alt = newRelease;
newReleaseColumn.appendChild(newReleaseFiller);
newReleaseFiller.appendChild(newReleaseFillerImg);
});
newReleasesColumnWrapper.appendChild(newReleaseColumn);
});
}
function createMiddleColumns(columnOrder) {
//Loop through array to generate correct number of columns
columnOrder.forEach(order => {
const newReleaseColumn = document.createElement("div");
newReleaseColumn.classList = "new-releases-column js-new-releases-column";
//Loop through each array to generate correct number of elements
order.forEach(newRelease => {
const newReleaseImgWrapper = document.createElement("button");
newReleaseImgWrapper.className = "new-releases-image-wrapper js-nr-image-wrapper";
newReleaseImgWrapper.ariaLabel = newRelease;
const newReleasesImg = document.createElement("img");
newReleasesImg.className = "new-releases-image";
//Match urls with corresponding show names
newReleasesImg.src = imageMap[newRelease];
newReleaseImgWrapper.appendChild(newReleasesImg);
newReleaseColumn.appendChild(newReleaseImgWrapper);
})
newReleasesColumnWrapper.appendChild(newReleaseColumn);
});
}
function setActiveImg(array) {
for (let i = 0; i < array.length; i++) {
array[i].classList.remove("new-releases-active");
}
array[activeIndex].classList.add("new-releases-active");
}
//Generates 2 filler columns before middle columns
createFillerColumns(fillerImgOrderTop);
//Generates middle columns that are interactive
createMiddleColumns(imageOrderMiddle);
//Generates 3 filler columns after middle columns
createFillerColumns(fillerImgOrderBottom);
//Event listeners
const newReleaseImgWrapper = document.querySelectorAll(".js-nr-image-wrapper");
const newReleaseColumn = document.querySelectorAll(".new-releases-column");
const newReleaseWrapper = document.querySelector(".js-new-releases-wrapper");
let activeIndex = 0;
let imageIndex = 0;
newReleaseImgWrapper.forEach((wrapperImage, index) => {
wrapperImage.addEventListener("click", (e) => {
activeIndex = index;
setActiveImg(newReleaseImgWrapper);
const positon = wrapperImage.getBoundingClientRect();
imageIndex++;
newReleaseWrapper.style = `--x: -${imageIndex * positon.width}px; --y: -${positon.height}px`
});
});
document.querySelector(".js-new-releases-btn-left")
.addEventListener("click", () => {
activeIndex = (activeIndex - 1) % newReleaseImgWrapper.length;
setActiveImg(newReleaseImgWrapper);
})
document.querySelector(".js-new-releases-btn-right")
.addEventListener("click", () => {
activeIndex = (activeIndex + 1) % newReleaseImgWrapper.length;
setActiveImg(newReleaseImgWrapper);
})