ここ最近主にナビゲーションなどでホバー時にアンダーラインをアニメーションさせるエフェクトの実装要望が多いので、パッと使えるようによく利用するものをひと通りまとめたのでシェアします。
また、大体この手のアニメーションを利用する際はサイト全体で動きを統一させることが多いのですが、たまに場所によって少し違いをつけたいということもあるので、そういったときにすぐ対応できるようにSassのmixinを用いて実装する方法も併せて紹介します。

ここで紹介しているサンプルで使用しているHTMLは、すべて<a href="#">Lorem ipsum</a>のようなシンプルなa要素を使用した想定になっています。

Fade Top

ホバーするとテキスト下でアンダーラインが上からフェードインしてくるタイプのアニメーションで、実装にはCSSを下記をのように記述します。

a {
  position: relative;
  display: inline-block;
  text-decoration: none;
}
a::after {
  position: absolute;
  bottom: 2px;
  left: 0;
  content: '';
  width: 100%;
  height: 2px;
  background: #333;
  opacity: 0;
  visibility: hidden;
  transition: .3s;
}
a:hover::after {
  bottom: -4px;
  opacity: 1;
  visibility: visible;
}

Fade Bottom

先ほどとは逆に、ホバーするとテキスト下でアンダーラインが下からフェードインしてくるタイプのアニメーションで、実装にはCSSを下記をのように記述します。

a {
  position: relative;
  display: inline-block;
  text-decoration: none;
}
a::after {
  position: absolute;
  bottom: -8px;
  left: 0;
  content: '';
  width: 100%;
  height: 2px;
  background: #333;
  opacity: 0;
  visibility: hidden;
  transition: .3s;
}
a:hover::after {
  bottom: -4px;
  opacity: 1;
  visibility: visible;
}

Left to Right

ホバーするとアンダーラインが左から右に引かれる形で表示され、ホバーが外れるとまた左に戻っていくタイプのアニメーションで、実装にはCSSを下記をのように記述します。

a {
  position: relative;
  display: inline-block;
  text-decoration: none;
}
a::after {
  position: absolute;
  bottom: -4px;
  left: 0;
  content: '';
  width: 100%;
  height: 2px;
  background: #333;
  transform: scale(0, 1);
  transform-origin: left top;
  transition: transform .3s;
}
a:hover::after {
  transform: scale(1, 1);
}

Right to Left

こちらは先ほどとは逆に、ホバーするとアンダーラインが右から左に引かれる形で表示され、ホバーが外れるとまた右に戻っていくタイプのアニメーションで、実装にはCSSを下記をのように記述します。

a {
  position: relative;
  display: inline-block;
  text-decoration: none;
}
a::after {
  position: absolute;
  bottom: -4px;
  left: 0;
  content: '';
  width: 100%;
  height: 2px;
  background: #333;
  transform: scale(0, 1);
  transform-origin: right top;
  transition: transform .3s;
}
a:hover::after {
  transform: scale(1, 1);
}

Left in Right

ホバーすると左から右にラインが引かれる形で表示されますが、こちらはホバーが外れた場合に左に戻らず右に向かって非表示になるというタイプのアニメーションです。
実装にはCSSを下記をのように記述します。

a {
  position: relative;
  display: inline-block;
  text-decoration: none;
}
a::after {
  position: absolute;
  bottom: -4px;
  left: 0;
  content: '';
  width: 100%;
  height: 2px;
  background: #333;
  transform: scale(0, 1);
  transform-origin: right top;
  transition: transform .3s;
}
a:hover::after {
  transform-origin: left top;
  transform: scale(1, 1);
}

Right in Left

こちらは先ほどとは逆で、ホバーすると右から左にラインが引かれる形で表示され、ホバーが外れた場合に右に戻らず左に向かって非表示になるというタイプのエアニメーションです。
実装にはCSSを下記をのように記述します。

a {
  position: relative;
  display: inline-block;
  text-decoration: none;
}
a::after {
  position: absolute;
  bottom: -4px;
  left: 0;
  content: '';
  width: 100%;
  height: 2px;
  background: #333;
  transform: scale(0, 1);
  transform-origin: left top;
  transition: transform .3s;
}
a:hover::after {
  transform-origin: right top;
  transform: scale(1, 1);
}

Center

ホバーすると中央から左右に向かってラインが引かれるタイプのアニメーションで、実装にはCSSを下記をのように記述します。

a {
  position: relative;
  display: inline-block;
  text-decoration: none;
}
a::after {
  position: absolute;
  bottom: -4px;
  left: 0;
  content: '';
  width: 100%;
  height: 2px;
  background: #333;
  transform: scale(0, 1);
  transform-origin: center top;
  transition: transform .3s;
}
a:hover::after {
  transform: scale(1, 1);
}

mixin

