JavaScriptでCSSパーサーを書くための情報を収集中(5日目)
はい。5日目です。今日は「収集したルールを元に、要素にスタイルを適用する」です。
レガシーとかインラインとかは無かったことに
昨日は、レガシースタイルとインラインスタイルを収集して重み付けしましたが、今日はそのへんバッサリと削ってます。
# よくよく考えたら、いらない処理でした。
今日実装した部分
PHASE1〜2 を実装しました。PHASE3 は色々懸案事項があるので実装していません。
PHASE1. uuCSSParser.parse() STEP1. でスタイルを収集する STEP2. スタイルを重み付けでソートする(legacy, inlineは収集せず) PHASE2. uuCSSParser.execute() STEP1. uuCSSParser 専用のスタイルシート(_sheet)を追加する STEP1. spec0 から 999 までの各ルールにIDを付ける STEP2. ".uucssp" + ID なルールを _sheet に追加 STEP3. specが大きい順に CSSセレクタで要素を検索し、 該当する要素の className の先頭に、"uucssp" + ID を追加 STEP4. className を改変した目印として、element.uuCSSParser = "1" を設定 PHASE3. 未実装 STEP1. spec1000以上の各ルールにIDを付ける STEP2. CSSセレクタで要素を検索し、 要素の計算済みのスタイルと、!important で指定されたスタイルとの 違いを検査。違いがあれば、element.style を直接改変する STEP3. element.style を改変した目印として、classNameに uuCSSParser = "2" を設定
http://uupaa-js-spinoff.googlecode.com/svn/trunk/uuCSSParser.js/uuCSSParser.js
(function() { var _cssp, // inner namespace _mm = uuMeta, _win = window, _doc = document, _autoExec = !_win.UUCSSPARSER_DISABLE_AUTOEXEC, // 1 = disable auto execute _ie = _mm.ie, _sheet = 0, // private style sheet _urule = {}, // unique rule _uid = 0, // unique id /* 略 */ _cssp = { // uuCSSParser.parse - CSS Parser parse: function(css) { // @param CSSString(= ""): // @return Hash: { specs: [spec-num1, spec-num2, ...], // data[spec-num1]: { rule, expr, decl }, // data[spec-num2]: ... } var specs = [], data = {}; _ie && _cssp._memento(); if (!css) { css = _cssp._importStyleSheets(); } _cssp._collectStyleSheets(specs, data, css); specs.sort(function(a, b) { return b - a; }); // sort of number(10 -> 1) return { specs: specs, data: data }; }, // uuCSSParser.execute - CSS Executor execute: function(hash) { _cssp._createStyleSheet(); var v, w, i = 0, j, k, iz = hash.specs.length, jz, kz, spec, data, expr, id, node; for (; i < iz; ++i) { spec = hash.specs[i]; data = hash.data[spec]; if (spec >= 10000) { // !important // not impl. } else { for (j = 0, jz = data.length; j < jz; ++j) { expr = data[j].expr; id = _urule[expr] || (_urule[expr] = ++_uid); _cssp._addRule(".uucssp" + id, data[j].decl.join(";")); node = uuQuery(expr); for (k = 0, kz = node.length; k < kz; ++k) { v = node[k]; w = v.className; v.className = "uucssp" + id + (w ? " " : "") + w; v.uuCSSParser = "1"; } } } } }, // uuCSSParser.recalc recalc: function() { _urule = {}, _uid = 0; // reset _sheet && _cssp._deleteRule(); // delete all var node = uuQuery("[uuCSSParser=1]"), v, i = 0, iz = node.length; for (; i < iz; ++i) { v = node[i]; v.className = v.className.replace(/uucssp[\d]+\s*/g, ""); v.uuCSSParser = "0"; } _cssp.execute(_cssp.parse()); }, /* 略 */ }; // --- initialize --- function autoexec() { _cssp.execute(_cssp.parse()); _mm.event.unbind(_win, "load", autoexec); } _autoExec && _mm.event.bind(_win, "load", autoexec); _win.uuCSSParser = _cssp; // export })(); // uuCSSParser scope
何ができるようになったか
古いブラウザで、最新のCSSが動作します。
<style> div ul>li:nth-child(-n+3) { background-color: silver } div ul>li:nth-child(even) { color: red } </style>
デモ
IE6, IE7, Opera9.2x, Opera9.5x, Opera9.6x, Firefox2 なんかの古いブラウザで実行すると、わかりやすいと思います。
- ページロードでスタイルを自動適用する版
- ページロードでスタイルを自動適用しない版
次回は…
うーん。どうしよう。