<ul class="carousel-03" id="js-carousel-03">
<li class="carousel-03__item-wrapper"><a class="carousel-03__item" href="#">
<div class="carousel-03__bg" style="background-image: url(https://picsum.photos/id/1000/800/400)"></div>
<div class="carousel-03__text">
<h2 class="carousel-03__title"><span>TITLE1</span></h2><br />
<p class="carousel-03__catch"><span>テキストが入ります。テキストが入ります。テキストが入ります。テキストが入ります。</span></p>
</div>
</a></li>
<li class="carousel-03__item-wrapper"><a class="carousel-03__item" href="#">
<div class="carousel-03__bg" style="background-image: url(https://picsum.photos/id/1001/800/400)"></div>
<div class="carousel-03__text">
<h2 class="carousel-03__title"><span>TITLE2</span></h2><br />
<p class="carousel-03__catch"><span>テキストが入ります。テキストが入ります。テキストが入ります。テキストが入ります。</span></p>
</div>
</a></li>
<li class="carousel-03__item-wrapper"><a class="carousel-03__item" href="#">
<div class="carousel-03__bg" style="background-image: url(https://picsum.photos/id/1002/800/400)"></div>
<div class="carousel-03__text">
<h2 class="carousel-03__title"><span>TITLE3</span></h2><br />
<p class="carousel-03__catch"><span>テキストが入ります。テキストが入ります。テキストが入ります。テキストが入ります。</span></p>
</div>
</a></li>
</ul>
ul.carousel-03#js-carousel-03
each item in carouselItems
li.carousel-03__item-wrapper
a.carousel-03__item(href=item.link)
div.carousel-03__bg(style='background-image: url(' + item.img + ')')
div.carousel-03__text
h2.carousel-03__title
span #{ item.title }
br
p.carousel-03__catch
span #{ item.catch }
{
"carouselItems": [
{
"link": "#",
"img": "https://picsum.photos/id/1000/800/400",
"title": "TITLE1",
"catch": "テキストが入ります。テキストが入ります。テキストが入ります。テキストが入ります。"
},
{
"link": "#",
"img": "https://picsum.photos/id/1001/800/400",
"title": "TITLE2",
"catch": "テキストが入ります。テキストが入ります。テキストが入ります。テキストが入ります。"
},
{
"link": "#",
"img": "https://picsum.photos/id/1002/800/400",
"title": "TITLE3",
"catch": "テキストが入ります。テキストが入ります。テキストが入ります。テキストが入ります。"
}
]
}
$BLOCK_NAME: '.carousel-03';
// 変数
$color_primary: #d31619;
$color_white: #fff;
$duration_default: 1s;
$easing_default: cubic-bezier(0.55, 0.05, 0.22, 0.99);
@mixin clipTransition($delay: 0) {
clip-path: polygon(0 0, 0 0, 0 100%, 0 100%);
transition: clip-path $duration_default $easing_default #{$delay + 's'};
transform: translateZ(0);
will-change: clip-path;
@at-root #{ $BLOCK_NAME }__item-wrapper.is-current & {
clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%);
}
@at-root #{ $BLOCK_NAME }__item-wrapper.is-next & {
clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%);
}
}
#{ $BLOCK_NAME } {
position: relative;
width: 100%;
height: calc(100vh - 32px);
&__item-wrapper {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
overflow: hidden;
clip-path: polygon(100% 0, 100% 0, 100% 100%, 100% 100%);
transition: clip-path $duration_default ease 0s;
transform: translateZ(0);
&.is-current,
&.is-next {
clip-path: polygon(100% 0, 0 0, 0 100%, 100% 100%);
}
&.is-next {
z-index: 2;
&.is-current {
z-index: 1;
}
}
}
&__item {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
display: block;
}
&__bg {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-repeat: no-repeat;
background-position: center center;
background-size: cover;
transition: transform 5s 0s;
@at-root #{ $BLOCK_NAME }__item-wrapper.is-active & {
transform: scale(1.1);
}
@at-root #{ $BLOCK_NAME }__item-wrapper.is-next & {
transform: scale(1.1);
}
}
&__text {
position: absolute;
bottom: 100px;
left: 100px;
z-index: 1;
}
&__title {
position: relative;
display: inline-block;
padding: 10px;
font-size: 24px;
color: $color_white;
@include clipTransition(1);
&::before {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: -1;
content: '';
background: $color_primary;
}
& > span {
@include clipTransition(2);
}
}
&__catch {
position: relative;
display: inline-block;
padding: 10px;
font-size: 18px;
color: $color_primary;
@include clipTransition(1);
&::before {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: -1;
content: '';
background: $color_white;
}
& > span {
@include clipTransition(2);
}
}
}
'use strict';
export const carousel03 = () => {
const carousel = new Carousel03('js-carousel-03');
carousel.init();
}
class Carousel03 {
el: HTMLElement;
itemEls: NodeListOf<HTMLElement>;
currentIndex: number;
slideTime: number;
loadedImg: number;
constructor(elId: string) {
this.el = document.getElementById(elId);
if (!this.el) return;
this.itemEls = this.el.querySelectorAll('.carousel-03__item-wrapper');
this.loadedImg = 0;
this.currentIndex = 0;
this.slideTime = 4000;
}
/**
* 初期化
*/
init(): void {
if (!this.el) return;
this.loadingHandler();
}
/**
* スライド
* @param first 初期表示であるか
*/
slide(first: Boolean = false): void {
[...this.itemEls].forEach(el => {
if (el.classList.contains('is-current')) {
el.classList.remove('is-current');
el.classList.remove('is-next');
}
});
let current;
if (first) {
current = this.itemEls.length - 1;
} else {
current = this.currentIndex;
}
const next = current >= this.itemEls.length - 1 ? 0 : current + 1;
const currentEl = this.itemEls[current];
const nextEl = this.itemEls[next];
currentEl.classList.add('is-current');
nextEl.classList.add('is-next');
// 次のスライドをアニメーションさせる
setTimeout(() => {
this.currentIndex = next;
this.slide();
}, this.slideTime);
}
/**
* 画像読み込み完了時の処理
*/
loadingHandler(): void {
[...this.itemEls].forEach(el => {
const bgEl = <HTMLElement>el.querySelector('.carousel-03__bg');
// 背景要素から画像URLを取得
const url = bgEl.style.backgroundImage.replace(/^url\(["']?/, '').replace(/["']?\)$/, '');
const img = new Image();
img.addEventListener('load', () => {
this.loadedImg++;
this.startSlide();
});
img.src = url;
});
}
/**
* スライドの開始
*/
startSlide(): void {
// 全ての画像の読み込みが完了していない場合、処理を終了
if (this.loadedImg !== this.itemEls.length) return;
this.slide(true);
}
}