ページ内のテキスト表示に動きをつける「タイプライター風」を、複数行のテキストでも対象になるようJavaScriptで作ってみました。
この記事では、ページ描画時ではなく「スクロールイン時」がトリガーにして、ヒーローエリア以外でも利用できるようにしています。
なので、スクロールインがトリガーになるスニペットです。
是非、最後までご覧いただけたら嬉しいです。
.innerHTML
JavaScriptの .innerHTML
は、要素内の HTML を取得・設定するプロパティです。
const text = el.innerHTML;
この記事では、設置した要素のHTMLを取得して、それを分割してタイプライター風にテキストを表示させます。
タイプライター風に表示されるテキストのサンプル
早速サンプルです。
ページをスクロールしていき、以下のブロックがウィンドウ内に入ると「どこか、遠くへ。」のコピー下にある「そうだ。遠くへ行こう。明日、明後日。明明後日。気の向くままに。」が一文字づつタイプライター風に表示されます。
どこか、遠くへ。
そうだ。遠くへ行こう。
明日、明後日。明明後日。
気の向くままに。
スクロールインをトリガーにすることで、ヒーローエリア以外でもタイプライター風に表示されます。
実装の手順と方法
コードの解説の前に、実装の手順と方法について解説します。
はじめに、設置したい場所にHTMLを記述します。
<p class="textTitle">どこか、遠くへ。</p>
<p class="typeWriter">そうだ。遠くへ行こう。<br>明日、明後日。明明後日。<br>気の向くままに。</p>
次に、JavaScriptのコードをページに記述します。
コードは <body>〜</body>
で、</body>
の閉じタグ(クロージングタグ)の前に記述しましょう。
const doObserve = (element) => {
const targets = document.querySelectorAll('.typeWriter'); /* ターゲットの指定 */
const options = {
root: null,
rootMargin: '0px',
threshold: 0
};
const observer = new IntersectionObserver((items) => {
items.forEach((item) => {
if (item.isIntersecting) {
const typeWriter = selector => {
const el = document.querySelector(selector);
const text = el.innerHTML;
(function _type(i = 0) {
if (i === text.length) return;
el.innerHTML = text.substring(0, i + 1) + '<span aria-hidden="true"></span>';
setTimeout(() => _type(i + 1), 150);
})();
};
typeWriter(".typeWriter");
} else {
item.target.classList.remove('typing'); /* 表示域から外れた時にターゲットから削除するclassの指定 */
}
});
}, options);
Array.from(targets).forEach((target) => {
observer.observe(target);
});
};
doObserve('.observe_target');
最後に、CSSを記述します。
p.textTitle {
text-align: center;
font-size: 2rem;
font-weight: 600;
letter-spacing: 0.08rem;
margin-bottom: 0;
}
.typeWriter {
font-size: 1.2rem;
color: #313131;
text-align: center;
margin: 0 !important;
min-height: 120px;
}
.typeWriter > span {
border-right: 2px solid;
animation: caret 1s steps(1) infinite;
}
@keyframes caret {
50% {
border-color: transparent;
}
}
ざっくりとしたコードの解説
コードは、HTML・JavaScript・CSSの3種です。順に解説していきます。
HTML
HTMLは、p
タグが2つのシンプルな造りです。
「どこか、遠くへ。」のコピー部分も p
タグにしていますが、設置するページの構造によっては h2
の見出しタグが適切な場合もあるので、適宜書き換えると良いです。
<p class="textTitle">どこか、遠くへ。</p>
<p class="typeWriter">そうだ。遠くへ行こう。<br>明日、明後日。明明後日。<br>気の向くままに。</p>
JavaScript
JavaScriptは、ざっくり言うと「ターゲットの指定」を行い、条件分岐で処理方法をそれぞれ記述します。
const doObserve = (element) => {
const targets = document.querySelectorAll('.typeWriter'); /* ターゲットの指定 */
const options = {
root: null,
rootMargin: '0px',
threshold: 0
};
const observer = new IntersectionObserver((items) => {
items.forEach((item) => {
if (item.isIntersecting) {
const typeWriter = selector => {
const el = document.querySelector(selector);
const text = el.innerHTML;
(function _type(i = 0) {
if (i === text.length) return;
el.innerHTML = text.substring(0, i + 1) + '<span aria-hidden="true"></span>';
setTimeout(() => _type(i + 1), 150);
})();
};
typeWriter(".typeWriter");
} else {
item.target.classList.remove('typing'); /* 表示域から外れた時にターゲットから削除するclassの指定 */
}
});
}, options);
Array.from(targets).forEach((target) => {
observer.observe(target);
});
};
doObserve('.observe_target');
具体的には、冒頭にある option
で「root」のキーを「null」に設定することで、要素がウィンドウに入ったかどうかの検知ができるようになります。
CSS
簡素なサンプルなので、それぞれの p
タグのレイアウトとフォントサイズを整える程度の記述内容ですが、タイプ中のカーソルを span
タグで作り、それを @keyframes caret
でアニメーションさせます。
p.textTitle {
text-align: center;
font-size: 2rem;
font-weight: 600;
letter-spacing: 0.08rem;
margin-bottom: 0;
}
.typeWriter {
font-size: 1.2rem;
color: #313131;
text-align: center;
margin: 0 !important;
min-height: 120px;
}
.typeWriter > span {
border-right: 2px solid;
animation: caret 1s steps(1) infinite;
}
@keyframes caret {
50% {
border-color: transparent;
}
}
span
タグは、HTMLで記述せずにJavaScriptで生成させています。
さいごに
全文字が表示されるまで多少時間がかかるので、タイプライターの対象になる文字数と、レイアウトには気をつける必要があります。
が、動きも出るので使い方によってはユーザーも、認識してくれやすくなります。
なので、状況に応じて使ってみてください。