JavaScript で取得した値・計算した結果を CSS に反映する方法
CSS には四則演算が行える calc() 関数があります。この中で使えるのは px, em, %, vw といった長さや割合の数値のみ。表示されている画面のサイズや解像度といったシステム情報は利用できません。
一方で JavaScript を使えば、システム情報のデータで取得できます。CSS 内で計算できない、取得できない値を使いたい場合は、JavaScript を使うことで簡単に CSS へ反映できます。
ではその手順を解説していきましょう。
ここで紹介する JavaScript のサンプルプログラムは、処理の起点(onclick で処理が動くとか、function で呼び出されるとか)を意識した記述をしていません。用途に応じて適宜書き換えてご利用ください。
新しいスタイルを定義する場合
【お題】width を指定する新しいクラス test01 を追加
以下の2つのプログラムの違いは、HTML に style タグが存在するかどうかの違いです。2つ目のプログラムの場合、style タグが存在していても有効なプログラムなので、1つ目の処理はおまけ程度に捉えてください。
// style タグの要素を取得 var style = document.getElementsByTagName("style"); // セットする値 var setVal = (取得した値や計算結果を格納); // 既存の style タグに新しいクラスを追加 style[0].sheet.insertRule ( ".test01 { width:" + setVal + "px; }", 0 );
// head タグに style タグを挿入 var style = document.createElement("style"); document.head.appendChild( style ); // セットする値 var setVal = (取得した値や計算結果を格納); // 追加した style タグに新しいクラスを追加 style.sheet.insertRule ( ".test01 { width:" + setVal + "px; }", 0 );
ポイントは、CSS を style タグに追加する API である insertRule() メソッドを使っている点です。CSS のために用意されたものなので、存在だけでもぜひ覚えておいてください。
既存のスタイルを変更する場合
まず大前提として、style タグ内のデータや CSS ファイルの内容を書き換える API はありません。ちょっとしたプログラムを組む必要があり、その対応方法にもいくつかパターンが存在します。
- style タグを削除して新しい style タグを追加
- 書き換えが発生するクラスを定義しているタグに複数クラスを設定して対応
- HTML の末尾に style を定義して強制上書き
どれも処理として正解ではあるものの、おすすめは2つ目の複数クラスを定義した対応です。言葉だけではピンとこないと思うので、それぞれのプログラムをご覧ください。
【お題】既存クラス test02 の内容を再定義する
書き換えが必要な CSS を個別の style タグに定義して、JavaScript でそのタグを丸ごと削除した上で再定義する流れです。プログラムの仕組みとしてはあまり美しくはないですね。
// style タグ定義 or link タグで外部 css 呼び出し <style>...</style> // or <link rel="style" href="..../xxx.css"> // 書き換えが発生する CSS は別で定義しておく <style id="excss"> .test02 { max-width: 400px; } </style>
// style タグ id="excss" の要素を削除 var elmCss = document.getElementById("excss"); // IE11 を無視していいならこの処理 elmCss.remove(); // IE11 での動作を保証したいならこの処理 elmCss.parentNode.removeChild(elmCss); // 削除した style タグを再定義(同じクラス付きで定義) var style = document.createElement("style"); document.head.appendChild( style ).classList.add("excss"); // セットする値 var setVal = (取得した値や計算結果を格納); // 追加した style タグにクラスを再定義 style.sheet.insertRule ( ".test02 { max-width:" + setVal + "px; }", 0 );
4行目の element の削除処理 remove() は IE11 に未対応です。6行目の処理は IE11 に対応しているので、利用環境に応じてどちらか一方を定義しておけば大丈夫です。
【お題】test02 クラスを持つタグに別クラスを定義して CSS を上書き
書き換えが必要なクラスを指定しているタグに、何も CSS を定義していないクラスを並列で記載しておくのがポイント。CSS 定義を上書きするよりも、拡張定義してそちらが優先的に使われるようにする方法なので、プログラム的にはとてもわかりやすい処理になります。
// style タグ定義 or link タグで外部 css 呼び出し <style> ... .test02 { max-width: 400px; } ... </style> // or <link rel="style" href="..../xxx.css"> // HTML のソース上は CSS 定義のない expansion クラスを並列で記載 <div class="test02 expansion">.....</div>
// 新しい style タグを定義 var style = document.createElement("style"); document.head.appendChild( style ); // セットする値 var setVal = (取得した値や計算結果を格納); // 追加した style タグに新しいクラスを追加 style.sheet.insertRule ( ".test02.expantion { max-width:" + setVal + "px; }", 0 );
ポイントは .test02.expantion で CSS を定義してる点です。スペースを空けずにくっつけて記載することで、test02 と expantion のクラスが定義されている要素を対象にします。
.test02 の定義よりも .test02.expantion と記述したほうが CSS 反映の優先度が高いので、元々あった .test02 の定義をそのまま残していても影響がありません。
【お題】HTML の末尾に style を定義して test02 クラスの内容を強制上書き
CSS の定義で同じクラスの内容が複数定義されていた場合は、ソースコードの後に記述があるものが優先される仕組みを利用した方法です。つまり body 終了タグの直前に style タグを追加して、既存の定義を残したまま強制的に上書きしてしまいます。
// style タグ定義 or link タグで外部 css 呼び出し <style> ... .test02 { max-width: 400px; } ... </style> // or <link rel="style" href="..../xxx.css">
// セットする値 var setVal = (取得した値や計算結果を格納); // 新しい style タグをベタ書きで定義 var styleVal = "<style>.test02 { max-width:" + setVal + "px; }</style>" // body タグの要素を取得 var elm = document.getElementsByTagName("body"); // body 終了タグの直前 (beforeend) に作成した style タグを直接追加 elm[0].insertAdjacentHTML( 'beforeend', styleVal );
まとめ
JavaScript で計算した値、取得した値を CSS に反映する方法として、いくつか対応手段を紹介しました。CSS 定義された内容を JavaScript から直接更新する方法がないため、少し工夫が必要になるもののそこまで難しい処理ではありません。
僕自身のおすすめは2番目の複数クラス定義です。HTML を見ても処理用のクラスが用意されているので、将来ソースコードを修正する時にもわかりやすいです。他に動的な変更が必要なクラスがあれば、同様に expansion クラスを追加定義するといったルールを決めておくのも悪くないですね。
とは言え、プログラムは動けばそれが正解だったりもするので、好みの処理を使えば良いと思います。