<div class="vegetables">
<div class="inner">
<ul class="page">
<li><span>Carrot</span></li>
<li><span>Tomato</span></li>
<li><span>Broccoli</span></li>
<li><span>Cucumber</span></li>
<li><span>Spinach</span></li>
</ul>
<!-- Page 1 -->
<ul class="page">
<li><span>Potato</span></li>
<li><span>Pepper</span></li>
<li><span>Eggplant</span></li>
<li><span>Lettuce</span></li>
<li><span>Onion</span></li>
</ul>
<!-- Page 2 -->
<ul class="page">
<li><span>Zucchini</span></li>
<li><span>Cauliflower</span></li>
<li><span>Kale</span></li>
<li><span>Cabbage</span></li>
<li><span>Mushroom</span></li>
</ul>
<!-- Page 3 -->
<ul class="page">
<li><span>Asparagus</span></li>
<li><span>Artichoke</span></li>
<li><span>Radish</span></li>
<li><span>Beet</span></li>
<li><span>Okra</span></li>
</ul>
<!-- Page 4 -->
<ul class="page">
<li><span>Brussels Sprouts</span></li>
<li><span>Green Bean</span></li>
<li><span>Butternut Squash</span></li>
<li><span>Turnip</span></li>
<li><span>Chard</span></li>
</ul>
<!-- Page 5 -->
</div>
</div>
<div class="pagination">
<ul id="dots">
<li class="prev"></span></li>
<li></li>
<li></li>
<li></li>
<li></li>
<svg width="430" height="200" viewBox="0 0 400 200">
<path></path>
</svg>
</ul>
<button id="prevPage">Previous</button>
<button id="nextPage">Next</button>
</div>
@font-face {
font-family: "Romie";
src: url("https://assets.codepen.io/383755/Romie-Regular.woff2")
format("woff2");
}
body {
font-family: sans-serif;
max-width: 100vw;
height: 100vh;
position: relative;
overflow: hidden;
--black: #151515;
--c1: #0272f2;
--c2: #ff5213;
--c3: #ffdf3f;
--c4: #01b26e;
--c5: #fea9e0;
--c6: #ffdf3f;
background: var(--black);
}
.vegetables {
perspective: 500px;
transform-style: preserve-3d;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
width: 100vw;
height: 100%;
position: absolute;
top: 0;
left: 0;
margin: 0 auto;
font-family: "Romie";
* {
transform-style: preserve-3d;
}
.inner {
position: absolute;
width: 100vw;
height: 100vh;
}
}
.page {
transform-style: preserve-3d;
position: absolute;
top: calc(50% - 100px);
left: 50%;
list-style: none;
padding: 0;
height: calc(90vmin - 300px);
width: 90vmin;
display: flex;
justify-content: center;
align-items: stretch;
flex-wrap: wrap;
gap: 10px;
padding: 0;
margin: 0;
transform: translate(-50%, -50%) translateZ(200vmin);
transition: 0.3s cubic-bezier(0.175, 0.885, 0.32, 1) 0.75s;
li {
transition: 0.5s ease-in-out;
opacity: 0;
font-size: 7vmin;
@for $i from 1 through 5 {
&:nth-of-type(#{$i}) {
color: #ccc;
span:after {
transform: scaleX(0);
background: #ccc;
transition: 0.5s ease-in-out #{($i/8) + 0.75}s;
}
}
}
}
&.current {
transform: translate(-50%, -50%) translateZ(0vmin);
li {
opacity: 1;
background-position: 50% 100%;
@for $i from 1 through 5 {
&:nth-of-type(#{$i}) {
transition: 0.5s ease-in-out 0.75s, color 0.5s ease-in-out #{($i/8) + 1}s;
color: var(--c#{$i});
span:after {
transform: scaleX(1);
background: var(--c#{$i});
transition: 0.5s ease-in-out #{($i/8) + 0.75}s;
}
}
}
}
&:nth-of-type(even) li {
@for $i from 1 through 5 {
&:nth-of-type(#{$i}) {
color: var(--c#{6 - $i});
span:after {
background: var(--c#{6 -$i});
}
}
}
}
}
}
.page li {
display: flex;
justify-content: flex-start;
align-items: center;
width: 100%;
overflow: hidden;
span {
display: inline-block;
position: relative;
background: var(--black);
&:after {
content: "";
position: absolute;
width: 100vw;
left: calc(100% + 1rem);
top: calc(50% - 0.5px);
height: 1px;
background: #ccc;
z-index: -1;
}
}
&:nth-of-type(even) {
justify-content: flex-end;
span {
&:after {
left: auto;
right: calc(100% + 1rem);
}
}
}
}
.pagination {
text-align: center;
margin-top: 20px;
position: absolute;
bottom: 0;
left: 0;
width: 100%;
padding: 1rem;
}
button {
padding: 8px 16px;
border: 1px solid #ccc;
background: transparent;
color: #ccc;
cursor: pointer;
margin: 0 7.5px 1rem;
position: relative;
z-index: 999;
width: 200px;
border-radius: 50px;
transition: 0.3s ease-in-out;
font-family: "Romie";
font-size: 1.15rem;
padding: 0.15rem;
font-weight: 900;
}
button:hover {
border-color: var(--c3);
color: var(--c3);
}
button:disabled {
border-color: #666;
color: #666;
cursor: not-allowed;
}
#dots {
--timing: 0.75;
width: 400px;
list-style-type: none;
position: absolute;
top: -150px;
height: 200px;
left: 50%;
transform: translate(-50%);
padding: 0;
margin: 0;
--basepath: "M 0 100 Q 200 100 400 100 ";
--basepath-1: "M 0 150 Q 100 100 400 100 ";
--basepath-2: "M 0 100 Q 100 200 400 100 ";
--basepath-3: "M 0 100 Q 200 200 400 100 ";
--basepath-4: "M 10 100 Q 300 200 400 100 ";
--basepath-5: "M 10 100 Q 300 100 400 150 ";
@for $i from 1 through 5 {
--placement-#{$i}: #{(($i - 1) * 100) - 5}px;
&:has(li:nth-of-type(#{$i}).active) {
@for $j from 1 through 5 {
&:has(li:nth-of-type(#{$j}).prev) {
--origin: var(--placement-#{$j});
--destination: var(--placement-#{$i});
svg path {
animation: spring#{$j} 0.75s ease-in-out 1 forwards;
@keyframes spring#{$j} {
75% {
d: path(var(--basepath-#{$j}));
animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1.875);
}
100% {
d: path(var(--basepath));
animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1.875);
}
}
}
li {
animation: bounce#{$j} 0.75s ease-in-out 1 forwards;
@keyframes bounce#{$j} {
75% {
offset-path: path(var(--basepath-#{$j}));
animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1.875);
}
100% {
offset-path: path(var(--basepath));
animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1.875);
}
}
&:before {
animation: shift#{$j}
calc(0.35s * var(--timing))
ease-out
1
forwards
0.6s,
jump#{$j} calc(0.35s * var(--timing)) linear 1 forwards 0.6s;
@keyframes shift#{$j} {
100% {
transform: translateX(calc(var(--destination) - var(--origin)));
}
}
@keyframes jump#{$j} {
25%,
75% {
top: calc(-50px * (var(--timing) * 0.75));
}
50% {
top: calc(-50px * (var(--timing) * 1.25));
}
33%,
66% {
top: calc(-50px * (var(--timing) * 1));
}
}
}
}
}
}
}
}
}
svg {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
z-index: -1;
stroke-linecap: round;
filter: drop-shadow(0 5px 10px rgba(0, 0, 0, 0.25));
path {
stroke-width: 25px;
stroke: var(--c1);
fill: none;
d: path(var(--basepath));
}
}
#dots li {
width: 10px;
height: 10px;
background: var(--black);
box-shadow: 0 0 0 3px var(--black);
border-radius: 100%;
offset-path: path(var(--basepath));
position: absolute;
cursor: pointer;
&:hover {
box-shadow: 0 0 0 2px var(--black), 0 0 0 3px var(--c5);
}
&:before {
content: "";
position: absolute;
width: 100%;
height: 100%;
background: var(--c5);
left: 0;
top: 0;
border-radius: 100%;
opacity: 0;
z-index: 999;
pointer-events: none;
}
&.active {
pointer-events: none;
}
&.prev {
z-index: 9;
&:before {
opacity: 1;
}
}
@for $i from 1 through 5 {
&:nth-of-type(#{$i}) {
offset-distance: calc(#{($i - 1) * 25} * 1%);
}
}
}
View Compiled
document.addEventListener("DOMContentLoaded", function () {
const pages = document.querySelectorAll(".page");
const prevButton = document.getElementById("prevPage");
const nextButton = document.getElementById("nextPage");
let currentPage = 0;
function showPage(pageNumber) {
pages.forEach((page, index) => {
page.classList.remove("current");
pages[pageNumber].classList.add("current");
document.body.style.setProperty("--shift", pageNumber);
});
}
function updateButtons() {
prevButton.disabled = currentPage === 0;
nextButton.disabled = currentPage === pages.length - 1;
}
prevButton.addEventListener("click", function () {
if (currentPage > 0) {
currentPage--;
showPage(currentPage);
updateButtons();
document.querySelectorAll("#dots li")[currentPage].click();
}
});
nextButton.addEventListener("click", function () {
if (currentPage < pages.length - 1) {
currentPage++;
showPage(currentPage);
updateButtons();
document.querySelectorAll("#dots li")[currentPage].click();
}
});
showPage(currentPage);
updateButtons();
let dotNav = document.getElementById("dots"),
newIndex = 0,
prevIndex;
document.querySelectorAll("#dots li").forEach((dot, index) => {
dot.addEventListener("click", function (e) {
currentPage = index;
showPage(currentPage);
if (document.getElementsByClassName("active")[0]) {
prevIndex = newIndex;
newIndex = index;
updateButtons();
dotNav.style.setProperty(
"--timing",
Math.abs((newIndex - prevIndex) / 5) + 0.5
);
document.getElementsByClassName("prev")[0] &&
document.getElementsByClassName("prev")[0].classList.remove("prev");
document.getElementsByClassName("active")[0].classList.add("prev");
document.getElementsByClassName("active")[0].classList.remove("active");
}
e.target.classList.add("active");
});
});
});
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.