2011年09月07日

DOMで既存スタイルシートにルールを追加してはいけない

JavaScriptでスタイルシートを操作するには?

JavaScriptで既存HTMLページにCSSを追加する必要が出て来たのでちょっと調べた。
基本的に、document.styleSheetslink要素やstyle要素で読み込まれるスタイルシートが配列風(実際は配列ではない)に参照出来、insertRuleで新規にルールを追加出来るようだ(ただし例によってInternet Explorer以外。IE死ね!)。

const styleSheets = document.styleSheets;
// これで、
//  styleSheets[0] = 1つ目のlink或いはstyleで導入されているスタイルシート
//  styleSheets[1] = 2つ目のlink或いはstyleで導入されているスタイルシート
// ……といった感じでアクセス出来る。
const styleSheetsNum = styleSheets.length;	// スタイルシートの数

styleSheets[0].insertRule(	// ルールの追加;一番最初のスタイルシートに……
	"a { font-weight: bold; }",	 // ←のルールを……
	0);	// 0番目(対象スタイルシート先頭)に挿入。
const ruleNum = styleSheets[0].cssRules.length;	// ルールの数
styleSheets[0].insertRule("h1 { color: #000; }", ruleNum);	// ←で、スタイルシートの最後にルールを追加出来る。

で、こういった事を解説している、

なんかでは、document.styleSheetsの一番最後にルールを追加するようなコードを載せてる。

でもこれっておかしくない?

スタイルシートのメディアタイプ

link要素もstyle要素も、mediaという属性を持っている。対象のスタイルシート(linkの場合はスタイルシートに限らないが)を適用する媒体を指定する物だ。例えばmedia="screen"ならばコンピュータのディスプレイに、media="print"であれば印刷時に適用される。

さぁ、もしもdocument.styleSheetsの最後のスタイルシートのmediaが予期しない物だったら?

という訳で、検証用のHTMLを書いてみた。

ソース中にスタイルシートを規定している要素は2つ。どちらもstyle要素である。1つめのmediascreenであり、もう片方はprintである。

<style type="text/css" media="screen">/* <![CDATA[ */
	#applies { background-color: #aaaaff; }
/* ]]> */</style>
<style type="text/css" media="print">/* <![CDATA[ */
	#applies { border: 1px black solid; }
/* ]]> */</style>

そして、一番最後のスタイルシートにinsertRuleを行うと……

const ssheets = document.styleSheets;
const ssheet = ssheets[ssheets.length - 1];

ssheet.insertRule('#applies { font-weight: bold; }', ssheet.cssRules.length);

JavaScriptで追加したfont-weightはどうなったか?PCのディスプレイでの表示と、その印刷プレビューのキャプチャを以下に示す。スタイルシート適用先の要素である"APPLIES"と書かれている部分に注目。Firefox 6.0にて確認。
[PCディスプレイでの表示結果; media= [印刷時表示(印刷プレビューでの確認); media=

PCディスプレイ側には適用されず、印刷側には適用されている。

これでは、HTMLCSS、JavaScriptを複数人で分業している場合、混乱が生じるのではないか。個人開発でも、上で挙げている解説ページのように関数化して常用していると躓く可能性がある。

既存スタイルシートの操作ではなく、新規にスタイルシートを生成する

ここは『既存のスタイルシートにルールを追加する』のではなく、『ルールを追加する為の新規スタイルシートを追加する』べきだろう。

JavaScript初級者から中級者になろう:五章第三回 CSSの操作CSSStyleSheetの追加と削除を参照すると、style要素を生成し、そのsheetプロパティにアクセスすれば良いようだ。

var style = document.getElementsByTagName('head')[0].appendChild(document.createElement('style'));
style.type = 'text/css';
style.sheet.insertRule(追加するルール, style.sheet.cssRules.length);

では、例えばそのページのメンテナンスをするのが自分自身であり、mediaに関する問題を起こさないと言える時には『最後のスタイルシートにルールを追加』しても良いのだろうか?そうは思えない。

昨今のwebブラウザはアドオンをサポートしている物が多い。それらは勿論の事、Greasemonkeyのように、ページに対し閲覧者が任意のスクリプトを実行する場合さえある。それら(或いは彼ら)が、ページ中にスタイルシートを追加しないとどうして言い切れるだろうか。

Skype Extension for Firefox と Security error" code: "1000 - てっく煮ブログではSkype Extension for Firefox はお行儀が悪いと言っているが、少なくともスタイルシートに関しては、その意見に同意出来ない。幾つもの要素をページ中に挿入するアドオンの場合、生成した全ての要素のstyleプロパティを同一の内容にするよりも、1つのスタイルシートを生成した方がより利口だろう。nitoyon氏の書いたJavaScriptの方が"お行儀が悪い"のではないだろか。

posted by 天井冴太 at 12:51| Comment(2) | TrackBack(0) | Study | 更新情報をチェックする
この記事へのコメント
Hello! Do you use Twitter? I'd like to follow you if that would be okay. I'm undoubtedly enjoying your blog and look forward to new posts. agfcebadefdk
Posted by Johnk371 at 2014年05月30日 18:44
Thank you for your comment, Johnk371.
I have Twitter account, but I stopped what use it.
Alternatively, I'm using Google+ ( https://plus.google.com/110360324196605830601 ).
Posted by 天井冴太 (AmaiSaeta) at 2014年05月31日 01:29
コメントを書く
コチラをクリックしてください

この記事へのトラックバック