<ul class="card-12__list">
<li><a class="card-12 js-card-12" href="#">
<div class="card-12__circle"></div>
<div class="card-12__img"><img src="https://picsum.photos/id/1000/400/200" /></div>
<p class="card-12__category">NEWS</p>
<p class="card-12__text">テキストが入ります。テキストが入ります。テキストが入ります。</p>
<p class="card-12__date">2021.01.01</p>
</a></li>
<li><a class="card-12 js-card-12" href="#">
<div class="card-12__circle"></div>
<div class="card-12__img"><img src="https://picsum.photos/id/1000/400/200" /></div>
<p class="card-12__category">NEWS</p>
<p class="card-12__text">テキストが入ります。テキストが入ります。テキストが入ります。</p>
<p class="card-12__date">2021.01.01</p>
</a></li>
<li><a class="card-12 js-card-12" href="#">
<div class="card-12__circle"></div>
<div class="card-12__img"><img src="https://picsum.photos/id/1000/400/200" /></div>
<p class="card-12__category">NEWS</p>
<p class="card-12__text">テキストが入ります。テキストが入ります。</p>
<p class="card-12__date">2021.01.01</p>
</a></li>
</ul>
ul.card-12__list
each item in items
li
a.card-12.js-card-12(href=item.link)
.card-12__circle
.card-12__img
img(src=item.img)
p.card-12__category #{ item.category }
p.card-12__text #{ item.text }
p.card-12__date #{ item.date }
{
"items": [
{
"link": "#",
"img": "https://picsum.photos/id/1000/400/200",
"category": "NEWS",
"text": "テキストが入ります。テキストが入ります。テキストが入ります。",
"date": "2021.01.01"
},
{
"link": "#",
"img": "https://picsum.photos/id/1000/400/200",
"category": "NEWS",
"text": "テキストが入ります。テキストが入ります。テキストが入ります。",
"date": "2021.01.01"
},
{
"link": "#",
"img": "https://picsum.photos/id/1000/400/200",
"category": "NEWS",
"text": "テキストが入ります。テキストが入ります。",
"date": "2021.01.01"
}
]
}
$BLOCK_NAME: '.card-12';
// 変数
$color_white: #fff;
$color_black: #000;
$duration_text: 0.4s;
$duration_circle: 1s;
#{ $BLOCK_NAME } {
&__list {
display: flex;
justify-content: space-around;
& > li {
width: 30%;
}
}
position: relative;
z-index: 1;
display: flex;
flex-direction: column;
height: 100%;
padding: 24px;
overflow: hidden;
font-family: '游ゴシック', YuGothic, 'ヒラギノ角ゴ Pro',
'Hiragino Kaku Gothic Pro', 'メイリオ', Meiryo, sans-serif;
color: $color_black;
background: $color_white;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
transition: $duration_text;
&:hover {
color: $color_white;
}
&__circle {
position: absolute;
top: 50%;
left: 50%;
z-index: -1;
width: 0;
height: 0;
content: '';
background: $color_black;
border-radius: 50%;
transition: width $duration_circle, height $duration_circle;
transform: translate3d(-50%, -50%, 0);
will-change: left, top;
@at-root #{ $BLOCK_NAME }:hover & {
width: 1000px;
height: 1000px;
}
}
&__img {
& > img {
width: 100%;
}
}
&__category {
margin-top: 8px;
font-family: 'Comfortaa', cursive;
font-size: 14px;
font-weight: 700;
text-align: right;
}
&__text {
flex-grow: 1;
margin-top: 16px;
font-size: 20px;
font-weight: 400;
}
&__date {
margin-top: 48px;
font-weight: bold;
}
}
'use strict';
export const card12 = () => {
const card = new Card12('js-card-12');
card.init();
}
class Card12 {
els: HTMLCollectionOf<Element>;
circleSelector: string;
constructor(className: string) {
this.els = document.getElementsByClassName(className);
this.circleSelector = '.card-12__circle';
}
/**
* 初期化
*/
init(): void {
if (!this.els.length) return;
this.onEnterHandler();
this.onLeaveHandler();
}
/**
* 円要素の位置設定
* @param el マウスイン/アウトした要素
* @param event イベントオブジェクト
*/
setCirclePos(el: HTMLElement, event: MouseEvent): void {
const circleEl = <HTMLElement>el.querySelector(this.circleSelector);
const clientRect = el.getBoundingClientRect();
// 要素内におけるカーソル位置を取得
const x = event.pageX - (clientRect.left + window.pageXOffset);
const y = event.pageY - (clientRect.top + window.pageYOffset);
// 要素の位置を設定
circleEl.style.left = x + 'px';
circleEl.style.top = y + 'px';
}
/**
* カーソル進入時の処理
*/
onEnterHandler(): void {
[...this.els].forEach(el => {
el.addEventListener('mouseover', e => {
this.setCirclePos(<HTMLElement>el, <MouseEvent>e);
});
});
}
/**
* カーソル退出時の処理
*/
onLeaveHandler(): void {
[...this.els].forEach(el => {
el.addEventListener('mouseout', e => {
this.setCirclePos(<HTMLElement>el, <MouseEvent>e);
});
});
}
}