IE6で透過PNGをサポートする
まず、IE6では24bit png(α成分による透過)をサポートしていません。256色pngの透過はサポートしていますが、256色pngではセクシーな表現ができんのですよ。
IE8β1が出たこの時期にいまさらIE6用に透過png(24bit png)機能をサポートするのはどうなんだろう? と思いましたが、あと2年ぐらいは使われそうな気がするので、uupaa.jsの機能の一部としてサポートすることにしました。
参考にしたのは、http://blog.kaburk.com/lang/html/ie-penetration-png.html とか。
使い方。
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>24bit PNG test</title> <!--[if IE]><script type="text/javascript" src="../lib/xpath.js"></script><![endif]--> <script type="text/javascript" src="../uupaa.js"></script> <style> body { background-color: black; } div { background: black url(../img/burning_sunset.jpg); } </style> </head> <body> <div> <img src="../img/png24.png" alt="" /> <!-- 24bit PNG image --> <img src="../img/kuma24.png" alt="" /> <!-- 24bit PNG image --> </div> <img src="../img/png24.png" alt="" /> <!-- 24bit PNG image --> <img src="../img/kuma24.png" alt="" /> <!-- 24bit PNG image --> </body> </html>
- ../lib/xpath.js は、id:amachang が紹介しているIE用のxpathの実装です。JavaScript-XPath で入手できます。
- ../uupaa.js は uupaa.jsで配ってるライブラリです。
JavaScriptで動的にpng画像を追加する場合は、uu.fixIEPNG24(動的に生成したimg要素) を呼び出します。
uu.fixIEPNG24()に渡す引数は、要素の配列でもOKです。
んで、以下が今回の機能追加に関係する部分です。1x1.gif は、uupaa.jsと同じディレクトリにあるものとします。
var uu = window.uu = { "#": { basePath: "", // uupaa.js base path enablePNG24: true, // true: IE5〜6でAlphaPNGを自動的にサポートする, false: しない }, /** uupaaへの通知 * * スクリプト読み込み完了通知: notify("included", script-file-name) */ notify: function(msg, param) { switch (msg) { case "IEHack": uu.fixIEPNG24(uu.xsnap('//img[translate(substring(@src,string-length(@src)-3),".PNG",".png")=".png"]')); break; } }, /** support alpha PNG(PNG-24) for IE5.5/IE6.0 * * @param element/array elms image-element or [image-element, ...] */ fixIEPNG24: function(elms) { if (!(/MSIE (5\.5|6\.0)/.test(navigator.userAgent) && navigator.platform == "Win32")) { return; } if (!uu.id("1x1")) { // <img id="1x1" src="${uu["#"].basePath}/1x1.gif" ... /> var e = document.createElement("img"); e.id = "1x1"; e.style.display = "none"; document.body.appendChild(e); e.onload = function() { uu.fixIEPNG24(elms); }; e.src = uu["#"].basePath + "1x1.gif"; return; } var src1x1 = uu.id("1x1").src; elms = uu.isA(elms) ? elms : [elms]; elms.forEach(function(v) { var org = { w: v.width, h: v.height }; v.style.filter = 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src="' + v.src + '",sizingMethod=scale)'; uu.mix(v, { src: src1x1, width: org.w, height: org.h }); }); } }; // IE Hack if (uu.ua.ie && uu["#"].enablePNG24) { uu.registWindowEvent("onload", function(){ uu.notify("IEHack"); }); } // search "uupaa.js" file path. uu.xsnap('//script[substring(@src,string-length(@src)-7)="uupaa.js"]', "src").forEach(function(v) { uu["#"].basePath = v.replace(/uupaa\.js/, ""); });
足りない部品は、こっち
var uu = window.uu = { /** protected member */ "#": { events: {}, }, ua: { ie: !!(window.attachEvent && !window.opera), // Internet Explorerでtrue }, isF: function(mix) { return typeof(mix) === "function"; }, // isFunction isA: function(mix) { return mix.constructor === Array; }, // isArray id: function(id) { return (typeof id === "string") ? document.getElementById(id) : id; }, args: function(arg, defaultValue) { return (typeof arg === "undefined") ? defaultValue : arg; }, mix: function(src, mixer) { if (typeof mixer !== "object") { return src; } for (var p in mixer) { src[p] = mixer[p]; } return src; }, forEach: function(obj, iter, thisp /* = undefined */) { if (!obj || typeof iter !== "function") { throw TypeError(); } if (typeof obj.forEach === "function") { return obj.forEach(iter, thisp); } for (var p in obj) { obj.hasOwnProperty(p) && iter.call(thisp, obj[p], p, obj); } return this; }, xsnap: function(xpath, attr, ctx, sort) { var n = document.evaluate(xpath, uu.args(ctx, document), null, uu.args(sort, true) ? 7 : 6, null); var rv = [], i = 0; attr = uu.args(attr, ""); if (attr.length) { for (; i < n.snapshotLength; ++i) { rv.push(n.snapshotItem(i)[attr]); } } else { for (; i < n.snapshotLength; ++i) { rv.push(n.snapshotItem(i)); } } return rv; }, registWindowEvent: function(name, fn) { var n = "window." + name, evt = uu["#"].events; if (!(n in evt)) { // at first time evt[n] = []; window[name] = function() { uu.forEach(evt[n], function(v) { uu.isF(v) && v(); }); } } evt[n].push(fn); } };
今回の反省会(03/09)
- 予想外に時間かかったよ。結局一日がかりだった。
追加の反省会(03/12)
- <img id="1x1" src="1x1.gif" ... >方式は問題があることが判明
- なんかコードがごっちゃりと長いので、スッキリしたコードも載せるほうが良いのかね?
- それは他の人に任せればよさげ。探せば何ぼでも見つかるし。
- そか。
- それは他の人に任せればよさげ。探せば何ぼでも見つかるし。
- 背景画像やhover等に透過png使いたいってニーズは? 現状は<img src="*.png">のみ気にしてるけど。
- わからん。ニーズがあったら考える。
さぁ、反省おわり。
Let's スケスケ。
2008-04-12 追記:
XPathが無くても動作するように実装を変更しました。http://pigs.sourceforge.jp/wiki/index.php?uupaa.js で最新版の動作デモをやってます。
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>24bit PNG test</title> <style> body { background-color: black; } div { background: black url(./burning_sunset.jpg); } </style> </head> <body> <div><img src="./png24.png" alt="" /><img src="./kuma24.png" alt="" /></div> <img src="./png24.png" alt="" /><img src="./kuma24.png" alt="" /> <script> var uu = window.uu = { mix: function(mapSrc, mapMixer) { for (var p in mapMixer) { mapSrc[p] = mapMixer[p]; } return mapSrc; }, toArray: function(map) { var rv = new Array(map.length || 0), i = 0, sz = rv.length; for (; i < sz; ++i) { rv[i] = map[i]; } return rv; } }; if (document.uniqueID && /MSIE (5\.5|6\.0)/.test(navigator.userAgent) && navigator.platform == "Win32") { uu.fixIEPNG24 = function(elms) { var d = document, e = d.getElementById("1x1gif"), w, h; if (!e) { d.body.appendChild(uu.mix(d.createElement("img"), { id: "1x1gif", onload: function() { uu.fixIEPNG24(elms); } })).src = "./1x1.gif"; } else { e.style.display = "none"; ((elms instanceof Array) ? elms : [elms]).forEach(function(v) { w = v.width, h = v.height; v.style.filter = 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src="' + v.src + '",sizingMethod=scale)'; uu.mix(v, { src: e.src, width: w, height: h }); }); } } } if (!Array.prototype.forEach) { Array.prototype.forEach = function(iter, bindThis /* = undefined */) { var i = 0, sz = this.length; for (; i < sz; ++i) { (i in this) && iter.call(bindThis, this[i], i, this); } return this; }; } window.onload = function() { if (document.uniqueID) { var png = []; uu.toArray(document.images).forEach(function(v) { if (v.src.match(/.png$/i) && v.complete) { png.push(v); } }); uu.fixIEPNG24(png); } }; </script> </body> </html>