【HTMLとCSSのみ】実務でよく使いそうなテキストホバーアニメーションについてまとめてみる(備忘録)

今回は、テキストリンクのホバーアニメーションについて、いろんなWebデザインギャラリーを見て、比較的多く使われているものを紹介していければと思います。

独断と偏見で選んでいること、実装方法も正攻法とは限りませんので、予めご了承ください。

なお、Webデザインギャラリーについては、定期的に見ていますので、そこで新しいテキストリンクのホバーアニメーションを発見しましたら、本記事に追加していければと考えています。

それでは実装に入っていきます。

HTMLの記述について

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta name="robots" content="index, follow" />
  <title>CSSのみでよく使いそうなテキストホバーアニメーション(備忘録)</title>
  <link rel="stylesheet" href="../reset.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main>
    <section>
      <div class="ly_inner">
        <h2>アンダーバーが左から右に伸びて左に戻る</h2>
        <div class="md_textblock">
          <p><a href="" class="el_hover01">リンクテキスト</a></p>
        </div>
      </div>
      <div class="ly_inner">
        <h2>アンダーバーが左から右に伸びて右へ進み縮小していく</h2>
        <div class="md_textblock">
          <p><a href="" class="el_hover02">リンクテキスト</a></p>
        </div>
      </div>
      <div class="ly_inner">
        <h2>アンダーバーが中央から左右に伸びていく</h2>
        <div class="md_textblock">
          <p><a href="" class="el_hover03">リンクテキスト</a></p>
        </div>
      </div>
      <div class="ly_inner">
        <h2>アンダーバーが上から下にスライドしながら現れる</h2>
        <div class="md_textblock">
          <p><a href="" class="el_hover04">リンクテキスト</a></p>
        </div>
      </div>
      <div class="ly_inner">
        <h2>テキストの色が変わる</h2>
        <div class="md_textblock">
          <p><a href="" class="el_hover05">リンクテキスト</a></p>
        </div>
      </div>
      <div class="ly_inner">
        <h2>同じテキストが下から上にスライドしてくる</h2>
        <div class="md_textblock">
          <p>
            <a href="" class="el_hover06" data-replace="リンクテキスト">
              <span>リンクテキスト</span>
            </a>
          </p>
        </div>
      </div>
      <div class="ly_inner">
        <h2>アンダーラインがグラデーションを経由する</h2>
        <div class="md_textblock">
          <p>
            <a href="" class="el_hover07">リンクテキスト</a>
          </p>
        </div>
      </div>
      <div class="ly_inner">
        <h2>1文字1文字がバラバラに点滅する</h2>
        <div class="md_textblock">
          <p>
            <a href="" class="el_hover08">
              <span>リ</span><span>ン</span><span>ク</span><span>テ</span><span>キ</span><span>ス</span><span>ト</span>
            </a>
          </p>
        </div>
      </div>
    </section>
  </main>
</html>

構造はシンプルですので、特に解説はしません。

一番最後については、文字をバラバラにしてCSSの表現をする必要があったため、spanタグで囲っております。

CSSの記述について

@charset "utf-8";

/* ==========================
  初期設定
========================== */
*,
*::before,
*::after {
  box-sizing: border-box;
}
a {
  background-color: transparent;
  text-decoration: none;
  color: inherit;
}
img {
  width: 100%;
}

/* ==========================
  コンテンツの中身
========================== */
.ly_inner {
  width: 100%;
  max-width: 1080px;
  margin: 40px auto;
  padding: 20px;
  background-color: #fff;
}
.ly_inner h2 {
  font-size: 130%;
  font-weight: bold;
  margin-bottom: 30px;
}
.md_textblock > * + * {
  margin-top: 10px;
}

/* ==========================
  アンダーバーが左から右に伸びて左に戻る
========================== */
.el_hover01 {
  position: relative;
  display: inline-block;
}
.el_hover01::after {
  position: absolute;
  content: "";
  left: 0;
  bottom: -3px;
  height: 1px;
  width: 0;
  background-color: #000;
  transition: 0.3s;
}
.el_hover01:hover::after {
  width: 100%;
}

