インジケーターを追加したカルーセルのサンプル
<div class="carousel-outer">
<div class="carousel">
<div class="carousel__section">
<img src="https://placehold.jp/ccffff/000000/960x540.png?text=Section1">
</div>
<div class="carousel__section">
<img src="https://placehold.jp/ffccff/000000/960x540.png?text=Section2">
</div>
<div class="carousel__section">
<img src="https://placehold.jp/ccffcc/000000/960x540.png?text=Section3">
</div>
</div>
<button class="carousel__button-left">←</button>
<button class="carousel__button-right">→</button>
<ul class="carousel__indicator">
<li class="active"></li>
<li></li>
<li></li>
</ul>
</div>
img {
max-width: 100%;
height: auto;
}
ul, li {
list-style: none;
margin: 0;
padding: 0;
}
.carousel-outer {
position: relative;
overflow: hidden;
width: 100%;
max-width: 960px;
}
.carousel {
display: flex;
transform: translateX(-100%);
transition: transform 0.5s ease-in-out;
}
.no-transition {
transition: none;
}
.carousel__section {
min-width: 100%;
}
.carousel__button-left,
.carousel__button-right {
position: absolute;
top: 50%;
transform: translateY(-50%);
cursor: pointer;
}
.carousel__button-left {
left: 5%;
}
.carousel__button-right {
right: 5%;
}
.carousel__indicator {
display: flex;
position: absolute;
bottom: 5%;
left: 50%;
transform: translateX(-50%);
}
.carousel__indicator > li {
width: 10px;
height: 10px;
margin: 0 5px;
border-radius: 50%;
border: 1px solid #000;
}
.carousel__indicator > .active {
background: #000
}
let current = 1
let isAnimation = false;
const carousel = document.querySelector('.carousel')
const carousels = document.querySelectorAll('.carousel__section')
const carouselLen = carousels.length
const lastCarousel = carouselLen + 1
const total = carouselLen + 2;
const newOrder = [];
newOrder.push(carousels[carouselLen - 1].outerHTML)
carousels.forEach((section) => {
newOrder.push(section.outerHTML)
})
newOrder.push(carousels[0].outerHTML)
carousel.innerHTML = newOrder.join('')
function updateIndicators(newIndex) {
if (newIndex < 0) {
newIndex = carouselLen - 1
} else if (newIndex > (carouselLen - 1)) {
newIndex = 0
}
document.querySelectorAll('.carousel__indicator > li').forEach((dot, index) => {
dot.classList.toggle('active', index === newIndex)
})
}
function showSection() {
isAnimation = true;
carousel.style.transform = `translateX(${-current * 100}%)`;
updateIndicators(current - 1)
}
function prevSection() {
if (isAnimation) return
current = current === 0 ? carouselLen + 1 : current - 1;
showSection()
}
function nextSection() {
if (isAnimation) return
current = (current + 1) % (carouselLen + 2);
showSection()
}
const btnLeft = document.querySelector('.carousel__button-left')
const btnRight = document.querySelector('.carousel__button-right')
btnLeft.addEventListener('click', prevSection)
btnRight.addEventListener('click', nextSection)
carousel.addEventListener('transitionend', () => {
if (current === carouselLen + 1) {
current = 1
} else if (current === 0) {
current = carouselLen
}
carousel.classList.add('no-transition')
carousel.style.transform = `translateX(${-current * 100}%)`
setTimeout(() => {
carousel.classList.remove('no-transition')
isAnimation = false
}, 20)
})
function handleKeyDown(event) {
if (isAnimation) return
if (event.key === 'ArrowLeft') {
prevSection()
} else if (event.key === 'ArrowRight') {
nextSection()
}
}
document.addEventListener('keydown', handleKeyDown)
元記事を表示する