designjs Wiki

designjs のWikiページへようこそ。

Design.js の機能

概要

 Design.jsは、.cssテキストやstyleタグではなく、JavaScriptを使用してCSSルールをメモリ上にダイレクトに作成するモジュールです。単純な書き間違いJavaScriptの文法エラーとして表面化させることができます。
 また、同じブラウザでも、バージョンによって対象が異なるベンダープレフィックスも、一切、指定する必要がありません。「Design.js」が、ブラウザに問い合わせて、適切なプレフックスを付与してルールを作成します。これにより、誤ったプレフィックスによってスタイルが無効になる問題は避けられます。プレフックスの確認作業は不要となり、同じ要素を重複して記述する必要もありません。

 さらに、要素や値に変数や関数の戻り値が利用できるので、解像度やブラウザ(種類、バージョン、スクリプト・エンジン)といった動作環境によって、動的に適用するスタイルを切り替えることもできます。たとえば、PC、タブレット、スマートフォンで、それぞれに適したスタイルを生成することができます。これは、指定に柔軟性のないメディア・クエリを使用するよりも容易です。どんなブラウザにも対応するように、ムダに同じ意味の指定をズラズラならべることも必要なくなります。

 CSSテキストをlinkタグで読み込むように、アプリケーションの起動時にすべてのデザイン・ルールを構築していしまうというのが、もっとも単純な利用法です。それに加え、CSSルールそのものを動的に変更することできるので、ユーザの操作に従って、ページの外観を一度に変更したり、コンテンツの配置を変更するというテクニックも利用できます。
 従来では、エレメントのstyle属性を書き換えるか、必要なだけ、クラスを使ったルールをズラっと定義しておき、エレメントのクラス属性を入れ替えるという方法しかありませんでした。Design.jsの活用は、こうした硬直化した開発手法に代わり、より自然で柔軟性のある解決策を提供します。

開発の経緯

 cssテキスト(linkタグで取り込むファイルまたは、styleタグ内に書かれるテキスト)は、記載にミスがあってもhtmlファイルの表示やJavaScriptの実行を妨げません。
 期待したスタイルがブラウザに読み込まれないことによる表示の崩れCSSアニメーションの不実行があるだけで、それは人間が目にして初めて認識されることになります(ブラウザの開発ツールによってエラーを知る方法はあります)。

 重要な要素であるデザインが、cssテキストの文法エラー(セレクタの指定方法の間違いや、ルール内の文字列のクォーテーションの閉じ忘れ)で「エラー」とならずに、製品としてサーバに配置される危険性は、html/JavaScriptアプリケーションの配布をビジネスとする上で、致命的な欠陥といわざるを得ません。
 ブラウザの開発ツールやチェックサイトを使用することで、開発時に確認することも可能ですが、そのチェック作業は容易にスキップされがちです。

 もっとも懸念されるのは、ちょっとした修正のつもりの書き換えによって、修正した箇所は正常でも、それまで正常に動いていたルールを巻き込んで無効にしてしまい、表示に異常をきたしたアプリケーションがエンドユーザの目にさらされる危険性がついて回るという現実です(クォーテーションの閉じ忘れが、まさにコレを引き起こします)。多くの場合、「ちょっとした修正」の対象しか確認しないために、「まき沿い」を食った箇所が未確認のままに放置されるからです。この問題を、ブラウザはアラートしません。

 もう1つの重要な問題は、CSSテキストは固定した値であるという点です。ユーザの選択やアプリケーションのコンテキストによって動的な変化をもたらそうとすると、たちまちスクリプトを巻き込んだ、膨大かつ複雑な記述に追い回される羽目になってしまいます。

 Webアプリを作成する上で、こうした障害をいかに克服し、効率的な開発に導けるか、これがDesign.jsの大きなテーマです。

主な機能

(1) オブジェクトのルール化

Design.castメソッドにObjectクラスのインスタンスを渡すことによって、中に定義されているプロパティを「セレクタ」としたスタイル・ルールが生成されます。
下記の例では、セレクタやルールを文字列で指定していますが、スクリプトなので、当然、変数関数の戻り値が利用できます。
    Design.cast({
        ...................................
        "body": {
            "font-size": "100%",
            "font-family": "Robot,sans-serif",
            ...................
        },

        ".main_panel": {
            ...................
            "box-sizing": "border-box",
            ...................
        }
        ...................................
        ...................................
    });

 キー部分はスタイルのセレクタなので、「.<クラス名>」のようにJavaScriptにとっての演算子や、ハイフンやスペースが入ることもあるので、文字列定数で指定します。擬似要素も、そのまま含められます。

1つのキーに対して、複数の値を設定したい場合は、値を配列にします。グラデーションのように、ブラウザによって表記が異なる場合などに使用します。

    Design.cast({
        "background": ["-moz-linear-gradient(left, rgba(255,255,255,1) 0%, rgba(246,246,246,1) 47%, rgba(237,237,237,1) 100%)",        
                       "-webkit-gradient(linear, left top, right top, color-stop(0%,rgba(255,255,255,1)), color-stop(47%,rgba(246,246,246,1)), color-stop(100%,rgba(237,237,237,1)))"]
    });

(2) 文字列のルール化

 Design.create()メソッドに、cssテキストに指定するのに等しいテキストを与えることで、新しいスタイルシートを作成します。  この場合は、ルールを個別に指定するのではなく、1つのスタイルシートに含めるすべてのルールを指定できます。

重要  このメソッドでは、ベンダー・プレフィックスの自動検索などの機能が利用できないので、「セレクタ{ルール}の形式による通常のスタイル指定に使用するのは適当ではありません

 上記のようにオブジェクト化ができない、特殊な文法であるcssアニメーションの作成が適しています。

 文字列での指定なので、内部に変数や関数の戻り値を含められるのは、当然です。また、必要なベンダー・プリフックスも、アプリケーション・フレームワークから取得できるのであれば、同じルールをベンダーごとに複数指定する無駄は排除できます。

Design.create(
    "@" + (N3C.getAnimationInfo())[0] + "keyframes media_playing {" +
        "0% {}" +
        "100% {" + (N3C.getAnimationInfo())[0] + "transform: rotate(360deg) }" +
    "}\n"
);

    // N3C.getAnimationInfo()は、N3というフレームワークを使用した例です。
    // フレームワークが自動検出したベンダー・プレフィックスを付加しています。

(3) CSSルールの削除

 メソッドDesign.remove()を使用することでDesign.cast()で定義したCSSルールをメモリ上から削除できます。

注) linkタグやstyleタグで作成されたルールは削除できません。

    Design.remove(".my_class");

(4) デバッグモードによるミスの検出

 「Design.enableDebugging(true);」を実行すると、それ以降の「Design.cast()」によるルール作成時に指定した「実際に存在しないスタイル名」が記録されるようになります。

 存在しない名前は、「Design.fetchUnknowns()」によって文字列配列として取得できます。

    Design.enableDebugging(true);

    .............................
    .............................

    Design.cast({
        .............................
        .............................
        ".main_pane": {
            "wide": "100px",        // 'width をwideとミスタイプ
            "high": "200px"         // 'height をhighとミスタイプ
        },
        .............................
        .............................
    });

    .............................
    .............................

    // 上記のwideとhighが配列で取得できる
    var not_founds = Design.fetchUnknowns();
    for ( var i = 0, sz < not_founds.length; i < sz; i++ ) {
        console.log("Unknown: [" + not_founds[i] + "]");
    }

    .............................
    .............................

    Design.enableDebugging(false);  // これ以降は記録されない