日々のコンピュータ情報の集積と整理

Dr.ウーパのコンピュータ備忘録

2014年6月12日木曜日

JavaScript:スタイルシートへスタイルを動的に追加する:試行錯誤の末にたどり着いたもの

イントロダクション

記事「Blogger:ボタンを押すと、ブラウザの幅いっぱいまでコンテンツを表示する (最低幅は固定)」にて、コンテンツの幅を動的に変更するために、スタイルシートへスタイルを動的に追加する JavaScript コードを作成しました。

このときに作成したスタイルシートへのスタイルの動的追加の JavaScript コードの特徴は以下の点です。


  • 外部 styleSheet へはスタイルを書き込めないことに対する対策を実施
  • 動的に追加したスタイルは一つのスタイルシート(新規作成)で管理
  • オブジェクトという形で追加先スタイルシートを保持


これらの特徴は独立したものではなく、外部 styleSheet へはスタイルを書き込めないため、その対策として新規作成した一つのスタイルシートで管理することになりました。その時に動作の高速化のために追加先スタイルシートを保持しようとした場合に、変数をグローバル化しないためにオブジェクトという形で管理することになりました。


Internet Explorer, Firefox, Chrome で動作するように調整を加えました。
今後同じ問題へぶち当たった人に向けてコードの公開と、解説をここに公開したいと思います。


コード


    // スタイルシートをコントロールする
    function CSSController() {

        /*
            スタイルを追加したいスタイルシートが外部シートの場合、
            Firefox 29 ではセキュリティエラーとなったので、
            新しいシートを追加してそこにスタイルを追加する方式とする
        */
        var sheet;          // スタイルを追加するスタイルシート

        /*
        スタイルシートに新しいルールを追加する

        selector : CSSのセレクタ
        styleName : スタイル名
        value : スタイルの値

        参考:http://bmky.net/text/note/javascript-css/
        http://ash.jp/web/css/js_style.htm
        */
        this.addRule = function (selector, styleName, value) {

            // 追加先スタイルシートが無い場合、新規作成
            if (!sheet) {
                var style = document.createElement("style");
                document.getElementsByTagName("head")[0].appendChild(style);
                sheet = style.sheet;
            }

            var ins_pos;
            if (sheet.addRule) {        // IE
                sheet.addRule(selector, styleName + ":" + value, sheet.rules.length);
            } else if (sheet.insertRule) {
                sheet.insertRule(selector + "{" + styleName + ":" + value + "}", sheet.cssRules.length);
            }
        }
    }


CSSController をオブジェクトとして生成した後、addRule メソッドによりスタイルをスタイルシートへ追加します。


最初はスタイルを既存のスタイルシートへ追加する実装を考えていましたが、Firefox 29 で試したところ、同一ドメインではない CSS ファイルから読み込まれた styleSheet へアクセスしたところ、セキュリティエラーとなり実行時エラーとなってしまったため、新しいスタイルシートを作成し、そこにスタイルを追加する形としました。(それ以前のどのバージョンからこのような動作仕様になっていたのかは調べていません。)

詳細:
 → JavaScript:Firefox:外部から読み込んだスタイルシートへは動的にスタイルを追加できない


Chrome でも試してみましたが、同一ドメインではない CSS ファイルから読み込まれた styleSheet の場合、styleSheet の rules が null であるものの、addRuleを行うとそのスタイルは Web ページに適用されました。ただし、追加後も rules が null のため、追加したスタイルへアクセスしたい場合にはどうやってアクセスしたらいいのかわかりませんが。


なお、Internet Explorer の場合は rules プロパティ と addRule メソッドを、Firefox の場合は cssRules プロパティと insertRule メソッドを切り分けて使用しています。

Chrome の場合には、そのどちらのプロパティとメソッドも保持しているため、上記のコードでいうと  rules プロパティ と addRule メソッドのルートで動作します。


使い方

以下のように CSSController のオブジェクトを作成した後、そのオブジェクトの addRule メソッドを使用して、スタイルを追加しています。

        var css = new CSSController();

        // コンテンツの幅を最大化
        css.addRule(".content-outer", "max-width", width);


このメソッドでは、スタイルシートの最後の部分に新しいスタイルを追加していきます。そのため、既に同じスタイルが定義されている場合には、後から追加したスタイルの方が既存のスタイルよりも優先されます。


なお、管理上、別々の styleSheet へスタイルを追加したい場合には、新しく CSSController のオブジェクトを作成した後、そのオブジェクトの addRule メソッドを使用して、スタイルを追加すれば、CSSController ごとに追加する styleSheet を選択することができます。


動作確認環境

Chrome

バージョン:35.0.1916.114 m

Internet Explorer

バージョン:9.0.8112.16421

Firefox

バージョン:29.0.1






関連記事

関連記事を読み込み中...

同じラベルの記事を読み込み中...