/* ==========================
  アンダーバーが左から右に伸びて右へ進み縮小していく
========================== */
.el_hover02 {
  position: relative;
  display: inline-block;
}
.el_hover02::after {
  position: absolute;
  content: "";
  left: 0;
  bottom: -3px;
  height: 1px;
  width: 100%;
  background-color: #000;
  transform: scaleX(0);
  transform-origin: right top;
  transition: transform 0.3s;
}
.el_hover02:hover::after {
  transform: scaleX(1);
  transform-origin: left top;
}

/* ==========================
  アンダーバーが中央から左右に伸びていく
========================== */
.el_hover03 {
  position: relative;
  display: inline-block;
}
.el_hover03::after {
  position: absolute;
  content: "";
  left: 50%;
  transform: translateX(-50%);
  bottom: -3px;
  height: 1px;
  width: 0;
  background-color: #000;
  transition: 0.3s;
}
.el_hover03:hover::after {
  width: 100%;
}

/* ==========================
  アンダーバーが中央から左右に伸びていく
========================== */
.el_hover03 {
  position: relative;
  display: inline-block;
}
.el_hover03::after {
  position: absolute;
  content: "";
  left: 50%;
  transform: translateX(-50%);
  bottom: -3px;
  height: 1px;
  width: 0;
  background-color: #000;
  transition: 0.3s;
}
.el_hover03:hover::after {
  width: 100%;
}

/* ==========================
  アンダーバーが上から下にスライドしながら現れる
========================== */
.el_hover04 {
  position: relative;
  display: inline-block;
}
.el_hover04::after {
  position: absolute;
  content: "";
  left: 0;
  bottom: 0;
  height: 1px;
  width: 100%;
  background-color: #000;
  opacity: 0;
  visibility: hidden;
  transition: 0.3s;
}
.el_hover04:hover::after {
  bottom: -3px;
  opacity: 1;
  visibility: visible;
}

/* ==========================
  テキストの色が変わる
========================== */
.el_hover05 {
  position: relative;
  display: inline-block;
  transition: 0.4s ease-out;
}
.el_hover05:hover {
  color: #58b1c4;
}

/* ==========================
  同じテキストが下から上にスライドしてくる
========================== */
.el_hover06 {
  position: relative;
  display: inline-block;
  overflow: hidden;
  transition: 0.4s ease-out;
}
.el_hover06::before,
.el_hover06::after {
  content: "";
  position: absolute;
  width: 100%;
  left: 0;
}
.el_hover06::after {
  content: attr(data-replace);
  height: 100%;
  top: 0;
  transform-origin: 50% 100%;
  transform: translate(0, 200%);
  transition: transform 0.3s ease;
}
.el_hover06:hover::after {
  transform: translate(0, 0);
}

.el_hover06 span {
  display: inline-block;
  transition: transform 0.3s ease;
}

.el_hover06:hover span {
  transform: translate(0, -200%);
}

/* ==========================
  アンダーラインがグラデーションを経由する
========================== */
.el_hover07 {
  position: relative;
  display: inline-block;
  transition: 0.4s ease-out;
  padding-bottom: 5px;
  overflow: hidden;
}
.el_hover07::after {
  content: "";
  position: absolute;
  width: 300%;
  height: 2px;
  right: -200%;
  bottom: 0;
  background: linear-gradient(
      to right,
      #222 0%,
      #222 33.333333%,
      red 33.333333%,
      blue 66.666666%,
      #222 66.666666%,
      #222 100%
    )
    no-repeat;
  transition: right 0.6s ease;
}
.el_hover07:hover::after {
  right: 0;
}

/* ==========================
  1文字1文字がバラバラに点滅する
========================== */
.el_hover08 {
  position: relative;
  display: inline-block;
}
.el_hover08 span {
  transition: opacity 0.2s cubic-bezier(0.165, 0.84, 0.44, 1);
}
.el_hover08:hover span:nth-of-type(1) {
  animation: blink_animation 0.13s linear 0.12015s;
  animation-iteration-count: 2;
}
.el_hover08:hover span:nth-of-type(2) {
  animation: blink_animation 0.13s linear 0.13605s;
  animation-iteration-count: 2;
}
.el_hover08:hover span:nth-of-type(3) {
  animation: blink_animation 0.13s linear 0.0579s;
  animation-iteration-count: 2;
}
.el_hover08:hover span:nth-of-type(4) {
  animation: blink_animation 0.13s linear 0.1182s;
  animation-iteration-count: 2;
}
.el_hover08:hover span:nth-of-type(5) {
  animation: blink_animation 0.13s linear 0.1215s;
  animation-iteration-count: 2;
}
.el_hover08:hover span:nth-of-type(6) {
  animation: blink_animation 0.13s linear 0.10755s;
  animation-iteration-count: 2;
}
.el_hover08:hover span:nth-of-type(7) {
  animation: blink_animation 0.13s linear 0.02745s;
  animation-iteration-count: 2;
}
@keyframes blink_animation {
  0% {
    opacity: 1;
  }
  50% {
    opacity: 0.35;
  }
  100% {
    opacity: 1;
  }
}

