<label class="checkbox">
<input type="checkbox" id="overflow" checked /> Hide image overflow
</label>
<div class="container">
<h2 class="title">Welcome to the Snuggle Zone</h2>
<div class="carousel-viewport">
<ul class="items">
<li class="item">
<img src='https://images.unsplash.com/photo-1611003228577-e610e9a727c5?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwxNDU4OXwwfDF8cmFuZG9tfHx8fHx8fHx8MTYyMjgzMzExNw&ixlib=rb-1.2.1&q=80&w=1200' width="1200" height="675" alt=''>
</li>
<li class="item">
<img src='https://images.unsplash.com/photo-1611507929918-08ee0bcb42d7?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwxNDU4OXwwfDF8cmFuZG9tfHx8fHx8fHx8MTYyMzE4OTc4OQ&ixlib=rb-1.2.1&q=80&w=1200' width="1200" height="675" alt=''>
</li>
<li class="item">
<img src='https://images.unsplash.com/photo-1589441161120-8781d5644435?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwxNDU4OXwwfDF8cmFuZG9tfHx8fHx8fHx8MTYyMzE4NzY1MQ&ixlib=rb-1.2.1&q=80&w=1200' width="1200" height="675" alt=''>
</li>
<li class="item">
<img src='https://images.unsplash.com/photo-1518914781460-a3ada465edec?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwxNDU4OXwwfDF8cmFuZG9tfHx8fHx8fHx8MTYyMzE4OTg0MA&ixlib=rb-1.2.1&q=80&w=1200' width="1200" height="675" alt=''>
</li>
</ul>
</div>
<button class="carousel-control prev" title="Go to previous item">
<svg viewBox="0 0 256 512">
<path d="M31.7 239l136-136c9.4-9.4 24.6-9.4 33.9 0l22.6 22.6c9.4 9.4 9.4 24.6 0 33.9L127.9 256l96.4 96.4c9.4 9.4 9.4 24.6 0 33.9L201.7 409c-9.4 9.4-24.6 9.4-33.9 0l-136-136c-9.5-9.4-9.5-24.6-.1-34z" />
</svg>
</button>
<button class="carousel-control next" title="Go to next item">
<svg viewBox="0 0 256 512">
<path d="M224.3 273l-136 136c-9.4 9.4-24.6 9.4-33.9 0l-22.6-22.6c-9.4-9.4-9.4-24.6 0-33.9l96.4-96.4-96.4-96.4c-9.4-9.4-9.4-24.6 0-33.9L54.3 103c9.4-9.4 24.6-9.4 33.9 0l136 136c9.5 9.4 9.5 24.6.1 34z" />
</svg>
</button>
<ol class="carousel-dots">
<li class="dot active">1</li>
<li class="dot">2</li>
<li class="dot">3</li>
<li class="dot">4</li>
</ol>
</div>
@import url("https://fonts.googleapis.com/css2?family=Gorditas&display=swap");
.container {
display: grid;
grid-template: "container" 1fr;
place-items: center;
place-content: center;
overflow: hidden;
max-height: clamp(450px, 50vh, 600px);
}
.container > * {
grid-area: container;
max-width: 1000px;
}
.title {
place-self: start center;
}
.carousel-control.prev {
place-self: center left;
}
.carousel-control.next {
place-self: center right;
}
.carousel-dots {
place-self: end center;
}
/* Other element styles */
* {
box-sizing: border-box;
}
body {
--space: 6rem;
--bg-color: papayawhip;
display: grid;
place-items: center;
padding: var(--space) 0;
grid-gap: var(--space);
background-color: var(--bg-color);
font-family: "Helvetica", sans-serif;
line-height: 1.2;
}
.checkbox {
position: fixed;
top: 0;
left: 0;
z-index: 1;
cursor: pointer;
user-select: none;
background-color: inherit;
padding: 1rem;
opacity: 0.9;
}
.container {
--border: 4px dashed dodgerblue;
position: relative;
border-top: var(--border);
border-bottom: var(--border);
margin: 0 auto;
width: 100%;
color: white;
}
.title {
position: relative;
font-family: "Gorditas", sans-serif;
font-size: clamp(1rem, 4vw, 2.5rem);
padding: 1rem;
text-align: center;
z-index: 1;
}
.carousel-viewport {
position: relative;
overflow: hidden;
margin: 0 auto;
z-index: -1;
}
.carousel-viewport .items {
position: relative;
display: flex;
transition: transform 500ms cubic-bezier(0.25, 1, 0.5, 1);
}
.carousel-viewport .item {
position: relative;
overflow: hidden;
aspect-ratio: 16 / 9;
min-width: 100%;
transform: translateZ(0);
}
.carousel-viewport img {
object-fit: cover;
width: 100%;
height: 100%;
user-select: none;
}
.carousel-control {
--size: clamp(2.5rem, 8vw, 4rem);
position: relative;
cursor: pointer;
display: flex;
align-content: center;
justify-content: center;
color: white;
fill: currentcolor;
background: dodgerblue;
border: none;
width: var(--size);
height: var(--size);
padding: 0.25rem;
touch-action: manipulation;
transform: translateY(0);
}
.carousel-control:active {
transform: translateY(1px);
}
.carousel-control svg {
width: 100%;
height: 100%;
pointer-events: none;
}
.carousel-dots {
display: flex;
gap: 1rem;
padding: 1rem;
}
.carousel-dots .dot {
--size: 1rem;
padding: 0;
font-size: 0;
color: transparent;
border: 3px solid white;
background-color: white;
border-radius: 50%;
width: var(--size);
height: var(--size);
}
.carousel-dots .dot.active {
background-color: dodgerblue;
}
/* aspect-ratio fallback */
@supports not (aspect-ratio: 16 / 9) {
.carousel-viewport .item::before {
content: "";
float: left;
padding-top: 56.25%;
}
.carousel-viewport .item::after {
content: "";
display: block;
clear: both;
}
}
/* Overflow toggle */
const hideOverflow = document.getElementById("overflow");
hideOverflow.addEventListener("click", () => {
document.querySelector(".container").style.overflow = hideOverflow.checked
? "hidden"
: "visible";
});
/* Carousel */
const items = document.querySelector(".items");
const dots = document.querySelectorAll(".dot");
const prev = document.querySelector(".prev");
const next = document.querySelector(".next");
const total = items.children.length - 1;
const active = "active";
let current = 0;
const setActiveDot = () => {
dots.forEach((button, i) => {
i === current
? button.classList.add(active)
: button.classList.remove(active);
});
};
const scrollToCurrent = () => {
items.style.transform = `translateX(${current * -100}%`;
setActiveDot();
};
const scrollPrev = () => {
if (current === 0) return;
current--;
scrollToCurrent();
};
const scrollNext = () => {
if (current === total) return;
current++;
scrollToCurrent();
};
prev.addEventListener("click", scrollPrev);
next.addEventListener("click", scrollNext);
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.