上で全7種類のアンダーラインアニメーションを紹介してきましたが、以下はこれらを必要に応じて簡単に使用できるようにしたmixinになります。
こういったアニメーションなどは大体サイト内で揃えることが多いですが、たまに場所によって少し動きを変えたいときがあるので、そういったときに便利かと思います。

@mixin hover-underline($type: fade, $dir: null, $weight: 2px, $color: #000) {
  @if $dir == null {
    @if $type == fade {
      $dir: 'top';
    } @else if $type == slide {
      $dir: 'center';
    }
  }

  position: relative;
  display: inline-block;
  text-decoration: none;
  &::after {
    position: absolute;
    left: 0;
    content: '';
    width: 100%;
    height: $weight;
    background: $color;
    @if $type == fade {
      transition: .3s;
      opacity: 0;
      visibility: hidden;
      @if $dir == bottom {
        bottom: $weight * -4;
      } @else {
        bottom: $weight;
      }
    } @else if $type == slide {
      bottom: $weight * -2;
      transform: scale(0, 1);
      transition: transform .3s;
      @if $dir == left-right or $dir == right-in-left {
        transform-origin: left top;
      } @else if $dir == right-left or $dir == left-in-right {
        transform-origin: right top;
      } @else {
        transform-origin: center top;
      }
    }
  }
  &:hover::after {
    @if $type == fade {
      bottom: $weight * -2;
      opacity: 1;
      visibility: visible;
    } @else if $type == slide {
      @if $dir == left-in-right {
        transform-origin: left top;
      } @else if $dir == right-in-left {
        transform-origin: right top;
      }
      transform: scale(1, 1);
    }
  }
}

全体的に条件分岐多めで冗長な感じになってますが、上で紹介した7種類のアンダーラインアニメーションを上記mixinで簡単に利用できるようになり、アニメーション指定に利用するものとして下記4つの引数があります。
それぞれに特定の値を指定することで使用したいアニメーションを呼び出すことができ、主に$type$dirで指定された値と条件分岐を使って出力内容が変わるようになっています。

  • $type(タイプ)
  • $dir(方向)
  • $weight(ラインウェイト)
  • $color(ラインカラー)

それぞれの引数について説明すると、$typeはアニメーションのタイプを指定するもので、上で紹介した「Fade Top」と「Fade Bottom」がfade、それ以外の「Left to Right」~「Center」までがslideという形で大きく分類しており、初期値はfadeを指定しています。

次に$dirではアニメーションの方向を指定し、ここは$typeで指定した値によって指定できるものが異なります。
$typefadeを指定した場合はtopbottomを、$typeslideを指定した場合はleft-right, left-in-right, right-left, right-in-left, centerのいずれかを指定します。
$dirの初期値はnullを設定しており、もし指定されなかった場合はデフォルトの動きとして$typefadeにしていれば「Fade Top」が、$typeslideにしていれば「Center」が適用されるような形にしてあります。
また、間違った指定(例えばfadeleft-rightを指定するなど)をした場合でも、何も指定されなかったときと同じようにデフォルトの動きが適用されます。

$weightはラインウェイトを指定(初期値は2px)するもので、ここで指定した値は単純にラインの太さのために使用するだけでなく表示位置の調整などにも利用しています。

最後の$colorについては、そのままラインカラーを指定(初期値は#000)するものになります。

実際にmixinを使用する場合は、それぞれ下記のように記述していきます。
下記はすべて$weight$colorの指定は省略したものになりますので、必要であれば例えば@include hover-underline('fade', 'top', 4px, #aaa);のような形で追記してください。

// Fade Top
.example01 a {
  @include hover-underline('fade', 'top');
}

// Fade Bottom
.example02 a {
  @include hover-underline('fade', 'bottom');
}

// Left to Right
.example03 a {
  @include hover-underline('slide', 'left-right');
}

// Right to Left
.example04 a {
  @include hover-underline('slide', 'right-left');
}

// Left in Right
.example05 a {
  @include hover-underline('slide', 'left-in-right');
}

// Right in Left
.example06 a {
  @include hover-underline('slide', 'right-in-left');
}

// Center
.example07 a {
  @include hover-underline('slide', 'center');
}

ちなみに、そのまま使用した場合「Fade Top」は@include hover-underline;、「Center」は@include hover-underline('slide');でも呼び出すことができます。

以下はこのmixinを用いて指定しているデモで、CodePenなので実際の表示確認するだけでなくちょっとコードを変更して試すこともできます。


mixinに関しては条件分岐多めだったりでもっとスマートに書けそうな感じがすごいので、もっと良い感じに書ける方法をご存知の方は是非教えてください。

ちなみに、ここで紹介してきたものはすべてアンダーラインのみという形でしたが、疑似要素を増やすことで上下にラインを表示させたり、それぞれ違う方向からラインを引くといったことも可能になります。
以前にもこのようなエフェクトの実装方法を紹介しており、ここで紹介しているものとはtransformの使い方などが若干異なりますが、それらの実装方法については以下を参考にしてみてください。