- Центральную «активную» карточку
- Вид слева и справа соседних карточек (обрезанных/замаскированных)
- Кнопки «Предыдущий/следующий» + точки
https://www.ramseysolutions.com/busines ... leadership
Сейчас мой JS заменяет внутренний HTML внутри слотов при каждой навигации. Это вызывает «щелканье»/дерганье, и я не могу добиться плавного скольжения/перехода между старой и новой картой. Я также иногда вижу краткий эффект «дополнительной карты ниже», если во время перехода существуют два элемента .ts-slot-inner.
Код: Выделить всё
function initCarousel(root) {
const articles = Array.from(root.querySelectorAll(".slides > article"));
const prevSlot = root.querySelector('[data-slot="prev"]');
const currSlot = root.querySelector('[data-slot="current"]');
const nextSlot = root.querySelector('[data-slot="next"]');
const prevBtn = root.querySelector("[data-prev]");
const nextBtn = root.querySelector("[data-next]");
const dotsWrap = root.querySelector("[data-dots]");
const slides = articles.map(a => ({
title: a.dataset.title || "Slide",
html: a.innerHTML
}));
const mod = (n, m) => ((n % m) + m) % m;
const wrapSlot = (html) => `${html}`;
const wrapPeek = (html) =>
`${html}`;
let index = 0;
function renderDots() {
dotsWrap.innerHTML = slides.map((s, i) => `
${s.title}
`).join("");
dotsWrap.querySelectorAll("[data-dot]").forEach(btn => {
btn.addEventListener("click", () => {
index = Number(btn.dataset.dot);
update();
});
});
}
function update() {
const prevIndex = mod(index - 1, slides.length);
const nextIndex = mod(index + 1, slides.length);
prevSlot.innerHTML = wrapPeek(slides[prevIndex].html);
currSlot.innerHTML = wrapSlot(slides[index].html);
nextSlot.innerHTML = wrapPeek(slides[nextIndex].html);
renderDots();
}
prevBtn.addEventListener("click", () => {
index = mod(index - 1, slides.length);
update();
});
nextBtn.addEventListener("click", () => {
index = mod(index + 1, slides.length);
update();
});
update();
}
document.querySelectorAll(".carousel").forEach(initCarousel);Код: Выделить всё
.carousel-row {
display: grid;
grid-template-columns: 2fr 6fr 2fr;
gap: 16px;
align-items: stretch;
}
/* slots clip their contents */
.peek, .center {
position: relative;
overflow: hidden;
min-height: 1px;
}
/* if multiple inner wrappers exist, they should overlap */
.peek .slot-inner,
.center .slot-inner {
position: absolute;
inset: 0;
width: 100%;
}
/* keep first one in-flow to preserve height */
.peek > .slot-inner:first-child,
.center > .slot-inner:first-child {
position: relative;
}
/* side peek masks */
.peek-inner { width: 300%; }
.peek-left .peek-inner { transform: translateX(-66.6667%); }
.peek-right .peek-inner { transform: translateX(0); }
.card {
background: white;
padding: 16px;
border-radius: 16px;
box-shadow: 0 0 8px rgba(0,0,0,.15);
text-align: center;
}
.card-green { color: #2b6b45; }
.card-blue { color: #3aa7c9; }
.card-yellow { color: #f1953a; }
.quote { font-size: 18px; line-height: 1.6; }
.meta::before {
content: "";
display: block;
width: 180px;
height: 4px;
background: currentColor;
margin: 16px auto;
border-radius: 2px;
}
/* I *want* to animate between slides, but this currently doesn't work well */
.slot-inner {
transition: transform 0.9s ease, opacity 0.9s ease;
}Код: Выделить всё
‹
›
“Generic quote text for slide one.”
Person One
Category A
“Generic quote text for slide two.”
Person Two
Category B
“Generic quote text for slide three.”
Person Three
Category C
Подробнее здесь: https://stackoverflow.com/questions/798 ... ion-smooth
Мобильная версия