むにゅっと出てくるボタン
概要
スクロールでボタンが画面に入ったら、アニメーションが動き出すようにしています。
ボタンが円の状態から拡大縮小し、横にむにゅっと広がることで、リズム感のある動きになっております。ボタンの横幅はmax-width
で制御しており、幅を指定することで広がるときにもむにゅっとなるようにしております。
かなり文章が長いボタンとなると、このmax-width
をもっと大きく設定してあげる必要があります。
コードサンプル
HTML
<div class="btn-wrap js-scroll-anim">
<a class="btn">
<span class="btn-text">Button</span>
<span class="btn-icon"></span>
</a>
</div>
CSS
.btn-wrap {
/* アニメーション */
--icon-duration: 1s;
/* 色 */
--btn-color: #F4F5F9;
--border-color: #7d8797;
--icon-color: #08254f;
--font-color: #333333;
/* 文字の大きさ */
font-size: 1rem;
}
.btn {
position: relative;
background-color: var(--btn-color);
box-shadow: 0 0 0 0.1em var(--border-color);
border-radius: 1em;
max-width: 2em;
height: 2em;
display: inline-flex;
justify-content: center;
align-items: center;
line-height: 1;
column-gap: 0.5em;
will-change: max-width;
}
.btn-text {
margin-inline: 1em 2em;
color: var(--font-color);
white-space: nowrap;
opacity: 0;
will-change: opacity;
}
.btn-icon {
position: absolute;
inset-inline-end: 0.5em;
display: block;
margin: auto;
width: 1em;
aspect-ratio: 1 / 1;
background-color: var(--icon-color);
border-radius: 50%;
transform-origin: center center;
will-change: width, height;
z-index: -1;
}
.btn-icon::before,
.btn-icon::after {
position: absolute;
inset: 0;
display: block;
margin: auto;
content: "";
background-color: #f4f5f9;
z-index: 1;
}
.btn-icon::before {
width: 65%;
height: 2px;
}
.btn-icon::after {
width: 2px;
height: 65%;
}
.btn-wrap.is-active {
.btn {
animation: btn-expand 0.5s ease-in-out;
animation-delay: var(--icon-duration);
animation-fill-mode: forwards;
}
.btn-text {
animation: btn-text 0.5s;
animation-delay: calc(var(--icon-duration) + 0.25s);
animation-fill-mode: forwards;
}
.btn-icon {
animation: icon var(--icon-duration) ease-in-out;
animation-fill-mode: forwards;
}
}
@keyframes icon {
0% {
scale: 1.3;
z-index: -1;
}
50% {
scale: 2.8;
z-index: -1;
}
100% {
scale: 1.3;
z-index: 1;
}
}
@keyframes btn-expand {
0% {
max-width: 2em;
}
100% {
max-width: 10em;
}
}
@keyframes btn-text {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
JavaScript
document.addEventListener("DOMContentLoaded", function () {
const scrollTriggers = document.querySelectorAll(".js-scroll-anim");
const revealObserver = new IntersectionObserver(
entries => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add("is-active");
revealObserver.unobserve(entry.target);
}
});
},
{
threshold: 0.1,
}
);
scrollTriggers.forEach(el => {
revealObserver.observe(el);
});
});