HTML、1行ごとに背景色を変更。

〽️ テキストの折り返しに自動で対応。




⬆︎SVGついてのまとめページ、CSSアニメーションの基本コーナーはこちら。



テキスト要素でも色を交互に。


こんにちは、「ふ」です。
web上で、<table>や<li>要素を使って1行ごとに背景色を変えているものを見かけると思います。
これらについては、擬似クラスを使ったセレクタで各行にアクセスできるため、CSSだけで容易に実装することができます。

それでは、<p>のような単なるテキスト要素に対し、背景色を交互に違うものにするには、どうすればいいのでしょうか?
<table>要素のようにCSSセレクタで各行にアクセスすることはできません。もとよりテキスト要素はブラウザでの表示幅によって行の折り返し位置も変わってきます

そこで今回。
JavaScriptとSVGを利用して、一般のテキスト要素でも1行ごとに背景色を変化させる、というものを作ってみました。これを実装することで、ただ単にタイピングしたものでも自動的に「折り返し位置」を検知し、1行ごとの色違いで表示させることができます。

いちいちtable化したりしなくても済むため、とても楽になりますよ♪

仕組み。


その仕組みですが、
position:absoluteを利用することで、テキスト要素の背面にSVG領域を重ねます。

JavaScriptを使い、テキストのline-heightを取得。line-heightは、fontsizeと行間の合計を表す値です。
背面のSVG領域に、line-heightと同じ高さの長方形を追加していきます。そしてfill(塗り)を1行ごと(長方形で言えば、1つごと)に交互に指定していけば、完成です。

HTMLとCSSのサンプル。


それではHTMLとCSSを準備します。

<p class = "alt_text"> bb1行目
bb2行目
bb3行目
bb4行目 </p>



1行目
2行目
3行目
4行目

4行のテキストを用意しました。CSSも記述します。

.alt_text { position:relative; line-height:1.5; } .svgarea { position:absolute; left:0; top:0; z-index:-1; }

テキスト要素のstyleと、後ほど追加するSVG領域のstyleもあらかじめ書いておきます。この2つは「position:relative」と「:absolute」の関係を持たせることで、同じ位置に重なるようにします。

SVG用のz-indexは「 -1」とし、テキスト要素の背面に回り込みませます。
また「left : 0」としたのは、テキスト要素のpadding-leftが指定されていた場合に影響をうけないようにするためです。

line-heightは明記する必要あり。

ここでテキスト要素に対し、line-heightの指定を明記しておく必要があります。
line-heightの初期値は「normal」です。これは、指定されたfont-family独自のデフォルト値に依存する、という意味です。

のちほどJavaScriptを使ってline-heightを「数値」として取得。それを背景に追加する長方形のheightに適用させるのですが、初期値の「normal」が返ってくるとこれは数値ではないのでheight値に適用することができません。

値は任意ですが、例えば今ご覧になっているテキストのline-heightは「1.5」です。
皆さんのデザインに合った値でかまわないので、CSS内にちゃんと数値で明記しておいてください。

JavaScriptを実装。


それではJavaScriptによる処理を書いていきましょう。

「「3//class要素を取得」」「「1 ..①」」 const altText = document.querySelectorAll(".alt_text"); 「「3//偶数行と奇数行の色を決める」」「「1 ..②」」 let color1 = "#d0e2b5"; let color2 = "#fff";


① 「alt_text」クラスの要素を取得します。
要素がページ内に複数あることを想定して、querySelectorAll( )を使っています。

② 偶数行と奇数行の色を決めておきます。のちほど長方形を生成する際に色を指定しても構わないのですが、後から変更したい場合。 グローバルな場所で変数に入れておくほうが、使い勝手がよくなります。

次にテキスト領域にぴったりと収まる、SVG領域を生成します。

「「3//クラス要素それぞれに処理を施す」」「「1 ..③」」 altText.forEach(function(value){ 「「3//SVG領域の生成」」「「1 ..④」」 let svgarea = document.createElementNS("http://www.w3.org/2000/svg","svg"); 「「3//テキスト要素と同じ幅/高さにする」」「「1 ..⑤」」 svgarea.setAttribute("width","100%"); svgarea.setAttribute("height","100%"); 「「3//CSSを適用」」「「1 ..⑥」」 svgarea.classList.add("svgarea");


③ ここでもclass要素が複数あることを想定して、forEach( )で全体の処理を行います。

