Blog スタッフブログ

【JavaScript】テキストを一文字ずつアニメーションさせるボタンを実装する

Category | Blog
/ 1,475views

こんにちは、CTOの奥田です。
最近は、完全にインドアな私が周りの人の影響でキャンプにはまっています。
キャンプ用品の沼はなかなかの深さで当分抜け出せそうにありません。
冬にソロキャンに行けるように今からソロキャン用品をちょっとずつ揃えていこうと思います。

さて、今回は「テキストを一文字ずつアニメーションさせるボタン」を実装してみたいと思います。

Table of contents

  1. 今回やりたいこと
  2. 要素の準備をする
  3. 1文字ずつ分割する
  4. アニメーションさせる
  5. さいごに

今回やりたいこと

今回やりたいことはこちら。
ボタンにマウスを乗せるとテキストが一文字ずつアニメーションするエフェクトを実装してみたいと思います。
アニメーションにはanime.jsを使用していますが、その他のアニメーション系ライブラリでも同様のことが可能です。

See the Pen
Button Animation
by Mineo (@min30327)
on CodePen.

要素の準備をする

まずは要素を準備します。
ボタンの文字が英語の場合、翻訳をした際に表示がおかしくなるので、translate=”no”を入れたり、文字を分割してしまうので、アクセシビリティを考慮してaria-labelを入れてあげるといいでしょう。

<button class="c-button" aria-label="ホバーしたらアニメーションするボタン" translate="no" data-button-animation>
    <span data-str-animation>Button Animation</span>
</button>

CSSは通常のスタイリングですが、[data-str-animation]内に一文字ずつspanで文字が入るため、display:flexで横並びにしています。
.js-str__animation(一文字ずつを囲っている要素のクラス)は単語間に半角スペースがあった際にスペースが無くなってしまうため、min-widthを入れて余白を調節しています。

[data-button-animation]{
    padding: 14px 30px;
    border-radius:4px;
    margin-bottom: 5px;
    background: #201f1c;
    color: #fff;
    font-size: 1rem;
    display: inline-block;
    transition:box-shadow .4s cubic-bezier(0.165, 0.840, 0.440, 1.000);
    &:focus,&:active{
        box-shadow:0 0 0 3px rgba(0,0,0,.2);
    }
    [data-str-animation]{
        display: flex;
        overflow: hidden;
    }
    .js-str__animation{
        min-width:.3rem;
    }
}

1文字ずつ分割する

次に文字を一文字ずつ分割して要素に入れ直す処理を書きます。
今回はES6の記法で書いているためレガシーブラウザに対応させるためにはトランスパイルが必要です。
ページ内のすべてのアニメーションさせたい要素に適応させるためquerySelectorAllで取得し、forEachでループしています。

class ButtonAnimation{

    constructor(){
        this.init()
    }
    init (){
        const strs = document.querySelectorAll("[data-str-animation]")
        if(strs.length > 0){
            strs.forEach((el)=>{
                const default_str = el.textContent.split("");
                let str = "";
                default_str.forEach( s => {
                    str += "<span class='js-str__animation'>" + s  + "</span>";
                })
                
                el.innerHTML = str;
            })
        }
    }
}
document.addEventListener('DOMContentLoaded',new ButtonAnimation)

アニメーションさせる

最後に要素をアニメーションさせます。
mouseenterイベントにバインドすることでマウスが乗った際の挙動を制御できます。
translateY:[0,”100%”]で文字が上に消えていき、complete内で translateY: [“100%”,0] をすることで下から出てきます。
ちょっとずつ文字がずれて動いている箇所はdelayプロパティで0.02秒ずつ遅延させています。
easingは”easeInExpo”から”easeOutQuart”で戻ってくるようにするとなめらかな動きになります。
これでアニメーションの実装が完成です。

mouseEnter(){
    const buttons = document.querySelectorAll("[data-button-animation]")
    if(buttons.length > 0){
        buttons.forEach( (button,i) => {
            let isEntered = false
            button.addEventListener("mouseenter",() => {
                if(isEntered) return
                isEntered = true
                const t = button.querySelectorAll('.js-str__animation')
                anime({
                targets :t,
                translateY: [0,"-100%"],
                easing: "easeInExpo",
                delay: function(el, i) {
                    return (i * 20);
                },
                duration:400,
                complete(){
                    anime({
                    targets :t,
                    translateY: ["100%",0],
                    easing: "easeOutQuart",
                    delay: function(el, i) {
                        return (i * 20);
                    },
                    duration:400,
                    complete: () =>{
                        isEntered = false
                    }
                    })
                }
                })
            })
        })

    }
}

さいごに

今回はちょっとしたエフェクトですが簡単そうに見えて意外と難しいアニメーションを実装してみました。
ぜひ、Webサイトに遊び心をプラスしてあげてください。
この記事が少しでも皆様の参考になれば幸いです。

Category | Blog
Author | Mineo Okuda / 1,475views

Company information

〒650-0024
神戸市中央区海岸通5 商船三井ビルディング4F

Contact us

WEBに関するお問い合わせは
078-977-8760 (10:00 - 18:00)