<div class="accordion-01 js-accordion-01">
<div class="accordion-01__head">
<p class="accordion-01__sub-heading"><span>ACCORDION 01-1</span></p>
<h3 class="accordion-01__heading">アコーディオン 01-1</h3>
<div class="accordion-01__icon"></div>
</div>
<div class="accordion-01__content-wrapper">
<div class="accordion-01__content">テキストが入ります。テキストが入ります。テキストが入ります。テキストが入ります。テキストが入ります。テキストが入ります。テキストが入ります。</div>
</div>
</div>
<div class="accordion-01 js-accordion-01">
<div class="accordion-01__head">
<p class="accordion-01__sub-heading"><span>ACCORDION 01-2</span></p>
<h3 class="accordion-01__heading">アコーディオン 01-2</h3>
<div class="accordion-01__icon"></div>
</div>
<div class="accordion-01__content-wrapper">
<div class="accordion-01__content">テキストが入ります。テキストが入ります。テキストが入ります。テキストが入ります。テキストが入ります。テキストが入ります。テキストが入ります。</div>
</div>
</div>
each accordion in accordionItems
.accordion-01.js-accordion-01
.accordion-01__head
p.accordion-01__sub-heading
span #{ accordion.subHeading }
h3.accordion-01__heading #{ accordion.heading }
.accordion-01__icon
.accordion-01__content-wrapper
.accordion-01__content #{ accordion.content }
{
"accordionItems": [
{
"subHeading": "ACCORDION 01-1",
"heading": "アコーディオン 01-1",
"content": "テキストが入ります。テキストが入ります。テキストが入ります。テキストが入ります。テキストが入ります。テキストが入ります。テキストが入ります。"
},
{
"subHeading": "ACCORDION 01-2",
"heading": "アコーディオン 01-2",
"content": "テキストが入ります。テキストが入ります。テキストが入ります。テキストが入ります。テキストが入ります。テキストが入ります。テキストが入ります。"
}
]
}
$BLOCK_NAME: '.accordion-01';
// 変数
$color_primary: #e60000;
$color_black: #272727;
$color_gray: #8e8e8e;
$duration_default: 0.6s;
$easing_default: cubic-bezier(0.23, 1, 0.32, 1);
#{ $BLOCK_NAME } {
padding: 0 16px;
font-family: 'Noto Sans JP', sans-serif;
border-bottom: 1px solid $color_black;
&:nth-of-type(1) {
border-top: 1px solid $color_black;
}
&__head {
position: relative;
padding: 20px 0;
cursor: pointer;
}
&__sub-heading {
font-size: 36px;
font-weight: 500;
line-height: 1;
& > span {
display: inline-block;
background: linear-gradient(
to right,
$color_black 0%,
$color_black 50%,
$color_primary 50%,
$color_primary 100%
);
background-position: 200% 0;
-webkit-background-clip: text;
background-size: 200% 100%;
animation: accordion01TextMaskOut $duration_default $easing_default
forwards;
-webkit-text-fill-color: transparent;
@at-root #{ $BLOCK_NAME }:hover & {
animation: accordion01TextMask $duration_default $easing_default
forwards;
}
@at-root #{ $BLOCK_NAME }.is-open & {
animation: accordion01TextMask $duration_default $easing_default
forwards;
}
}
}
&__heading {
margin-top: 8px;
font-size: 14px;
color: $color_gray;
}
&__icon {
position: absolute;
top: 0;
right: 0;
bottom: 0;
display: block;
width: 26px;
height: 26px;
margin: auto;
content: '';
&::before,
&::after {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
display: block;
height: 3px;
margin: auto;
content: '';
background: #000;
transition: background-color 0.3s;
@at-root #{ $BLOCK_NAME }:hover & {
background: $color_primary;
}
}
&::after {
transition: all 0.3s;
transform: rotate(90deg);
@at-root #{ $BLOCK_NAME }.is-open & {
background: $color_primary;
transform: rotate(0);
}
}
}
&__content-wrapper {
height: 0;
overflow: hidden;
}
&__content {
padding-bottom: 16px;
opacity: 0;
transition: all 0.3s;
transform: translateY(4px);
@at-root #{ $BLOCK_NAME }.is-open & {
opacity: 1;
transition-delay: 0.5s;
transform: translateY(0);
}
}
}
@keyframes accordion01TextMask {
0% {
background-position: 200% 0;
}
to {
background-position: 100% 0;
}
}
@keyframes accordion01TextMaskOut {
0% {
background-position: 100% 0;
}
to {
background-position: 0 0;
}
}
'use strict';
import { gsap } from 'gsap';
export function accordion01() {
const elList = document.getElementsByClassName('js-accordion-01');
[...elList].forEach(el => {
const accordion = new Accordion01(<HTMLElement>el);
accordion.init();
})
}
class Accordion01 {
el: HTMLElement;
headEl: HTMLElement;
contentEl: HTMLElement;
isOpen: Boolean;
isRunning: Boolean;
speed: number; // second
cssAnimSpeed: number; // millisecond
constructor(accordionEl: HTMLElement) {
this.el = accordionEl;
this.headEl = this.el.querySelector('.accordion-01__head');
this.contentEl = this.el.querySelector('.accordion-01__content-wrapper');
this.isOpen = false;
this.isRunning = false;
this.speed = .5;
this.cssAnimSpeed = 300;
}
/**
* Initialize accordion script
*/
init(): void {
this.onHeadClick();
}
/**
* Open accordion content
*/
openContent(): void {
// In animation, end the process
if (this.isRunning) return;
// Open accordion content
const self = this;
this.isRunning = true;
self.el.classList.add('is-open');
gsap.to(this.contentEl, {
duration: this.speed,
height: 'auto',
onComplete() {
self.isOpen = true;
self.isRunning = false;
}
});
}
/**
* Close accordion content
*/
closeContent(): void {
// In animation, end the process
if (this.isRunning) return;
// Close accordion after CSS animation
const self = this;
this.isRunning = true;
this.el.classList.remove('is-open');
setTimeout(() => {
gsap.to(this.contentEl, {
duration: this.speed,
height: 0,
onComplete() {
self.isOpen = false;
self.isRunning = false;
}
});
}, this.cssAnimSpeed);
}
/**
* Toggle accordion content
*/
toggleContent(): void {
if (this.isOpen) {
this.closeContent();
} else {
this.openContent();
}
}
/**
* Behavior settings when the heading is clicked
*/
onHeadClick(): void {
this.el.addEventListener('click', () => {
this.toggleContent();
});
}
}