下線アニメをbackground-sizeのanimationで実装したらIE11で動かなかったけど切り捨てた

# はじめに

「元々リンクテキストに下線が引いてあって、マウスホバーするとその下線が左から右へアニメーションする。」

そんなあるある要件を満たすためにいろいろと試してみました、が、悪しからず、**完璧なIE11対応はできなかったので諦めました**、という残念な記事です。

ぜひ、ナレッジがある方はお知恵を拝借できれば幸いです。

**追記(2021/03/16): お知恵を頂き、追記しました。**

# 実際にやってみた

ベースとなるHTMLは以下の通りです。

```html:HTML
<a>リンクテキスト<br>2行目です</a>
```

## まずは`scale()`で実装

widthを使ったりいろいろ実装方法はあると思いますが、まず私は`transform: scaleX()`で実装しました。
`transform-origin`を変えればアニメーションの起点を簡単に真ん中にしたり右端にしたり変えられると考えたからです。

```css:Mark.I（疑似要素で実現）
a {
  position: relative;
  display: inline-block;
  text-decoration: none;
}
a::after {
  position: absolute;
  bottom: 0;
  left: 0;
  content: "";
  width: 100%;
  height: 1px;
  background: #000;
  transform: scaleX(1);
  transform-origin: left top;
}
a:hover::after {
  animation: leftToRightUnderline 0.3s;
}

@keyframes leftToRightUnderline {
  from {
    transform: scaleX(0);
  }
  to {
    transform: scaleX(1);
  }
}
```

<p class="codepen" data-height="515" data-theme-id="dark" data-default-tab="css,result" data-user="heeroo-ymsw" data-slug-hash="eYBXVdV" style="height: 515px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="LeftToRight Mark.1">
  <span>See the Pen <a href="https://codepen.io/heeroo-ymsw/pen/eYBXVdV">
  LeftToRight Mark.1</a> by heeroo-ymsw (<a href="https://codepen.io/heeroo-ymsw">@heeroo-ymsw</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

疑似要素`after`で高さ1pxの線を作ってテキストの下に配置し、左端を起点にanimationで要素を拡大させています。
今回はもともと下線が引いてあるので、マウスホバーを外したときのアニメーションはありません。

しかし、このコードには問題があり、テキストが2行以上になるとそのブロックの下に下線がひかれ、「テキストの下線」ではなくなってしまいます。

## 複数行にも対応させる

```css:Mark.II（複数行対応版）
a {
  background: linear-gradient(#000, #000) 0 bottom/100% 1px no-repeat;
  text-decoration: none;
}

a:hover {
  animation: leftToRightUnderline 0.3s;
}

@keyframes leftToRightUnderline {
  from {
    background-size: 0% 1px;
  }
  to {
    background-size: 100% 1px;
  }
}
```

<p class="codepen" data-height="425" data-theme-id="dark" data-default-tab="css,result" data-user="heeroo-ymsw" data-slug-hash="wvoOxpj" style="height: 425px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="LeftToRight Mark.2">
  <span>See the Pen <a href="https://codepen.io/heeroo-ymsw/pen/wvoOxpj">
  LeftToRight Mark.2</a> by heeroo-ymsw (<a href="https://codepen.io/heeroo-ymsw">@heeroo-ymsw</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

疑似要素を用いるよりもスッキリした印象です。

`linear-gradient()`と`background-size`で幅100%/高さ1pxの下線を書いておき、`background-size`をアニメーションさせることで実現しています。

しかし、こちらにも問題点が。

**IE11は`background-size`のtransition/animationに対応していません。**

…

![r_655811_6dC5m.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/924363/88278742-358e-6c57-fe13-29dc1c681f59.gif)

## IE11に対応させる

```css:Mark.III（IE11対応）
a {
  background: linear-gradient(#000, #000) 0 bottom/100% 1px no-repeat;
  text-decoration: none;
}
a:hover {
  animation: leftToRightUnderline 0.3s;
}

@keyframes leftToRightUnderline {
  from {
    background-position: -190px bottom;
  }
  to {
    background-position: 0 bottom;
  }
}
```

<p class="codepen" data-height="417" data-theme-id="dark" data-default-tab="css,result" data-user="heeroo-ymsw" data-slug-hash="jOVJvmO" style="height: 417px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="LeftToRight Mark.3">
  <span>See the Pen <a href="https://codepen.io/heeroo-ymsw/pen/jOVJvmO">
  LeftToRight Mark.3</a> by heeroo-ymsw (<a href="https://codepen.io/heeroo-ymsw">@heeroo-ymsw</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

`background-position`で左にずらしとくパターンです。
ただし、これも残念ながら万能策ではありません。
むしろ、**問題が増えました**。

- 下線を適応させたい要素に応じて、ずらし具合(例だと-190pxの部分)を調整しなくてはいけない
- ずらし具合の調整が地味に面倒
- アニメーション方向が変わった場合などの汎用性が低い

## そのうちコーダーは考えるのをやめた

今回は以下の**言い訳とともにIE11を切り捨て**、`background-size`で実装しました。

- 調べたら[polyfill](http://asamuzak.jp/html/438)もあったが、案件でそれを検証している時間がない
- `background-position`を使っても、実装当初はリンクが増える、もしくはテキストが変更になる可能性が大いにあり、その度にズレを調整していられない
  - ついでにレスポンシブ対応&PCサイズのときはリキッド対応の必要がある

## そして、賢者が現れる

*2021/03/16 追記*

この記事を出したところ、賢者から知恵を頂くことができたので、改めてこの問題に向き合いました。
非常に勉強になります。ありがとうございます。

```CSS:MarkIV（IE11対応&汎用性UP）
a {
  background: linear-gradient(to right, #000 50%, transparent 50%) 0 bottom/200% 1px no-repeat;
  text-decoration: none;
}
a:hover {
  animation: leftToRightUnderline 0.3s;
}

@keyframes leftToRightUnderline {
  from {
    background-position: 100% bottom;
  }
  to {
    background-position: 0% bottom;
  }
}
```

<p class="codepen" data-height="481" data-theme-id="dark" data-default-tab="css,result" data-user="heeroo-ymsw" data-slug-hash="LYbvzYr" style="height: 481px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="LeftToRight Mark.4">
  <span>See the Pen <a href="https://codepen.io/heeroo-ymsw/pen/LYbvzYr">
  LeftToRight Mark.4</a> by heeroo-ymsw (<a href="https://codepen.io/heeroo-ymsw">@heeroo-ymsw</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

端的に言えば、`linear-gradient()`で横方向のグラデーションを作成し、それをbackground-positionで左右に動かすというものになります。

`■□`←こんな感じのグラデーションを作って、横を2倍に引き伸ばして、`background-position`は左端に寄せておいて下線を常時表示します。
アニメーション時は、`background-position`を右端に寄せて左端へ動かすことで左から右へ下線が動くように見えます。なるほどすごい！

しかしながら、はたまた**問題が**。

**IE11だとkeyframesでアニメーションしない……**

**transitionだと動く**のですが、下線を元々表示したい関係でkeyframesを使っており、これが動きませんでした。
書き方が悪いのか、IE11の仕様なのか…現在調査中です。

# まとめ

テキストの下線アニメーションの実装を行い、現段階では、~~`background-size`のanimation / transitionでの実装が最適解かと感じました。~~

`background-position`の代替案が出来たと思ったのですが、keyframesによるanimationがうまくいきませんでした。謎。
鋭意調査続行中であります。