<div class="modal-01__thumb js-modal-01" data-target="modal-target-01"><img src="https://picsum.photos/id/1000/400/200" width="400" height="200" /><span class="modal-01__thumb-icon"></span></div>
<div class="modal-01" id="modal-target-01">
<div class="modal-01__bg"></div>
<div class="modal-01__content">
<div class="modal-01__head">
<div class="modal-01__heading">見出しが入ります</div>
</div>
<div class="modal-01__body">
<div class="modal-01__text">テキストが入ります。テキストが入ります。テキストが入ります。テキストが入ります。テキストが入ります。テキストが入ります。テキストが入ります。</div>
<div class="modal-01__img"><img src="https://picsum.photos/id/1000/400/200" width="400" height="200" /></div>
</div><a class="modal-01__close"></a>
</div>
</div>
.modal-01__thumb.js-modal-01(data-target='modal-target-01')
img(src=img, width=width, height=height)
span.modal-01__thumb-icon
.modal-01#modal-target-01
.modal-01__bg
.modal-01__content
.modal-01__head
.modal-01__heading #{ heading }
.modal-01__body
.modal-01__text #{ text }
.modal-01__img
img(src=img, width=width, height=height)
a.modal-01__close
{
"heading": "見出しが入ります",
"text": "テキストが入ります。テキストが入ります。テキストが入ります。テキストが入ります。テキストが入ります。テキストが入ります。テキストが入ります。",
"img": "https://picsum.photos/id/1000/400/200",
"width": 400,
"height": 200
}
$BLOCK_NAME: '.modal-01';
// 変数
$color_primary: #43ceb2;
$color_white: #fff;
$color_gray: #ddd;
$scrollbar_width: 8px;
@mixin scrollbar() {
padding-right: $scrollbar_width;
margin-right: -$scrollbar_width;
&::-webkit-scrollbar {
-webkit-appearance: none;
}
&::-webkit-scrollbar-thumb {
background-color: $color_primary;
border: 0;
border-radius: $scrollbar_width / 2;
}
&::-webkit-scrollbar-track {
background: $color_gray;
border-radius: $scrollbar_width / 2;
}
&::-webkit-scrollbar:vertical {
width: $scrollbar_width;
}
}
#{ $BLOCK_NAME } {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 9999;
display: none;
align-items: center;
justify-content: center;
font-family: '游ゴシック体', YuGothic, '游ゴシック', 'Yu Gothic',
'Hiragino Kaku Gothic Pro', 'ヒラギノ角ゴ Pro W3', Meiryo, メイリオ,
sans-serif;
&.is-active {
display: flex;
}
&__bg {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
background: rgba(0, 0, 0, 0.7);
}
&__content {
position: relative;
z-index: 1;
display: flex;
flex-direction: column;
width: 800px;
max-width: calc(100% - 24px);
max-height: calc(100% - 24px);
padding: 72px 72px 60px;
background: $color_white;
border-radius: 24px;
}
&__head {
position: relative;
flex-shrink: 0;
}
&__heading {
font-size: 20px;
font-weight: bold;
}
&__body {
@include scrollbar();
margin-top: 24px;
overflow: auto;
}
&__img {
margin: 36px auto 0;
text-align: center;
}
&__close {
position: absolute;
top: 24px;
right: 24px;
width: 28px;
height: 28px;
cursor: pointer;
transition: all 0.5s;
&:hover {
transform: scale(1.1);
}
&::before,
&::after {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
width: 3px;
margin: auto;
content: '';
background: $color_primary;
}
&::before {
transform: rotate(45deg);
}
&::after {
transform: rotate(-45deg);
}
}
&__thumb {
position: relative;
width: 400px;
cursor: pointer;
}
&__thumb-icon {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
width: 120px;
height: 120px;
margin: auto;
background: rgba(0, 0, 0, 0.7);
border-radius: 50%;
transition: transform 0.3s;
@at-root #{ $BLOCK_NAME }__thumb:hover & {
transform: scale(1.1);
}
&::before,
&::after {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
margin: auto;
content: '';
background: $color_primary;
transition: transform 0.3s;
@at-root #{ $BLOCK_NAME }__thumb:hover & {
transform: rotate(180deg);
}
}
&::before {
width: 28px;
height: 4px;
}
&::after {
width: 4px;
height: 28px;
}
}
}
'use strict';
export const modal01 = () => {
const modalEls = document.querySelectorAll('.js-modal-01');
[...modalEls].forEach(el => {
const modal = new Modal01(<HTMLElement>el);
modal.init();
});
}
class Modal01 {
el: HTMLElement;
modalEl: HTMLElement;
bgEl: HTMLElement;
closeEl: HTMLElement;
constructor(el: HTMLElement) {
this.el = el;
if (!this.el) return;
const targetId = this.el.dataset.target;
this.modalEl = document.getElementById(targetId);
this.bgEl = this.modalEl.querySelector('.modal-01__bg');
this.closeEl = this.modalEl.querySelector('.modal-01__close');
}
/**
* 初期化
*/
init(): void {
if (!this.el) return;
this.onClickOpenHandler();
this.onClickCloseHandler();
this.onClickBgHandler();
}
/**
* ウインドウ固定
*/
fixWindow(): void {
const scrollBarWidth = window.innerWidth - document.body.clientWidth;
document.body.style.paddingRight = `${scrollBarWidth}px`;
document.documentElement.style.overflow = 'hidden';
}
/**
* ウインドウ固定を解除
*/
clearWindow(): void {
document.body.style.paddingRight = null;
document.documentElement.style.overflow = null;
}
/**
* モーダルを開く
*/
open(): void {
this.fixWindow();
this.modalEl.classList.add('is-active');
}
/**
* モーダルを閉じる
*/
close(): void {
this.modalEl.classList.remove('is-active');
this.clearWindow();
}
/**
* 開く要素クリック時の挙動
*/
onClickOpenHandler(): void {
this.el.addEventListener('click', e => {
e.preventDefault();
this.open();
});
}
/**
* 閉じるボタンクリック時の挙動
*/
onClickCloseHandler(): void {
this.closeEl.addEventListener('click', e => {
e.preventDefault();
this.close();
});
}
/**
* 背景クリック時の挙動
*/
onClickBgHandler(): void {
this.bgEl.addEventListener('click', e => {
e.preventDefault();
this.close();
});
}
}