2009年01月15日
[JavaScript] 如何讓 reset.css 和 HTML 預覽功能並存?
問題描述
現在 CSS 排版技術越來越盛行,很多網頁設計師為更精準地控制頁面呈現效果,都會使用 reset.css 來將 HTML 元素在瀏覽器的預設呈現效果給移除 (例如 YUI 的 reset.css 或 Eric Meyer 的 reset.css ) 。
雖然這個技術很好用,但在需要讓客戶自訂畫面的專案上就會遇到一個問題:如何讓客戶的 HTML 呈現出瀏覽器原本預設的效果?
像 YUI 有提供一個 base.css ,可以稍微幫我們將 HTML 元素回復原本的呈現方式。但我們有時只是需要在畫面上一小部份轉換為原來的效果,這時就勢必得修改 base.css ,在它的各項元素定義前加上某區塊的 class 或 id ;不過這不是一個好選項,因為大多數狀況我們還是沒辦法百分之百讓畫面呈現它原本的樣子。
解決方案
其實用 iframe 就可以幫我們解決這個問題。
步驟很簡單:
- 建立一個動態 iframe 。
- 將原本的 html 內容指定給 iframe 的 document 。
- 把 iframe 高度調整至和 html 內容一般高。
這裡我用 jQuery 來實作囉。
建立一個動態 iframe
假設我們的 html 內容已經放在 div.htmlContent 這個區塊中,我們可以用以下程式來動態建立一個 iframe ,並將它 append 在 div.htmlContent 中。當然也別忘記把原來的內容清掉:
$(function () {
var $iframe = $('<iframe src="about:blank" width="100%" height="300" frameborder="0"></iframe>');
var $htmlContent = $('div.htmlContent');
var html = $htmlContent.html();
$htmlContent.html('');
$htmlContent.append($iframe);
}
這裡要注意一點,就是 iframe 的高度一定要設定一個大於 0 的整數值,不然等一下 IE 在自動調整高度時會出問題。 (別問我為什麼...我也是自己試出來的 Orz)
至於 iframe 的來源,我們設定為 about:blank 就好,也就是瀏覽器預設的空白頁。
將原本的 html 內容指定給 iframe 的 document
在建立好動態的 iframe 之後,我們要先等它將內容載完。在載完之後,我們就可以將原來的 html 放到 iframe 裡的 docuement 物件的 body 中。
$iframe.load(function () {
var iframeDocument = getIframeDocument($iframe.get(0));
$(iframeDocument.body).html(html).css({ margin: '0', padding: '0' });
});
這裡用到了一個自訂函式 getIframeDocument , 它可以幫我們取得 iframe 裡的 document 物件,而且是跨瀏覽器的:
function getIframeDocument(iframeObject) {
if (iframeObject.contentWindow) {
return iframeObject.contentWindow.document;
} else if (iframeObject.contentDocument) {
return iframeObject.contentDocument.document;
}
return null;
}
註:getIframeDocument 暫時不支援 Google Chrome 和 Safari 。
把 iframe 高度調整至和 html 內容一般高
接著我們要調整 iframe 的高度,讓它能完整呈現出 html 的內容。
在 html 載入完畢後,body 的 offsetHeight 就會是我們所需要的內容高度:
$iframe.load(function () {
var iframeDocument = $.wacow.getIframeDocument($iframe.get(0));
$(iframeDocument.body).html(html).css({ margin: '0', padding: '0' });
setTimeout(function () {
var bodyHeight = iframeDocument.body.offsetHeight + 20;
$iframe.height(bodyHeight);
}, 0);
});
這裡有個小技巧,就是重新指定 html 內容時, load 事件並不會被觸發,所以我們要利用 setTimeout 來確定 html 已經全部加載完畢 (讓它跳離到另一個執行空間) 。
到這裡就大功告成啦~謝謝收看~
