margin系列之聖盃拾遺

margin系列之佈局篇 一文結尾時,咱們談到了聖盃佈局,說這個佈局的實現自己存在了一些問題:「在IE6/7下報廢,不過不用慌,由於它可被修復」。css

聖盃佈局的一些談資

下面節選一段來自網路上對聖盃的描述(略有調整):html

聖盃是宗教傳說中的聖物,耶穌曾經用這個杯子吩咐門徒喝下里面象徵他的血的紅葡萄酒,藉此創立了受難記念儀式。由於這個特殊的緣由,後來有些人認爲這個杯子具備某種神奇的能力。不少傳說相信,若是能找到這個聖盃而喝下其盛過的水就將返老還童、死而復生而且得到永生,這個傳說普遍延續到不少文學、影視、遊戲等做品中。瀏覽器

而所謂的聖盃佈局也並非一個具象的形容,更多的是指借但願於它可以實現某種特殊的佈局。ide

這種特殊佈局的需求是:側邊欄寬度固定,主內容欄寬度自適應,而且須要將主內容欄放在側邊欄前面,以便優先渲染(不管是兩欄或者三欄,需求都是同樣的)。佈局

遺留的問題

在 margin系列之佈局篇 裏,咱們用聖盃佈局作了 圖0 的效果。測試

圖0:classsic layout

圖0:classsic layoutspa

下面是咱們在上篇文章中寫的聖盃佈局核心代碼(固然,這個 #demo 容器你也能夠利用 body來取代):code

HTML

1
2
3
4
5
6
7
8
<div id="demo">
    <header id="hd">頭部</header>
    <div id="bd">
        <div id="main">主內容欄自適應寬度</div>
        <aside id="aside">側邊欄固定寬度</aside>
    </div>
    <footer id="ft">底部</footer>
</div>

CSS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#demo {
    width: 80%;
}
#bd {
    *zoom: 1;
    overflow: hidden;
    padding-left: 210px;
}
#main {
    float: left;
    width: 100%;
}
#aside {
    _display: inline;
    float: left;
    position: relative;
    left: -210px;
    width: 200px;
    margin-left: -100%;
}

你們可使用各類瀏覽器來測試一下這個示例 聖盃:左欄固定主內容自適應htm

通常狀況下,你會發現除了IE6外,其它的瀏覽器看起來都算正常,然而問題的範圍可能並不只限於這些,大部分問題沒被看出只不過是由於沒到達邊界。blog

問題列表:

  • IE6 佈局錯亂,側邊欄位置不對;
  • IE7 resize窗口時,側邊欄會跳動;
  • IE7及其它瀏覽器,當窗口縮小到主內容欄的寬度小於側邊欄的寬度時,佈局錯亂;

上面這幾個問題,你們其實均可以本身去測測看,應該是當前的實現中都存在的。

對於第3點,咱們看看上述的代碼實現,仍是能很是輕鬆的理解的。由於側邊欄定義了 margin-left: -100%,在這個場景中,100% 其實就等同於主內容欄的寬度。若是主內容欄的寬度小於側邊欄,那麼側邊欄偏移了一個比本身小的寬度,天然是放不下本身的。

對於第1點,這個就有點意思了,基本上這又算是IE6的一個Bug,描述一下這個Bug的現象:

