CSS 相對/絕對(relative/absolute)定位系列(三)

來源:互聯網
上載者:User
文章目錄
  • 一、absolute正業之元素隱藏
  • 二、absolute與等高布局
  • 三、absolute屬性與IE6/IE7之間的誤會
  • 四、下節看點

by zhangxinxu from http://www.zhangxinxu.com
本文地址:http://www.zhangxinxu.com/wordpress/?p=1528

//zxx:直接接上回

一、absolute正業之元素隱藏

元素隱藏與顯示是我們在頁面製作與互動效果實現中非常常見的,如果您只是使用display:nonedisplay:block/inline來實現DOM元素的顯隱控制,那你就out了。就元素的顯示與隱藏實現,使用display在有些時候算是比較糟糕的方法了。

控制元素顯隱的方法很多,但是本文不是講元素顯隱控制的,所以,只講與absolute相關的一些方法。
absolute屬性相關的隱藏方法,我知道的有三種,分別如下:

.hidden{
position:absolute;
top:-9999em;
}

.hidden{
position:absolute;
visibility:hidden;
}

.hidden{
position:absolute;
clip: rect(1px 1px 1px 1px); /* IE6, IE7 */
clip: rect(1px, 1px, 1px, 1px);
}

使用absolute屬性控制DOM元素的顯隱有三個關鍵點:頁面可用性迴流與渲染配合JavaScript的控制

① 可用性隱藏
所謂可用性隱藏,就是兼顧螢幕助讀程式這類互連網閱讀輔助裝置的隱藏方式。Yahoo! 可用性實驗室成員Ted Drake就不同隱藏方法下螢幕助讀程式的可用性問題作為測試,結果發現下面兩種隱藏方式螢幕助讀程式是讀不了的。

.completelyhidden {
display:none;
}

.visibilityhidden {
visibility:hidden;
}

You don’t want to show those hidden panels to any user. Use display:none for the hidden panels.

Screen readers will also ignore sections with visibility:hidden.

所以,從可用性角度而言,像“選項卡內容”,“更多收合展開”這類元素隱藏與顯示就不推薦使用display:none, 或者是position:absolute + visibility:hidden

例如優酷網電影或視頻的簡介中“顯示詳情”的實現就是使用的display:none,如下:

而福士點評網的隱藏層多採用position:absolute + visibility:hidden的方法,如下:

上述隱藏內容其實都是有用的資訊,對於像盲人這類需要藉助螢幕助讀程式的使用者無法知道這些資訊了。拿優酷的那個例子,盲人使用者就無法知道影片完整的簡介。

如果希望隱藏內容能夠被輔助閱讀裝置識別,就不能使用display:none以及visibility:hidden隱藏元素。可以使用類比隱藏的隱藏方法,又稱可用性隱藏。就是下面兩種隱藏方法。

.hidden{
position:absolute;
top:-9999em;
}

.hidden{
position:absolute;
clip: rect(1px 1px 1px 1px); /* IE6, IE7 */
clip: rect(1px, 1px, 1px, 1px);
}

但是,如果你是希望完全隱藏的,那就可以使用display:nonevisibility:hidden

額外說明:如果隱藏元素含有連結元素或是可獲得焦點的控制項元素,但是又是使用的可用性隱藏。這些隱藏的連結與控制項也是可以響應鍵盤焦點Tab切換的,但是這會讓鍵盤使用使用者產生不解與疑惑的。所以,從某種意義說,某些情況下,要兼顧螢幕助讀程式使用者和鍵盤使用者有時候是不可兼得的。

②迴流與渲染
早先時候我曾翻譯過兩篇關於迴流與重繪的文章,“最小化瀏覽器中的迴流(reflow)”以及“迴流與重繪:CSS效能讓JavaScript變慢?”。

我自己是沒測過。不過根據上面這兩篇文章的說法,以及一位口碑前端前輩的說法,使用absolute隱藏於顯示元素是會產生重繪而不會產生強烈的迴流。而使用display:none不僅會重繪,還會產生迴流,DOM影響範圍越廣,迴流越強烈。所以,就JavaScript互動的呈現效能上來講,使用absolute隱藏是要優於display相關隱藏的。

③配合JavaScript的控制
說到元素的顯示與隱藏,免不了與JavaScript的互動。例如display相關的隱藏於顯示,就是display:block/inline/inline-block/...display:none
要讓元素隱藏,很簡單,直接:

dom.style.display = "none";

但是,如果要顯示隱藏的元素,咋辦呢?因為不同的標籤所處的display水平是不一樣的,於是,我們很難有一個簡單的統一的顯示方法。例如,下面的代碼可能使用於div, p標籤,但是對於span等inline水平的元素,可能就會嗝屁了(原本單行顯示結果換行)。

dom.style.display = "block";

況且,隨著瀏覽器的不斷進步,以後類似於display:table-celldisplay:list-item會越來越多的使用。再想通過display實現通用的顯隱方法難度又會增大些。

