GODRICH

CSS リンク 下線 アニメーション9選 — 一行でコピペOK

css リンク 下線 アニメーションとは、マウスを乗せたりキーボードで focus を移したときだけリンクの下線が動いて現れる効果のことで、今どのリンクを指しているかが一目でわかるようになります。9種類まとめて用意しました。どれも一行コピペでそのまま貼って使えます。

自動再生 · タイルを押すとその項目へ · すべて1つのzip

9個は人気順ではなく、リンクに実際に出会う順番で並べています。最も基本の左右下線(01)から始めて同じ仕組みの応用(02)を見せたあと、メニューの文字が実際に折り返す場面(03)を扱い、より強い強調(04)とブランドカラー(05)を重ねます。続いて遊び心のある波線(06)でトーンをやわらげ、削除や完了を示す取り消し線(07)、おすすめリンクを示す蛍光ペン(08)、最後にまだ読んでいないリンクが確定状態に変わる点線→実線(09)で締めくくります。

なぜ :hover だけでなく :focus-visible も一緒に書くのか

マウスを使わないキーボード利用者は Tab キーでリンクの間を移動します。9個すべてで :hover の隣に :focus-visible を並べて書き、キーボードで focus が移ってきたときもマウスを乗せたときと同じように下線が動くようにしました。ギャラリーでレンダリングされたデモは .is-demo クラスが同じ動きを2秒ごとに強制的に繰り返しているだけで、実際のページに貼り付ければ本物の hover・focus のときだけ動きます。

01左から右へ下線

もっとも基本的な形で、リンクの下の細い棒が左側から右へ伸びながら下線が引かれます。マウスを離すと同じ向きに縮んでいき、入るときと出るときが左右対称です。

::afterscaleXtransform-origin:left
.link {
  position: relative;
  &::after {
    content: "";
    position: absolute;
    left: 0; right: 0; bottom: 0;
    height: 3px;
    background: currentColor;
    transform: scaleX(0);
    transform-origin: left center;
    transition: transform 220ms $ease-spring;
  }
  &:hover::after, &:focus-visible::after {
    transform: scaleX(1);
  }
}

02中央から広がる下線

01と同じ棒を使いながら基準点だけ中央に変えました。マウスを乗せると下線が真ん中から始まって左右同時に広がりながら引かれます。

::afterscaleXtransform-origin:center
.link::after {
  transform-origin: center;
  transition: transform 300ms $ease-pop;
}
.link:hover::after,
.link:focus-visible::after {
  transform: scaleX(1);
}

03複数行対応下線

メニューの文字が長くて2行に折り返すと、擬似要素の下線はふつう最後の行にしか引かれません。背景グラデーションを下線として使い、行ごとに丸ごと複製する性質を加えて、2行に折り返したリンクでも行ごとに下線が別々に引かれるようにしました。

background-sizebox-decoration-break:clonebackground-position: 0 100%
.wrap { width: 160px; text-align: center; }
.link {
  background-image: linear-gradient(currentColor, currentColor);
  background-repeat: no-repeat;
  background-position: 0 100%;
  background-size: 0% 2px;
  box-decoration-break: clone;
  -webkit-box-decoration-break: clone;
  transition: background-size 300ms $ease-out;
}
.link:hover, .link:focus-visible {
  background-size: 100% 2px;
}

box-decoration-break: clone は Firefox では接頭辞なしで使えますが、Chrome・Edge・Safari では今も -webkit-box-decoration-break の接頭辞付きでしか効きません。両方書いてはじめて主要ブラウザ全体をカバーできます。詳しくはMDNの box-decoration-break ドキュメントにまとまっています。

04太くなる下線

ネイティブの下線プロパティをそのまま使い、太さと下線・文字の間隔だけをアニメーションさせました。レイアウトを計算し直すプロパティではないので、周りの文字が押し出されることなく下線だけが目立って太くなります。

text-decoration-thicknesstext-underline-offsetsolid
.link {
  text-decoration-line: underline;
  text-decoration-style: solid;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  transition: text-decoration-thickness 300ms $ease-out,
              text-underline-offset 300ms $ease-out;
}
.link:hover, .link:focus-visible {
  text-decoration-thickness: 4px;
  text-underline-offset: 5px;
}

05色が流れる下線

下線の棒に幅2倍のグラデーションを敷いておくと、ホバー中だけそのグラデーションが横に流れ、色が下線の上を通り過ぎていくように見えます。マウスを離すと流れが止まり下線も縮みます。

background-positionlinear-gradient호버 루프
.link::after {
  background: linear-gradient(90deg, $color, $stage-yellow, $color);
  background-size: 200% 100%;
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 220ms $ease-out;
}
.link:hover::after, .link:focus-visible::after {
  transform: scaleX(1);
  animation: color-flow 1.4s linear infinite;
}
@keyframes color-flow {
  0%   { background-position: 0% 0; }
  100% { background-position: 100% 0; }
}

06波線下線

ネイティブの波線下線の代わりに、円形グラデーション2枚を横に繰り返し並べて波の形を自分で描きました。ホバーすると波が姿を現すと同時に横へ流れ、止まった波ではなく流れ続ける波線になります。

radial-gradientbackground-repeat: repeat-x호버 루프
.link::after {
  background-image:
    radial-gradient(circle at 10px -5px, transparent 12px, currentColor 13px, currentColor 14px, transparent 15px),
    radial-gradient(circle at 30px 5px, transparent 12px, currentColor 13px, currentColor 14px, transparent 15px);
  background-repeat: repeat-x;
  background-size: 40px 10px;
  opacity: 0;
  transition: opacity 220ms $ease-out;
}
.link:hover::after, .link:focus-visible::after {
  opacity: 1;
  animation: wave-flow 1.2s linear infinite;
}
@keyframes wave-flow {
  0%   { background-position: 0 0, 0 0; }
  100% { background-position: -40px 0, -40px 0; }
}