アンダーバーの伸びるパターンの対応について

疑似要素で線を作り、widthの値を変更して動かしているパターン、もしくはtransformのscaleの値を変更して動かしているパターンがあります。

個人的には結構使われている場面が多いなと感じました。また、実案件では、意外とコーダーが自由にアニメーションを考えていい場面も見受けられますので、迷ったときの選択肢の候補としてあってもいいのかなと思いました。

アンダーバーが上から下にスライドして現れるパターン

こちらについては、最初は見えない状態にするために、opacityを0、visibilityをhiddenにしておき、ホバー時に、opacityを1、visibilityをvisibleにしておきます。

あとはbottomなどの値を変えて、見えない状態のときの位置、見えている状態のときの位置を調整してあげれば対応できます。

transitionをつけるクラスは、疑似要素に対して設定すれば完成です。

同じテキストが下から上にスライドしてくる

<a href="" class="el_hover06" data-replace="リンクテキスト">

ポイントは、HTMLのdata-replace属性を下記のCSSのcontent部分と結びつけることです。

.el_hover06::after {
  content: attr(data-replace);
}

あとは記述どおりですが、親要素からはみ出た時に要素が表示されないようにoverflowをhiddenにし、疑似要素はtransformで位置を調整し見えない状態にしておきます。

あとはホバー時に動いた時に、spanで囲ったテキスト、ならびに疑似要素のテキストを動かしてあげれば完成です。

意外とこの実装については、いろんなページを見ていると多い印象でしたので、使う場面が多そうです。

1文字ずつばらしたパターンもあるのですが、JavaScriptを使っているケースが多かったため、今回は紹介しないことにしました。別の機会に紹介できればと思っています。

アンダーラインがグラデーションを経由する

.el_hover07::after {
  content: "";
  position: absolute;
  width: 300%;
  height: 2px;
  right: -200%;
  bottom: 0;
  background: linear-gradient(
      to right,
      #222 0%,
      #222 33.333333%,
      red 33.333333%,
      blue 66.666666%,
      #222 66.666666%,
      #222 100%
    )
    no-repeat;
  transition: right 0.6s ease;
}

ポイントは、widthの値と、backgroundのグラデ設定です。

今回行っていることは、width300%のうち、0〜100%は黒、100%〜200%は赤から青のグラデ、200〜300%は黒といったような線をイメージして作りました。

この線をホバー時に移動させることで、overflowがhiddenになって隠れていたグラデの線が通り過ぎるアニメーションが実装できます。

応用次第ではいろんなアニメーションもできそうです。現状はおしゃれ感が皆無ですが、色選びやグラデの割合、アニメーションのイージングの値を工夫することでよりおしゃれなアニメーションの実装ができると思います。

1文字1文字がバラバラに点滅する

こちらは正直使われている事例が1つだけでしたが、一応紹介しておくことにします。参考程度にしておくのがいいかと思います。

<a href="" class="el_hover08">
  <span>リ</span><span>ン</span><span>ク</span><span>テ</span><span>キ</span><span>ス</span><span>ト</span>
</a>

ポイントは1文字ずつspanで囲い、それぞれに対してCSSを設定できるようにすることです。

今回は点滅させることが目的のため、keyframesを設定し、それぞれのspanに対してanimationプロパティを使用しているだけです。

animation-iteration-countを2に設定すると、2回アニメーションが繰り返されます。

以上ですが、今後も実務で使えそうなテキストのホバーアニメーションを見つけましたら随時更新していきたいと思います。