這就是使用display屬性控制元素顯隱的局限性。順帶一提的是jQuery的顯隱方法show()/hide()/toggle()就是基於display的,其會儲存元素先前的display屬性值,於是元素再顯示的時候就可以準確地顯示出之前的display值了。

您可以狠狠地點擊這裡:jQuery與display的顯隱測試

而使用絕對位置實現的一些元素隱藏方法的控制就相對簡單很多的。例如:position:absolute + visibility:hidden方法,當我們要讓元素(原本非絕對位置元素)顯示的時候,我們需要設定:

dom.style.position = "static";
dom.style.visibility = "visible";

而類似的position:absolute + top:-999em方法,當我們要讓元素(原本非絕對位置元素)顯示的時候,我們只需要設定:

dom.style.position = "static";

而無需擔心原本標籤的是inline水平還是block水平。所以,就顯隱的JavaScript控制上來講,absolute相關方法要比display略勝一籌。

結合上面三點討論,我們可以看出,當前佔據主流的display:block/none控制元素顯示與隱藏的方法其實是諸多方面有弊端的方法,有拿著雞毛當令箭的意味。實際上,這種活(元素顯隱)交給absolute屬性更合適,控制元素顯示與隱藏才是absolute屬性的正業所在。//zxx: display屬性控制元素顯隱之所以會控制大半壁江山是因為其語義就是“顯示(display)”,於是先入為主,再加上人的從眾性。

如果您看到下面的文字,可能是由於在其他網站或是RSS中閱讀本文,本文原地址:http://www.zhangxinxu.com/wordpress/?p=1528,本文作者:張鑫旭,來自張鑫旭-鑫空間-鑫生活,訪問原出處更多優秀技術文章。二、absolute與等高布局

拿簡單的兩欄布局舉例,左欄與右欄有不同的背景色,且中間隔邊框線分隔,如何??因為隨著內容的不同,有可能左側欄高度較高,也有可能是右側欄高度較高。所以,要實現無縫的填色,定高不行不通的,置高度不理顯然也不行,此時解決方案就是讓左右兩欄等高。

我較早的時候寫過一篇名為“純CSS實現側邊欄/分欄高度自動相等”的小tip,其實現原理如下:

margin-bottom:-3000px; padding-bottom:3000px;

後來在“我所知道的幾種display:table-cell的應用”一文中也提過使用display:table-cell實現等高布局。

這裡再介紹些如何使用absolute實現等高布局。

正如系列前篇所述,應用了position:absolute的元素無寬度,無高度。正好,我們可以利用該特性來實現等高布局所需要的效果——如等高的背景色、邊框效果等。

您可以狠狠地點擊這裡:絕對位置與等高布局demo

點擊demo頁面中的兩個按鈕就可以看到無論左側欄高還是右側欄高,兩邊背景顏色純純的,中間的垂直分隔線直直的,如下:

其中,實現等高效果的核心CSS代碼如下:

.equal_height{width:100%; height:999em; position:absolute; left:0; top:0;}

同時,滿足以下一些條件:

  1. 高度999em的絕對位置層位於側欄容器內,側欄positionrelative
  2. 該欄實際元素內容用一個與absolute絕對位置層為兄弟關係的標籤層包裹,positionrelativez-index1或其他
  3. 左右欄的父標籤需設定overflow:hidden,同時為了相容IE6/7,需設定positionrelative

以上條件對應標註:

原理很簡單:由於絕對位置元素無高度的特性無寬度的特性,我們可以偽造一個高度足夠高的絕對位置層(設定背景色,邊框等屬性),同時設定父標籤溢出隱藏,那麼其多出來的高度酒不會顯示了,也就實現了看上去的等高布局效果了。具體細節可參見demo頁面中的代碼展示,相信很好理解的。

如果您看到下面的文字,可能是由於在其他網站或是RSS中閱讀本文,本文原地址:http://www.zhangxinxu.com/wordpress/?p=1528,本文作者:張鑫旭,來自張鑫旭-鑫空間-鑫生活,訪問原出處更多優秀技術文章。三、absolute屬性與IE6/IE7之間的誤會

absolute屬性確實存在不少相容性的問題,首先absolute屬性定位相關(left/top)的些bug(例如IE6的奇偶bug)這裡不予以討論。//zxx:很多人都知道,再說就沒意思了。

所以,下面所展示的些“誤會”都是沒有定位屬性的(即無left/top/right/bottom)。

1. margin定位元素絕對位置元素重疊的誤會
以前經常碰到的,今天怎麼都類比不出來了,這個先空著,回頭補上…… (*^__^*) 嘻嘻……

補充於2011-04-18
很簡單,雙欄調適型配置中,左側元素absolute絕對位置,右側的margin撐開距離定位。可參見“頁面重構鑫三無準則 之無寬度準則”一文中新浪微博的執行個體頁面中的使用(那裡是padding撐開距離)。

