最近スクロールと連動してテキストに下線を、アニメーションして引かせるコードを書く機会があったよ。
スクロールは何度もやってきたのでやり方はわかっていたんだが、下線をアニメーションで引かせるのをどうやるのかと思っていたところ、案外楽にできた。
下にそれぞれ、html,css,javascriptのコードを用意しておいた。コピペすれば使えるようになるぞ!
html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="style.css">
<title>スクロールと連動して下線が引かれるアニメーション</title>
</head>
<body>
<div>
<p>初めまして。とある会社でフロントエンドエンジニアをしている祐介と申します。</p>
<p>いろいろなことをやっている会社なので、みんながみんな同じ仕事をしているわけではないのですが、私はWEB制作の貴重な実務経験を積ませていただいています。</p>
<p>このブログは二通りのタイプの人をターゲットにしています。まずは同じエンジニアの方の役に立つ情報を更新していけたらと思います。</p>
<p>もう一つ、職場の割とパソコンリテラシーが浅いものの、今後学習していきたい方々に対する情報提供をしていけたらと思っています。<span class="underline-before">(ありがちなトラブル回避のため、コメント機能は消してあります)</span>できれば楽しんで読んでいただきたいという気持ちから、記事のテンションは無理矢理高くしています。</p>
<p>最初はこなれないかもしれませんが、<span class="underline-before">そのうちに自分のものにして行けたらと思います。</span>みなさま、何卒よろしくお願いいたします。</p>
</div>
<script src="action.js"></script>
</body>
</html>
CSS
div {
width: 250px;
height: auto;
margin: auto;
padding-bottom: 200px;
}
p {
margin: 60px auto;
}
.underline-before {
background: linear-gradient(black, black) 0 100%/0 2px no-repeat;
/*左から、カラー(始点と終点それぞれ同じものを指定)、position / サイズ横縦 繰り返しの有無 */
transition: background .5s;
/*トランジションの設定。下線を引く動きをアニメーションにするのに必要 */
text-decoration: none;
/*テキストの装飾の設定 */
}
.underline-after {
background-size: 100% 2px;
/* 変化後のスタイル。横サイズを0から100%に変えることで指定の文字列に下線を引く */
}
javascript
var expantion = document.getElementsByClassName('underline-before');
// .underline-beforeのついたDOMを取得
var expantionswitch = ["off","off","off"];
// 下線を引くアクションを行ったか行ってないかのスイッチを配列の値で表現。初期値はoff
window.onscroll = function(){
// スクロールした場合、関数(function)を実行
for(var i = 0,len = expantion.length;i < len;i++){
// .underline-beforeの数だけ繰り返しするfor文
var ex_clientRect = expantion[i].getBoundingClientRect();
// [i]番目の.underline-beforeの境界ボックスを取得(画面内での.underline-beforeの位置を取得)
var wh = window.innerHeight;
// ブラウザのウインドウの表示領域の高さを取得。(ページの上からどれだけ進んだか計る)
if(wh > ex_clientRect.top + 200 && expantionswitch[i] === "off") {
// if文による分岐。もしウインドウの表示領域の高さが、[i]番目の.underline-beforeの画面内での上からの位置+200pxより
// 高かった場合。また、[i]番目のexpantionswitchがoffの場合にtrueの動作を返す。
expantion[i].classList.add('underline-after');
// [i]番目の.underline-beforeがついている要素に新たに.underline-afterを追加。これによって下線を引くアクションが実現する。
expantionswitch[i] = "on";
// offだった配列の値をonにする。これによって二度同じ動作をするのを防いでいる。
}
}
}
ざっくり説明しよう。span.underline-beforeで囲われた部分に下線が引かれるわけだが、CSSの方で.underline-afterというセレクタも用意されている。
backgroundのサイズが前者が0 2pxに対して、後者は100% 2pxになっているのがわかるかな?。
2pxの太さの線が0%用意されていて、.underline-afterが付与されることで100%まで伸びるイメージさ。
.underline-beforeにtransitionがあるから、要素が動いた際にアニメーションとして動くようになるぞ。
javascriptの方ではwindow.onscrollで、スクロールするたびに画面の高さを取得している。その高さを取得しているのが、window.innerHeightだな。
getBoundingClientRect()という要素の境界ボックスを取得する関数で.underline-beforeの位置を求めることができるぞ。
それらに基づいてスクロール位置が.underline-beforeの位置と一致したところで、spanに.underline-afterが追加される。
そこで下線が引かれる仕組みになっているわけだ。
下線のアニメーションに関しては下記のサイトを参考にさせていただいた。
CSSで複数行に対応したアニメーション付きアンダーライン(下線)を実装する方法