在IE6中,假定是處於默認的書寫模式下,當一個浮動的元素定義了margin的值是一個百分比,那麼此時,浮動元素的margin百分比參照最近的清除了浮動的包含塊的父元素的寬度進行計算,或者參照body。(然而標準描述只是參考包含塊的寬度進行計算,詳情請參閱我以前的文章 margin系列之百分比

我會用一段僞代碼來詳述這個事,代碼以下:

1
body > c > b > a

假設上述代碼中的 a 就是咱們說的浮動元素,正常狀況下 a 設置了一個百分比的margin,百分比是要參考 b 的寬度進行計算的。

而後 IE6 並無實現這個規則,它的特徵是:

  • 浮動元素 a 定義了百分比的margin,假設它的祖先元素 b 和 c 都沒有清除浮動,那麼就會參照 body 的寬度進行百分比換算;
  • 假設 b 清除了浮動,那麼就會參照 c 的寬度進行百分比換算;

對於這個Bug,我寫了一個示例,你們能夠對照着描述來看這個例子:浮動margin百分比在ie6上的Bug

好了,知道了在 IE6 中有這個Bug以後,關於問題列表中的第1點,咱們就也可以理解了,由於 position: relative; left: -210px; 這個定義對於 IE6 來說,實際上是多餘的。

對於第2點,應該是在resize過程當中,不斷的重繪形成的,它須要不斷的去計算這個百分比的使用值。

殺死它們

因此若是想使得聖盃佈局變得更靠譜一些,咱們要麼就是見招拆招,修復這個問題(好比說爲 IE6 重置掉 position: relative; left: -210px; 定義),要麼就避免趕上這些問題,我更喜歡第二種的方式。

咱們如何作才能避免趕上這些問題?

其實咱們能夠細看一下,問題列表中的幾點,其實都是因浮動元素的margin百分比引起的。既然浮動元素的margin百分比,在各瀏覽器下須要差別化處理,那麼幹脆棄用百分比,改用固定值(複雜度其實並無上升,由於用百分比的時候,還得給left定義一個固定的偏移量)。

那麼,新的問題來了。若是改用margin固定值,咱們要如何知道這個固定值是多少?好比在這個佈局中咱們的容器寬度是視窗的 80%,咱們沒法獲得側邊欄須要偏移的固定值是多少,除非咱們使用運算表達式 calc(),可是它的兼容性並非咱們想要的。

這是由於主內容欄和側邊欄都是左浮動,而且側邊欄浮動在主內容欄後面,因此咱們須要讓側邊欄偏移 #main + #aside 的寬度,才能讓側邊欄出如今正確的位置。

因此,其實咱們能夠轉變一下思路,讓主內容欄和側邊欄朝不一樣的方向浮動,這樣的話,側邊欄只須要偏移自身的寬度就能出如今正確的位置上,不在須要使用margin百分比值。

新路

咱們按照前面說的將代碼調整一下,HTML不變:

CSS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#demo {
    width: 80%;
}
#bd {
    *zoom: 1;
    overflow: hidden;
    padding-left: 210px;
}
#main {
    float: right;
    width: 100%;
}
#aside {
    _display: inline;
    float: left;
    width: 200px;
    margin: 0 10px 0 -210px;
}

咱們來看看這個 進化的聖盃:左欄固定主內容自適應 效果,你會欣喜的發現,問題列表中的3個問題都被咱們跳過了,這是一個更健康的實現。

固然,它也是能夠任意調整列呈現順序的,咱們只須要這樣就行:

CSS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#demo {
    width: 80%;
}
#bd {
    *zoom: 1;
    overflow: hidden;
    padding-right: 210px;
}
#main {
    float: left;
    width: 100%;
}
#aside {
    _display: inline;
    float: right;
    width: 200px;
    margin: 0 -210px 0 10px;
}

因而咱們就獲得了一個 進化的聖盃:右欄固定主內容自適應 的佈局。

整體來說,聖盃佈局只是有能力達成咱們的需求,但就其自己來說並非太先進的佈局,靈活性相對侷限。

另外,你可能關注到了代碼中出現的 margin 定義,它並非一個單純的負值,而是多了一個 10px,這實際上是爲了解決 IE6/7 右浮動子元素的向右負偏移量最大隻能是自身寬度的問題(感興趣的童鞋能夠看看這個測試:右浮動margin-right負值在ie67上的bug),因此額外處理的間隙,但這其實並不影響其餘瀏覽器。

最後

本文,更多的在於補全以前的那篇文章,算個簡單的完結。本意其實並不在於說讓你們去折騰那些古老而無趣的瀏覽器,而是但願看到的是對待任何事情,咱們首先要以爲它能夠解決,而後再抽絲剝繭的去實現它。未知並不可怕,可怕是恐懼未知。

相關文章
相關標籤/搜索