為了再現IE6/IE7下的這個argin定位元素絕對位置元素重疊的誤會,我特地做了個簡單的demo頁面,您可以狠狠地點擊這裡:IE6/7下margin與absolute元素重疊demo

可以看到在IE6/7下左側應用了absolute屬性的圖片與右邊的自適應的文字內容重疊了,如所示(截自IE7):

此問題出現的原因與下面浮動與絕對位置元素重疊有著某些類似的原因,因為問題的出現都與絕對位置元素所在的標籤水平有關:上述demo中,absolute屬性所在的標籤是div標籤,屬於block水平的元素。如下:

要是我們把這裡的block水平的div元素修改成inline水平的span標籤,則重疊的問題就沒有了。如下:

您可以狠狠地點擊這裡:IE6/7下margin與absolute元素重疊問題修複demo

如果您手上的瀏覽器是即使是IE6/IE7,點擊上面的demo頁面也不會有重疊的bug了,而此問題的修複是非常簡單的將div標籤換成span,如下所示:

2. 浮動與絕對位置元素重疊的誤會
很簡單,前面一個標籤是浮動元素,後面的是block水平的絕對位置元素,結果IE8+,以及現代瀏覽器文字與圖片重疊;但是IE6/IE7瀏覽器確是並排顯示的。如下示意:

您可以狠狠地點擊這裡:浮動元素絕對位置元素重疊demo

CSS代碼如下:

.box{padding:1em; background-color:#f0f3f9; overflow:hidden; _zoom:1;}
.l{float:left;}
.abs{position:absolute;}

HTML代碼如下:

<div class="box">
<img class="l" src="http://image.zhangxinxu.com/image/study/s/s128/mm1.jpg" />
<div class="abs">呦喝,這不是張含韻小姐嗎?</div>
</div>

為何現代瀏覽器以及IE8+瀏覽器下浮動的圖片與絕對位置的文字會重疊,而IE6/7卻是並列顯示?這是由於IE6/IE7瀏覽器將inline水平標籤元素和block水平的標籤元素沒有加以區分一視同仁渲染了。我在前面已經多次提到,應用了絕對位置屬性的元素具有包裹性,等同於沒有高度與寬度的inline-block元素

上面斜體加粗的這個結論實際上說得不夠嚴謹,在IE6/IE7瀏覽器下,上面的話是沒錯的;在所有瀏覽器下,對於inline水平的元素,上面的話也是沒錯的;但是在現代瀏覽器下,對於block水平的元素,上面的結論就有商榷之處。實際上,按照正確的絕對位置渲染,像div, p這類block水平標籤並未完全inline-block化。inline-block化的元素有三大特性:包裹性;高寬可定義;圖文混排。然而,div, p這類標籤應用了position:absolute後,在非IE6/7瀏覽器下,只有包裹性和高寬可定義這兩個特性,但並不支援圖片混排,也就是與圖片文字在一起的時候會換行。

下面是舉例字,驗證上面的結論。首先是這麼句話:“對於inline水平的元素,上面的話也是沒錯的”。這句話的意思其實是,如果是inline水平的元素,上面的那個樣本就不會有相容性問題了,於是我們把應用了abs類名的div標籤改成span,如下HTML代碼:

<div class="box">
<img class="l" src="http://image.zhangxinxu.com/image/study/s/s128/mm1.jpg" />
<span class="abs">呦喝,這不是張含韻小姐嗎?</span>
</div>

結果如:

不僅IE8瀏覽器,Firefox/Chrome等先前重疊的現在都並排顯示了。

您可以狠狠地點擊這裡:浮動與inline水平絕對位置元素不重疊demo

下面再來驗證這個結論:“現代瀏覽器下block水平元素absolute化後不支援圖片混排”。也是很簡單的,我們可以把最上面重疊的那個例子的圖片的浮動屬性幹掉,也就是如下的HTML代碼:

<div class="box">
<img src="http://image.zhangxinxu.com/image/study/s/s128/mm1.jpg" />
<div class="abs">呦喝,這不是張含韻小姐嗎?</div>
</div>

結果如:

而在IE6/IE7瀏覽器下,依舊是並排顯示滴,如:

OK,現在應該很好理解最上面為何在現代瀏覽器片文字重疊而IE6/IE7下並排顯示了。

在“CSS float浮動的深入研究、詳解及拓展”系列中多次闡述了浮動元素的“無高度”特性,所以,當圖片應用了float:left屬性後,圖片所佔據的高度丟失,於是,原本換行顯示在下面的文字就提上去了,於是就形成了重疊,如標示:

四、下節看點

下篇講relative屬性,內容包括:
relative的佔位性;
relative最小化影響原則;
relative在一些bug中的修複功能;
等……

時間倉促,資質有限,文章難免有表述不準確或是理解有誤的地方,歡迎指正,不甚感謝。

原創文章,轉載請註明來自張鑫旭-鑫空間-鑫生活[http://www.zhangxinxu.com]
本文地址:http://www.zhangxinxu.com/wordpress/?p=1528

(本篇完)

相關文章

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.