window.getComputedStyle for IE6+ (その2)
ちょっと手直しして、
- メインロジックはそのまま
- コード量を 12% DOWN
- minify + zip で 1.1kB
- option = 0x0 の速度を 20% 〜 35% UP
IE8 | 1.375ms ⇒ 1.094ms |
IE6 | 1.875ms ⇒ 1.218ms |
- option = 0x0 で列挙するプロパティを ホワイトリスト式 ⇒ ブラックリスト式 に変更
- option = 0x0 で列挙するプロパティが A-Z 順でソート済の状態に
- IE9 に window.getComputedStyle が実装されなかった場合を考慮
- IE6, IE7 で動かした場合に、IE8 固有の CSS プロパティを列挙しないようした
- IE の各バージョンで、列挙されてくるプロパティ数が変化するということ
といった版を作りました。
- window.getComputedStyle(node, pseudo) では以下のプロパティを列挙しません。
- accelerator, behavior, hasLayout, zoom
- hasLayout 状態を調べるには node.currentStyle.hasLayout を直接参照してください
- window.getComputedStyle(node, pseudo, 0x1) では以下のプロパティを列挙しません。
- GALAPAGOS:
- accelerator, behavior, hasLayout, zoom, filter, styleFloat, ms*, scrollbar*
- SHORT HAND:
- borderColor, borderStyle, borderWidth, margin, padding, outline
- MINOR:
- blockDirection, orphans, quotes, widows
- imeMode, writingMode, unicodeBidi, emptyCells, tableLayout
- layout*, ruby*, text* (textAlign textOverflow textIndent除く), pageBreak*
- GALAPAGOS:
- window.getComputedStyle(node, pseudo, 0x2) では以下のプロパティのみを列挙します。
- borderBottomWidth, borderLeftWidth, borderRightWidth, borderTopWidth
- marginBottom, marginLeft, marginRight, marginTop
- paddingBottom, paddingLeft, paddingRight, paddingTop
- top, left, width, height, fontSize, cssFloat
速度向上のためにやったこと
- for in ループは遅いので while ( (v = ary[i++]) ) ループに変更
- 列挙するプロパティの一覧を、初期化処理内で事前作成
window.getComputedStyle || (function() { var _PT = /pt$/, _FULL = [], _MORE = [], _BOX = [], _MOD = { top: 1, left: 2, width: 3, height: 4 }, _UNIT = { m: 1, t: 2, "%": 3, o: 3 }, // em, pt, %, auto _THICK = (document.documentMode || 0) > 7 ? "5px" : "6px"; window.getComputedStyle = winstyle; function winstyle(node, // @param Node: pseudo, // @param String(= void 0): option) { // @param Number(= 0x0): // 0x0: enum full properties // 0x1: enum more properties // 0x2: enum some properties // @return Hash: { prop: "val", ... } if (!node.currentStyle) { return {}; } var rv = {}, ns = node.style, cs = node.currentStyle, rs = node.runtimeStyle, em, rect, unit, v, w, x, i = 0, j = 0, m1, m2, ary = !option ? _FULL : (option === 1) ? _MORE : 0, stock = { "0px": "0px", "1px": "1px", "2px": "2px", "5px": "5px", thin: "1px", medium: "3px", thick: _THICK }; if (ary) { while ( (w = ary[j++]) ) { rv[w] = cs[w]; } } em = parseFloat(cs.fontSize) * (_PT.test(cs.fontSize) ? 4 / 3 : 1); rect = node.getBoundingClientRect(); // calc border, padding and margin size while ( (w = _BOX[i++]) ) { v = cs[w]; if (!(v in stock)) { x = v; switch (unit = _UNIT[v.slice(-1)] || 0) { case 1: x = parseFloat(v) * em; break; // em case 2: x = parseFloat(v) * 4 / 3; break; // pt case 3: m1 = ns.left, m2 = rs.left; // %, auto rs.left = cs.left, ns.left = v; x = ns.pixelLeft, ns.left = m1, rs.left = m2; } stock[v] = unit ? x + "px" : x; } rv[w] = stock[v]; } for (w in _MOD) { v = cs[w]; switch (unit = _UNIT[v.slice(-1)] || 0) { case 1: v = parseFloat(v) * em; break; // em case 2: v = parseFloat(v) * 4 / 3; break; // pt case 3: // %, auto switch (_MOD[w]) { case 1: v = node.offsetTop; break; case 2: v = node.offsetLeft; break; case 3: v = (node.offsetWidth || rect.right - rect.left) - parseInt(rv.borderLeftWidth) - parseInt(rv.borderRightWidth) - parseInt(rv.paddingLeft) - parseInt(rv.paddingRight); v = v > 0 ? v : 0; break; case 4: v = (node.offsetHeight || rect.bottom - rect.top) - parseInt(rv.borderTopWidth) - parseInt(rv.borderBottomWidth) - parseInt(rv.paddingTop) - parseInt(rv.paddingBottom); v = v > 0 ? v : 0; } } rv[w] = unit ? v + "px" : v; } rv.fontSize = em + "px"; rv.cssFloat = cs.styleFloat; // compat alias return rv; } // init - make _FULL, _MORE, _BOX props (function() { var ary = [" "], i, w, trim = /^\s+|\s+$/g, cs = document.getElementsByTagName("html")[0].currentStyle; for (i in cs) { ary.push(i); } ary.sort(); w = ary.join(" ").replace(/ (?:accelerator|behavior|hasLayout|zoom)/g, ""); _FULL = w.replace(trim, "").split(" "); _MORE = w.replace(/ (?:lay\w+|rub\w+|text\w+|pageB\w+|ms\w+|scr\w+)/g, ""). replace(/ (?:blockDirection|orphans|quotes|widows|filter|styleFloat)/g, ""). replace(/ (?:imeMode|writingMode|unicodeBidi|emptyCells|tableLayout)/g, ""). replace(/ (?:border(?:Color|Style|Width)|margin|padding|outline) /g, " "). replace(/ (border\w+Width|margin\w+|padding\w+)/g, function(_, m) { return _BOX.push(m), _; }).replace(trim, "").concat(" textAlign textOverflow textIndent"). split(" ").sort(); })(); })();