ヒーロー カルーセル

設計
- 写真数の増減に対応してスライダー数も対応
- 最終画面で3秒後にコピーを表示、さらに7秒後にコピーを消去して、アニメーションも停止
- レスポンシブでレイアウトを変える
HTML
<div class="slider-container">
<div class="slides">
<div class="slide"></div>
<div class="slide"></div>
<div class="slide"></div>
<div class="slide"></div>
<div class="slide"></div>
<div class="slide copy">最終コピー<br />表示エリア</div>
</div>
<div class="slider-nav">
<button class="nav-btn prev-btn"></button>
<button class="nav-btn next-btn"></button>
<div class="dots-nav"></div>
</div>
<div class="slides_info">
<div class="logo">
<h1>h1 hide</h1>
</div>
<div class="case">NO</div>
<div class="name">顧客</div>
<div class="add">address</div>
<div class="data data-num">Data</div>
</div>
</div>
JavaScript
<script>
document.addEventListener("DOMContentLoaded", () => {
const photoSlides = document.querySelectorAll(".slide:not(.copy)");
const copySlide = document.querySelector(".slide.copy");
const dotsNav = document.querySelector(".dots-nav");
const prevBtn = document.querySelector(".prev-btn");
const nextBtn = document.querySelector(".next-btn");
if (photoSlides.length === 0) return;
let currentIndex = 0;
let slideTimeout;
let copyTimeout;
const photoIntervalTime = 3000; // 写真の遷移間隔3秒
photoSlides.forEach((_, index) => {
const dot = document.createElement("div");
dot.classList.add("dot");
if (index === 0) dot.classList.add("active");
dot.addEventListener("click", () => {
goToSlide(index);
});
dotsNav.appendChild(dot);
});
const dots = document.querySelectorAll(".dot");
function goToSlide(index, isAuto = false) {
clearAllTimers();
photoSlides[currentIndex].classList.remove("active");
dots[currentIndex].classList.remove("active");
if (copySlide) copySlide.classList.remove("active");
if (index >= photoSlides.length) {
currentIndex = 0;
} else if (index < 0) {
currentIndex = photoSlides.length - 1;
} else {
currentIndex = index;
}
photoSlides[currentIndex].classList.add("active");
dots[currentIndex].classList.add("active");
if (currentIndex === photoSlides.length - 1) {
if (copySlide) {
// 3秒後に .copy を表示
copyTimeout = setTimeout(() => {
copySlide.classList.add("active");
// +7秒後に .copy を消去して、アニメーションを停止
copyTimeout = setTimeout(() => {
copySlide.classList.remove("active");
}, 7000);
}, 1000);
}
} else {
slideTimeout = setTimeout(() => {
goToSlide(currentIndex + 1, true);
}, photoIntervalTime);
}
}
function clearAllTimers() {
clearTimeout(slideTimeout);
clearTimeout(copyTimeout);
}
prevBtn.addEventListener("click", () => goToSlide(currentIndex - 1));
nextBtn.addEventListener("click", () => goToSlide(currentIndex + 1));
photoSlides[0].classList.add("active");
slideTimeout = setTimeout(() => {
goToSlide(currentIndex + 1, true);
}, photoIntervalTime);
});
</script>
CSS
.slider-container {
background-color: #fff;
@media (737px < width) {
position: relative;
width: 100%;
aspect-ratio: 1.774;
object-fit: contain;
overflow: hidden;
max-height: 100dvh;
}
& .slides {
width: 100%;
aspect-ratio: 1.774;
object-fit: contain;
}
& .slide {
position: absolute;
color: #fff;
top: 0;
left: 0;
width: 100%;
opacity: 0;
z-index: 1;
transition: opacity 0.8s ease-in-out;
aspect-ratio: 1.774;
object-fit: contain;
@media (737px < width) {
height: 100%;
}
&.active {
opacity: 1;
z-index: 2;
}
}
& .slide.copy {
z-index: 3;
display: grid;
place-content: center;
text-align: center;
font-weight: 700;
pointer-events: none;
transition: all 1s;
line-height: 3;
@media (737px < width) {
font-size: calc(1.96em + ((1vw - 7.67px) * 1.9));
}
@media (736px >= width) {
font-size: clamp(18px, 5.600007vw, 25px);
line-height: 1.6;
letter-spacing: 0.05em;
aspect-ratio: 1.774;
object-fit: contain;
line-height: 4;
}
&.active {
z-index: 2;
animation-name: slide_copies;
animation-duration: 7.2s;
}
}
& .nav-btn {
z-index: 10;
color: #fff;
border: none;
cursor: pointer;
background-color: rgba(0, 0, 0, 0.5);
@media (737px < width) {
transition: background-color 0.5s;
}
&:after {
content: "";
display: inline-block;
background-color: #fff;
z-index: 3;
transition:
background-color 0.3s ease-in-out,
translate 0.3s ease-in-out;
}
@media (737px < width) {
position: absolute;
top: 50%;
transform: translateY(-50%);
padding: 10px 1em;
&:after {
height: 16px;
width: 12px;
}
@media (any-hover: hover) {
&:hover {
background-color: rgba(0, 28, 209, 0.8);
}
}
}
@media (736px >= width) {
padding: 0.5em 1em;
&:after {
height: 12px;
width: 8px;
}
}
}
& .slider-nav {
@media (736px >= width) {
display: flex;
justify-content: space-between;
align-items: center;
background-color: #000;
& .prev-btn {
order: 1;
}
& .next-btn {
order: 3;
}
& .dots-nav {
order: 2;
flex-wrap: wrap;
justify-content: center;
}
}
}
& .prev-btn {
@media (737px < width) {
left: 0;
}
&:after {
clip-path: polygon(0 50%, 100% 0, 100% 100%);
translate: -2px 0;
@media (736px >= width) {
translate: -2px 2px;
}
}
@media (any-hover: hover) {
&:hover {
&:after {
translate: -6px 0;
}
}
}
}
& .next-btn {
@media (737px < width) {
right: 0;
}
&:after {
clip-path: polygon(0 0, 100% 50%, 0 100%);
translate: 2px 0;
@media (736px >= width) {
translate: 2px 2px;
}
}
@media (any-hover: hover) {
&:hover {
&:after {
translate: 6px 0;
}
}
}
}
& .dots-nav {
z-index: 7;
display: flex;
@media (737px < width) {
position: absolute;
bottom: 15px;
left: 50%;
transform: translateX(-50%);
gap: 10px;
}
@media (736px >= width) {
gap: 5px;
}
& .dot {
background-color: rgba(255, 255, 255, 0.5);
cursor: pointer;
@media (737px < width) {
width: 24px;
height: 7px;
border-radius: 10vw;
transition: background-color 0.3s;
}
@media (736px >= width) {
width: 20px;
height: 5px;
border-radius: 0;
}
&:hover {
background-color: rgba(0, 28, 209, 0.5);
}
&.active {
background-color: #ffffff;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.5);
pointer-events: none;
}
@media (736px >= width) {
background-color: #595a69;
}
}
}
& .slides_info {
z-index: 5;
color: #fff;
letter-spacing: 0.06em;
@media (737px < width) {
position: absolute;
padding: 1em;
bottom: 1.3em;
left: 1em;
display: grid;
grid-template-columns: repeat(2, auto);
grid-template-rows: repeat(3, auto);
grid-column-gap: 20px;
}
@media (736px >= width) {
position: relative;
text-align: center;
padding-bottom: 1rem;
&::before,
&::after {
position: absolute;
content: "";
display: inline-block;
border-bottom: solid 1px #000;
top: -1px;
width: 2em;
}
&::before {
left: 0;
}
&::after {
right: 0;
}
}
& .case {
color: #111;
background-color: #ffffffaa;
display: flex;
justify-content: center;
align-items: center;
filter: invert();
backdrop-filter: blur(5px);
grid-area: 1 / 1 / 4 / 2;
@media (737px < width) {
padding: 1rem;
font-size: 22px;
}
&::before {
content: "Photo";
text-align: center;
font-size: 13px;
margin: 8px 6px 0 0;
}
@media (736px >= width) {
font-size: clamp(15.48px, 4.800006vw, 21.6px);
padding: 0 0 0.5rem;
&::before {
font-size: 12px;
margin: 5px 5px 0 0;
}
}
}
& .name {
line-height: 1.2;
font-weight: 900;
opacity: 1;
translate: 0 0;
transition:
opacity 0.6s ease-in-out,
translate 0.6s ease-in-out;
@media (737px < width) {
font-size: 24px;
border-bottom: 2px solid rgba(230, 109, 38, 1);
padding: 0 5px 6px 0px;
text-shadow: 0px 0px 5px #000;
}
grid-area: 1 / 2 / 2 / 3;
&::after {
content: "\69D8";
margin-left: 6px;
font-size: 0.8em;
}
@media (736px >= width) {
color: #000;
font-size: clamp(19.78px, 6.133341vw, 27.6px);
display: flex;
align-items: center;
justify-content: center;
padding: 1rem 1rem 0;
}
@starting-style {
opacity: 0;
translate: 0 10px;
}
}
& .add {
opacity: 0.9;
translate: 0 0;
transition:
opacity 0.6s ease-in-out 0.5s,
translate 0.6s ease-in-out 0.5s;
@media (737px < width) {
font-size: 13px;
padding: 4px 0 5px 2px;
text-shadow: 0px 0px 3px #000;
}
grid-area: 2 / 2 / 3 / 3;
@media (736px >= width) {
font-size: clamp(10.32px, 3.200004vw, 14.4px);
color: #444;
margin-top: 0.1em;
}
@starting-style {
opacity: 0;
translate: 0 8px;
}
}
& .data {
line-height: 0;
opacity: 1;
display: flex;
align-items: baseline;
translate: 0 0;
transition:
opacity 0.6s ease-in-out 1s,
translate 0.6s ease-in-out 1s;
@media (737px < width) {
text-shadow: 0px 0px 5px #000;
margin-top: 0.2em;
grid-area: 3 / 2 / 4 / 3;
}
@media (736px >= width) {
margin-top: 0.7em;
color: #000;
justify-content: center;
}
@starting-style {
opacity: 0;
translate: 0 10px;
}
& .large-num {
font-size: 1.5em;
margin-inline: 0.15em;
translate: 0 1px;
@media (736px >= width) {
font-size: 1.25em;
}
}
&::before {
content: "info";
color: #fff;
margin-right: 10px;
font-size: 13px;
line-height: 1.5;
padding: 0 5px 0 8px;
background: rgba(34, 67, 216, 0.8);
text-shadow: none;
display: inline-flex;
position: relative;
top: -1px;
left: 0;
@media (736px >= width) {
font-size: 12px;
}
}
}
& h1 {
display: none;
}
}
}
@keyframes slide_copies {
0% {
translate: 0 0.5em;
opacity: 0;
}
15% {
translate: 0 0;
opacity: 1;
}
85% {
translate: 0 0;
opacity: 1;
}
100% {
translate: 0 -0.5em;
opacity: 0;
}
}