④ SVGを生成しています。
HTML内で新たにSVGを生成するときにはcreateElementではなく、createElementNSを使い、第1引数にSVGの名前空間を指定する必要があります。
これは、その子要素についても同様です。

⑤ 生成したSVG領域はviewBox定義を持たせていないため、widthとheightを「100%」にしてやると、親要素である<p>の領域にぴったりとフィットします。

⑥ SVGに対し、事前にCSSで記述していた内容を適用させます。

このあと色違いの長方形を生成して、SVG領域に追加していきましょう。
一旦サンプルコードを区切りますが、まだforEach( )の中にいます。注意してください。

「「3//現在表示されている行数を取得」」「「1 ..⑦」」 let style = window.getComputedStyle(value); let lineCount = parseFloat(style.height)/parseFloat(style.lineHeight); 「「3//行数の数だけ長方形を生成→追加」」「「1 ..⑧」」 for(i = 0;i<lineCount;i++) { 「「3//長方形を生成」」「「1 ..⑨」」 let sikaku = document.createElementNS("http://www.w3.org/2000/svg","rect"); 「「3//幅と高さを指定」」「「1 ..⑩」」 sikaku.setAttribute("width","100%"); sikaku.setAttribute("height",style.lineHeight); 「「3//偶数行と奇数行で色を変える」」「「1 ..⑪」」 if(i%2 === 0) { bbsikaku.setAttribute("fill",color1); } else { sikaku.setAttribute("fill",color2); } 「「3//現在の行の高さだけy値をずらす」」「「1 ..⑫」」 sikaku.setAttribute("y",`${parseFloat(style.lineHeight)*i}px`); 「「3//SVG領域に追加」」「「1 ..⑬」」 svgarea.appendChild(sikaku); } 「「3//テキスト要素に追加」」「「1 ..⑭」」 value.appendChild(svgarea); })「「3 //←forEach閉じ」」


⑦ はじめに色違いの長方形を「何個作るか」を決めるために、テキスト要素の行数を調べます。
デバイスの画面幅や、PC上でのウィンドウの大きさによってテキスト要素全体のheightは可変します。実際に表示されている高さを取得するには、getComputedStyle( )を使用します。「実際の高さ」を「実際のlineheight」で割ってやると、事実上表示されている行数が得られます。

⑨ 長方形の生成には、やはりcreateElementNSを使います。

⑩ 長方形の幅と高さを属性値にて指定。
widthは100%。つまりテキスト領域の幅に合わせます。
heightはline-heightの値を適用することで、1行分の高さにフィットさせます。

⑪ ここで偶数行/奇数行ごとに違う色を指定します。
「i%2」とすると、偶数なら「0」、奇数なら「1(elseの状態)」になるので、はじめに決めていた2つの色をそれぞれ指定しましょう。

⑫ 繰り返し生成された長方形を親のSVGにそのまま追加すると、同じ位置(領域の上端)に重ねられた状態になってしまいます。ので、それぞれの位置を行に合わせてずらしていく必要があります。
n行目に位置する長方形のy座標は、「 n *( line-height ) 」となります。これをy属性に指定しましょう。

⑬ 長方形をSVG領域に追加します。

⑭ ここまで整ったら、最後にSVGをテキスト要素に追加。

1行目
2行目
3行目
4行目

結果がこちら⬆︎。
1行ごとに背景色が変更されています。お疲れ様でした!

あとは自動で。


最後までお読みくださり、ありがとうございます。
今回は<table>などの図表式要素ではなく、単なるテキスト要素で1行ごとに背景色を変更する、というものを作ってみました。

このように1度作成しておけば、あとはテキストをペシペシとタイプするだけで、自動で「1行ごとの色違い」が表示されます。色変更についても<script>の最初のところで変数にしてありますので、好みのカラーを代入してつかってみてください。<rect>要素にstroke(枠線)を付けてもいいかもですね。

ではまた〜 ♪



JavaScriptのドルマーク$に中括弧{ }、テンプレートリテラルについて。

2022.02.09
クオテーション祭り、さようなら。


JavaScriptのforEachとは? 〜配列のループメソッドについて。

2022.03.24
HTML要素の一括編集にも。


JavaScript、乱数の範囲や重複を指定〜Math.random使い方。

2021.11.17
整数/範囲/重複の有無を自在にあやつろう。

JavaScriptコードの「?」をまとめたページはこちら⬆︎。











「ふ」です。

swift、web、ガジェットなど。役立つ情報や観ていてたのしいページを書いていきたいと思います。