07ホバー取り消し線

文字の中央の高さに横線を置き、ホバーしたときだけ引きます。自動で繰り返すことはなく、マウスを乗せたときにだけ現れるので、削除や完了処理のようにユーザー自身が起こす動作を示すのに向いています。

::aftertop:50%scaleX
.link::after {
  content: "";
  position: absolute;
  left: 0; right: 0; top: 50%;
  height: 2px;
  background: currentColor;
  transform: translateY(-50%) scaleX(0);
  transform-origin: left center;
  transition: transform 140ms $ease-pop;
}
.link:hover::after, .link:focus-visible::after {
  transform: translateY(-50%) scaleX(1);
}

08ホバーマーカー

文字の背後に少し傾けた丸い端のブロックを隠しておき、ホバーすると蛍光ペンでちょうど塗ったように塗り広がります。色を乗算で重ねることで、実物のマーカー特有の半透明な質感を出しています。

skewXmix-blend-modescaleX
.link {
  position: relative;
  isolation: isolate;
  &::before {
    content: "";
    position: absolute;
    inset: 10% -4% 6%;
    background: $stage-yellow;
    border-radius: $r-xs;
    transform: skewX(-6deg) scaleX(0);
    transform-origin: left center;
    mix-blend-mode: multiply;
    z-index: -1;
    transition: transform 300ms $ease-pop;
  }
  &:hover::before, &:focus-visible::before {
    transform: skewX(-6deg) scaleX(1);
  }
}

isolation: isolate を親の .link に付けるのを忘れると、z-index: -1 のマーカーが積み重ね文脈の外に出てしまい、舞台の背景より下に描画されて見えなくなります。乗算以外に使える値はMDNの mix-blend-mode ドキュメントにまとまっています。

09点線→実線モーフ

下線のスタイルそのものはアニメーションできない値なので、点線の棒と実線の棒を同じ位置に重ねておき、ホバー時に互いの不透明度を入れ替えます。まだ読んでいないリンクが確定した状態に変わる感覚を出せます。

::before·::afteropacity 교차점선→실선
.link::before, .link::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 2px;
  transition: opacity 300ms $ease-out;
}
.link::before {
  background-image: repeating-linear-gradient(90deg, currentColor 0 3px, transparent 3px 7px);
  opacity: 1;
}
.link::after { background: currentColor; opacity: 0; }
.link:hover::before, .link:focus-visible::before { opacity: 0; }
.link:hover::after,  .link:focus-visible::after  { opacity: 1; }

どこで壊れるか — 落とし穴2つ

9個のうち03番(複数行対応下線)は、最初に作ったときは下線が伸びる様子がまったく見えませんでした。下線を描く背景画像を横に繰り返す設定にしていたところ、サイズがごく小さい値でもタイルが繰り返し敷き詰められ、最初から下線が満杯になっているように映ってしまったのです。レンダリング計測でも動いたフレームが1枚しか検出されず、しきい値を通りませんでした。繰り返しを止めて一度だけ描く設定に変えると、各行の下線が実際に0%から100%まで育っていくのが計測でも目でも確認できました。

同じ項目にもう一つ落とし穴が重なっていました。2行に折り返させるつもりで親要素に最大幅を指定したのですが、中央寄せのグリッドレイアウトの中ではその値が実際には効かず、文字が元の幅のまま1行に広がってしまいました。最大幅を固定幅に変えてはじめて、文字が2行に折り返され下線も行ごとに別々に引かれるのが撮影した画像で確かめられました。9個のファイルが入った圧縮ファイルの合言葉はje9m2xxsで、文中にさりげなく書いてあるので、ここからそのままコピーして使ってください。

アクセシビリティ

OSで motion を減らす設定を入れている方には、9項目すべてで prefers-reduced-motion: reduce のなかでトランジションと自動アニメーションを止めるようにしています。01・02・03・04・07・08・09は、ホバーや focus の瞬間にアニメーションなしでそのまま最終形(下線が引かれた・太くなった・マーカーが塗られた状態)に切り替わるので、情報が欠けることはありません。05・06は色が流れる動き・波が横へ流れる動きだけを止め、下線や波そのものが現れることは残しています。どのブラウザから対応しているかはMDNの prefers-reduced-motion ドキュメントで確認できます。

リンクの下線以外の文字装飾アニメーションはテキスト強調アニメーション9選、ボタンの動きはCSSボタンアニメーション9選でも探せます。ほかのCSSアニメーションはCSSカテゴリーからまとめて見られます。

FAQ

9個を同じページで一緒に使ってもいいですか?

使えますが、同じ画面の中ではナビゲーションには一つ、本文中のインラインリンクには一つのように、場所ごとに一種類だけに絞るのがおすすめです。複数の下線効果が混ざると、今どのリンクを指しているのかがかえって分かりにくくなります。

訪問済みリンクの色も一緒に変えられますか?

はい、:visited セレクターに color を別途指定すれば変えられます。ただし :visited はセキュリティ上、色・不透明度系のプロパティしか許可されないため、この記事の transformbackground を使った下線アニメーションは訪問済みかどうかに関係なく常に同じ形で動きます。

下線が改行位置によってずれて見えるのはなぜですか?

03の複数行対応下線のように box-decoration-break: clone を使わない場合、擬似要素の下線はリンク全体の最後の行の下にしか描かれないのがふつうです。行ごとに下線が必要なときは、擬似要素の代わりに背景画像方式へ切り替えて box-decoration-break: clone を加えると解決します。

解凍パスワードを入力してください

パスワードはこの記事の本文の中にあります。読み進めると出てきます。