等高分欄佈局小結

来源:http://www.cnblogs.com/lyzg/archive/2016/02/01/5164593.html
-Advertisement-
Play Games

上一篇文章《聖杯佈局小結》總結了幾種常見的分欄佈局方法,這幾個方法都可以實現多欄頁面下,所有欄的高度可動態變化,某一欄寬度自適應的佈局效果,能滿足工作中大部分的佈局需求。後來我在搜集更多關於分欄佈局的文章時,發現了一個新的問題,這個問題在前面那篇文章中也有朋友在評論里跟我提起,就是如何在實現分欄佈局...


上一篇文章《聖杯佈局小結》總結了幾種常見的分欄佈局方法,這幾個方法都可以實現多欄頁面下,所有欄的高度可動態變化,某一欄寬度自適應的佈局效果,能滿足工作中很多佈局需求。後來我在搜集更多關於分欄佈局的文章時,發現了一個新的問題,這個問題在前面那篇文章中也有朋友在評論里跟我提起,就是如何在實現分欄佈局的同時保證每欄的高度相同。我發現這種等高分欄佈局的情況,在網站裡面其實也很常見,所以本文總結了幾種可用的方法來解決這個新的需求。

1. 方法一:萬能的flex

跟上篇文章不同,這次把flex這種方法放在了第一位,因為相比較起來,它是所有分欄佈局方法裡面,優點最多的,如果相容性允許的話,很有必要在任何時候都優先使用它完成頁面佈局。如果你打開上篇文章,找到倒數第二部分關於flex實現分欄佈局的代碼,或者把上篇文章提供的代碼下載下來,直接預覽flex_layout.html,你會發現上篇文章的那段代碼其實已經做到了等高分欄佈局,同一段代碼,可以實現上篇文章中提到的五種分欄佈局,還可以實現本文提到的等高佈局的情況,這種能力其它方法真的無法比擬。而它之所以能實現等高佈局,跟一個flex的css屬性有關係,這個屬性是:align-item。它的預設值是:stretch,在flex item元素比如layout__main或layout__aside的高度未定義或者為auto的情況下,會拉伸flex item元素的高度或寬度,鋪滿flex的交叉軸,詳細的原理可以通過上文提供的flex學習資源去瞭解,這裡只做一個簡單的引用說明。

2. 方法二:使用table或者偽table

上篇文章中還有另外兩種佈局方法沒有介紹,第一種就是這裡要說的table佈局或者偽table佈局。table佈局用的就是table tr td這些元素去實現,相信絕大部分web開發人員在入門html時,首先接觸到的佈局方法肯定就是table佈局了,這種方法簡單高效,用它做任何分欄佈局都不是問題,只是因為table的嵌套結構太多,html冗雜,又不利於DOM的操作和渲染,用來佈局不符合語義,總之缺點較多,所以目前的環境下,用的情況越來越少了。偽table佈局其實跟table佈局類似,只不過藉助於css,可以讓我們不直接使用table tr td這些直接的表格元素,而是通過display: table, display: table-row, display: table-cell,改變元素的顯示特性,讓瀏覽器把這些元素當成table來渲染,這種渲染的表現跟用真實的table沒有啥區別,就連那些table專用的css屬性,比如table-layout,border-collapse和border-spacing,都能產生效果。table佈局的方法已經很少被採用了,本文也就沒必要再去介紹,但是偽table佈局的方法值得學習一下,經過這兩天的學習,發現偽table的方式相比直接用表格佈局,有不少的優點,值得運用到工作中去。不過在說明使用偽table佈局的方法之前,得先瞭解一些偽table相關的知識:

1)可用於偽table表現的display屬性值有:

image

2)當把一個元素的display屬性設置成以上列出的值後,就可以把這個元素看成與該屬性對應的表格元素,比如table-cell對應的就是td;同時,這個元素會擁有跟表格元素一樣的特性,比如display: table或者inline-table的元素可以使用table-layout,border-collapse和border-spacing這三個原本只有table才能生效的屬性;display:table-cell的元素跟td一樣,對寬度高度敏感,對margin值無反應,對padding有效。

3)關於table-cell還有一點要說明的就是,它會被其他一些CSS屬性破壞,例如float, position:absolute,所以這些個屬性不能同時使用。

4)跟直接使用表格元素不同的是,在使用表格元素的時候需要完全遵守表格元素嵌套結構,也就是下麵這種:

<table>
    <thead>
        <th></th>
    </thead>
    <tbody>
        <tr>
            <td></td>
        </tr>
    </tbody>
    <tfoot>
        <th></th>
    </tfoot>
</table>

而使用偽table的那些屬性時,可以僅單獨使用某一個屬性,瀏覽器會在這些元素的外層包裹缺失的來保證偽table元素框嵌套結構的完整性,這些框跟常提到的行框一樣都是不可見的,網上有的文章里也把這種做法叫做匿名錶格。下麵的這個代碼中,tb-cell元素的外層沒有加display: table-row和display: table的元素:

.tb-cell {
    display: table-cell;
    padding: 10px;
    border: 1px solid #ccc;
}

<div class="tb-cell">這是第1個display: table-cell;的元素。</div>
<div class="tb-cell">這是第2個display: table-cell;的元素。</div>

但是看到的效果是(藍色背景是它們父層的一個包裹元素: width: 800px;margin-left: auto;margin-right: auto):

image

因為瀏覽器自動在這兩個元素的外層,加了跟能夠跟tr和table起相同作用的框,來包含這兩個元素形成的框,所以這兩個元素看起來就跟實際的表格效果一樣。假如瀏覽器沒有做這個處理,這兩個元素之間是不可能沒有間隙的,中間會有一個因為換行符顯示出來的空格。這種自動添加的框都是行內框,不是塊級框。

接下來看看如何通過這些偽table的屬性來完成上文的分欄佈局以及本文要求的等高分欄佈局,玩法有很多:(本文相關源碼下載

玩法一:模擬直接用表格佈局(對應源碼中table_layout1.html)

這種方法的思路是佈局時完全按照表格的嵌套層次來處理,把display: table, display: table-row, display: table-cell都用上,相當於就是利用完整的table來做,比如說要實現上文的佈局三(3欄佈局,2個側邊欄分別固定在左邊和右邊,中間是主體內容欄),就可以這麼乾:

<div class="layout">
    <div class="layout__row">
        <aside class="layout__col layout__aside layout__aside--left">左側邊欄寬度固定</aside>
        <div class="layout__col layout__main">內容欄寬度自適應<br>高度增加一點,旁邊的高度都會自動增加</div>
        <aside class="layout__col layout__aside layout__aside--right">右側邊欄寬度固定</aside>
    </div>
</div>
<style type="text/css">
    .layout {
        display: table;
        width: 100%;
    }
    .layout__row {
        display: table-row;
    }
    .layout__col {
        text-align: center;
        display: table-cell;
    }
    .layout__col + .layout__col {
        border-left: 10px solid #fff;
    }
    .layout__main {
        background-color: #4DBCB0;
    }
    .layout__aside {
        width: 200px;
        background-color: #daf1ef;
    }
</style>

效果還是那個效果,而且天生支持等高佈局:

image

這個佈局原理跟使用table是完全一樣的,所以使用起來非常容易(以上提供的是針對上文佈局三的實現,其它四個佈局的實現不會再一一介紹了,源碼裡面也不會提供,因為相對比較簡單)。

這種偽table佈局有什麼特點呢:

1)相比直接用表格元素,這種做法不需要考慮語義,表格元素是有語義的,主要是用來顯示網頁上列表型的數據內容,雖然可以完成佈局,但是佈局結構都是沒有語義的,所以直接用表格不合適,而這種偽table佈局的特點就是:它沒有語義,但是可以像表格那樣佈局;

2)html的層次結構相比直接用table元素也要簡單一些,我們這裡只用到了3層,直接用table元素的話可能還有tbody這一層;

3)相比上文提到的那些佈局方法,如聖杯佈局和雙飛翼佈局,這個做法在css方面相對簡單,在html方面也只多了一層嵌套;

4)缺點是分欄之間的間隔不能用margin和padding來做,如果用margin,這個屬性在display: table-cell的元素上根本不會生效;如果用padding,那像demo裡面各欄的背景色就都會連到一塊,做不出間隔的效果,如果在layout__col裡面再嵌套一層,在這一層設置背景色的話,又會增加html的層次,也不是很好。我這裡是投了個巧,用border處理了一下。

玩法二:去掉display: table-row(對應源碼中的table_layout2.html)

前面說過,瀏覽器會用匿名錶格的方式,添加缺失的框,所以玩法一中的代碼,把layout-row完全去掉,一點都不影響佈局效果:

<div class="layout">
    <aside class="layout__col layout__aside layout__aside--left">左側邊欄寬度固定</aside>
    <div class="layout__col layout__main">內容欄寬度自適應<br>高度增加一點,旁邊的高度都會自動增加</div>
    <aside class="layout__col layout__aside layout__aside--right">右側邊欄寬度固定</aside>
</div>
<style type="text/css">
    .layout {
        display: table;
        width: 100%;
    }
    .layout__col {
        text-align: center;
        display: table-cell;
    }
    .layout__col + .layout__col {
        border-left: 10px solid #fff;
    }
    .layout__main {
        background-color: #4DBCB0;
    }
    .layout__aside {
        width: 200px;
        background-color: #daf1ef;
    }
</style>

玩法三:去掉display: table(對應源碼中的table_layout3.html)

根據玩法二,可以試想一下是否能再把display: table這一個屬性給去掉,反正瀏覽器還會再添加框來包裹:

<div class="layout">
    <aside class="layout__col layout__aside layout__aside--left">左側邊欄寬度固定</aside>
    <div class="layout__col layout__main">內容欄寬度自適應<br>高度增加一點,旁邊的高度都會自動增加</div>
    <aside class="layout__col layout__aside layout__aside--right">右側邊欄寬度固定</aside>
</div>
<style type="text/css">
    .layout__col {
        text-align: center;
        display: table-cell;
    }
    .layout__col + .layout__col {
        border-left: 10px solid #fff;
    }
    .layout__main {
        background-color: #4DBCB0;
    }
    .layout__aside {
        width: 200px;
        min-width: 200px;
        background-color: #daf1ef;
    }
</style>

效果是:

image

這個並沒有達到我們的效果,因為我需要主體內容欄能夠自適應寬度。產生這個效果的原因是什麼,就是因為沒有加顯示display: table這一層,瀏覽器自動加了一個框,不過這個框是行內框,導致主體內容欄顯示的寬度就跟內容的寬度一致了。為瞭解決這個問題,可以這麼乾,html結構不變,css稍加改動:

.layout__main {
    width: 3000px;
    background-color: #4DBCB0;
}

.layout__aside {
    width: 200px;
    min-width: 200px;
    background-color: #daf1ef;
}

關鍵的代碼就是紅色新增的那兩行,首先給主體內容欄設置一個很長的寬度,而且只能用具體的長度設置,不能用百分比,然後給側邊欄設置一個最小寬度,免得主體內容欄把側邊欄的寬度給擠掉了。這個原理就是因為display: table-cell的作用,導致layout__main跟layout__aside表現出跟td元素一樣的特性,td預設的寬度就是可自動調整的,即使寬度設置的很大,也不會撐破table的寬度,這裡雖然那個自動添加的框看不到,但是這個框的最大寬度也就是瀏覽器的寬度,layout__main不會打破這個寬度的,所以可以放心使用。

玩法四:去掉layout這一層包裹元素(對應源碼:table_layout4.html)

如果網站比較簡單,去掉layout這一層包裹元素也是可以的:

<header>頂部</header>
<aside class="layout__col layout__aside layout__aside--left">左側邊欄寬度固定</aside>
<div class="layout__col layout__main">內容欄寬度自適應<br>高度增加一點,旁邊的高度都會自動增加</div>
<aside class="layout__col layout__aside layout__aside--right">右側邊欄寬度固定</aside>
<footer>底部</footer>
<style type="text/css">
    .layout__col {
        text-align: center;
        display: table-cell;
        line-height: 50px;
    }
    .layout__col + .layout__col {
        border-left: 10px solid #fff;
    }
    .layout__main {
        width: 3000px;
        background-color: #4DBCB0;
    }
    .layout__aside {
        width: 200px;
        min-width: 200px;
        background-color: #daf1ef;
    }
</style>

以上四種做法都能實現我們想要的分欄等高佈局,相容性方面,不考慮IE8及以下,其它瀏覽器幾乎沒有問題。

由於匿名錶格的作用,導致採用偽table佈局的方法變得非常簡潔,上文之所以沒提到這個做法,是因為完全不知道有匿名錶格這回事,我也是寫這篇文章才學習到的,學完之後,發現又找到了一個做分欄佈局的好辦法,希望前面的這些介紹能幫助你掌握好這個用法。實際上偽table的這些屬性,尤其是table-cell,用途非常多,本文沒有辦法一一介紹,但是能提供一個思路,將來工作中也許有很多其它佈局場景,我們都可以想想用table-cell來處理。

3. 方法三:使用絕對定位

上文沒有介紹的另外一種分欄佈局方法就是這裡要介紹的絕對定位。之所以沒介紹這個方法,是因為上文介紹的都是分欄自適應佈局的方法,而絕對定位的做法,不能完全做到我們想要的分欄自適應佈局,分欄自適應有兩個原則:第一是主體內容欄寬度自適應,這點絕對定位是可以做到的;第二點是所有欄的高度都能動態變化,並且不能導致父容器高度塌陷,不能在各欄內部出現滾動或溢出的情況,這點絕對定位不容易做到適用所有場景。而本文又把這種佈局方法拿出來介紹,是因為絕對定位做等高佈局很容易,所以用絕對定位做等高分欄佈局是一種可行的辦法,只是這種方法適用的場景有一些限制,需要根據實際情況考慮是否要採用。

做法一:所有欄都採用絕對定位(對應源碼中absolute_layout1.html)

<header>頂部</header>
<div class="layout">
    <aside class="layout__aside layout__aside--left">左側邊欄寬度固定</aside>
    <div class="layout__main">內容欄寬度自適應</div>
    <aside class="layout__aside layout__aside--right">右側邊欄寬度固定</aside>
</div>
<footer>底部</footer>
<style type="text/css">
    .layout {
        height: 300px;
        position: relative;
    }
    .layout__aside, .layout__main {
        position: absolute;
        top: 0;
        bottom: 0;
    }
    .layout__main {
        left: 210px;
        right: 210px;
    }
    .layout__aside {
        width: 200px;
    }
    .layout__aside--left {
        left: 0;
    }
    .layout__aside--right {
        right: 0;
    }
</style>

效果:

image

這種佈局方法的特點是:

1)主體內容欄是自適應的;

2)所有欄完全等高,效果跟flex佈局和偽table佈局的效果一樣;

從這兩點來看,這種絕對定位的方法還是比較好用的,不過它有一個非常大的使用限制,就是父元素的高度沒有辦法通過它的內部元素給撐起來,要用的話,必須想辦法讓父元素有高度,適合做父元素高度可知或者全屏佈局。比如以下這個代碼就是全屏佈局的一個例子(對應源碼中absolute_layout2.html):

<header>頂部</header>
<div class="layout">
    <aside class="layout__aside layout__aside--left">左側邊欄寬度固定</aside>
    <div class="layout__main">內容欄寬度自適應</div>
    <aside class="layout__aside layout__aside--right">右側邊欄寬度固定</aside>
</div>
<footer>底部</footer>
<style type="text/css">
    html,body {
        margin: 0;
        height: 100%;
    }
    footer {
        position: absolute;
        bottom: 0;
        width: 100%;
    }
    .layout {
        width: 100%;
        position: absolute;
        top: 50px;
        bottom: 50px;
    }
    .layout__aside, .layout__main {
        position: absolute;
        top: 0;
        bottom: 0;
    }
    .layout__main {
        left: 210px;
        right: 210px;
    }
    .layout__aside {
        width: 200px;
    }
    .layout__aside--left {
        left: 0;
    }
    .layout__aside--right {
        right: 0;
    }
</style>

效果:

image

做法二:側邊欄絕對定位,主體內容欄保持流式佈局(對應源碼中absolute_layout3.html)

<div class="layout">
    <aside class="layout__aside layout__aside--left">左側邊欄寬度固定</aside>
    <div class="layout__main">內容欄寬度自適應<br>高度增加一點,旁邊的高度都會自動增加</div>
    <aside class="layout__aside layout__aside--right">右側邊欄寬度固定</aside>
</div>
<style type="text/css">
    .layout {
        position: relative;
    }
    .layout__aside {
        position: absolute;
        top: 0;
        bottom: 0;
    }
    .layout__main {
        margin: 0 210px;
    }
    .layout__aside {
        width: 200px;
    }
    .layout__aside--left {
        left: 0;
    }
    .layout__aside--right {
        right: 0;
    }
</style>

效果:

image

這個方法的特點是:

1)主體內容欄是寬度自適應的;

2)所有欄也是完全等高的;

上面的代碼中,layout__main通過magin來給側邊欄留出空間,其實也可以在layout元素上添加padding來處理,作用是一樣的。這個方法相比前一個方法好一點的是,父元素的高度可以通過主體內容欄給撐起來,不過由此也帶來了一個新問題,就是內容欄高度不夠的時候,側邊欄就會出現溢出或者滾動,解決這個新問題的辦法有2個:第一,如果側邊欄的內容都是已知的,並且沒有摺疊展開這種會改變側邊欄內容高度的功能,那麼可以給layout設置一個min-height來處理;第二,如果側邊欄的內容是動態的,除了給layout加min-height之外,還得在每次改變側邊欄內容的時候,主動去調整主體內容欄的高度,如果主體內容欄的高度小於側邊欄的高度,就要更新主體內容欄的高度。不過如果你的內容欄的內容很多,側邊欄內容較少的話,就不用考慮這個新問題了。

絕對定位的做法就是這樣,第一種限制較高;第二種稍微強一些,在一些場景下,可能還得藉助JS來處理,所以綜合起來不算是一個非常好的方式。只有你的佈局需求恰好滿足它的條件時,可能才會考慮使用它,就像上文中我提出的項目一的需求,就一定要用絕對定位的佈局來做。

4. 方法四:藉助邊框,背景實現假等高

前面介紹了幾種分欄等高佈局,有table佈局,偽table佈局,絕對定位佈局,flex佈局,這四種佈局方法在實現等高佈局時,屬於完全等高的情況,就是說他們佈局出來的頁面,各欄的真實高度都是相同的,並且在任意欄的內容動態變化時,其它欄的高度都能相應地自動調整,如果佈局的時候用的是這幾個佈局方法,那麼等高的問題就不存在了。不過回看一下上文內容的話,上文提到的3種佈局方式:聖杯佈局,雙飛翼佈局,float佈局,不用JS的話,就無法做到這種完全等高的效果。這三種佈局,只能考慮藉助邊框和背景實現視覺上的等高,也就是假等高的做法。畢竟從效果上來說,如果沒有設置背景和邊框的話,即使是完全等高,視覺上也看不出來,所以假等高的做法是值得採用的。

做法一:利用背景圖片

以佈局容器寬度固定的左中右三欄佈局說明這個做法的步驟,首先製作一張高度較小,寬度跟佈局容器寬度相同的背景圖片,把這張圖片作為佈局容器的背景圖垂直平鋪。這張背景圖要求跟頁面一樣也是分欄,而且每欄的寬度和欄之間的間隔都跟頁面佈局裡面的

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • XHXJ's LIS 題意:求出給定區間[L,R] (0<L<=R<263-1 and 1<=K<=10) 中數滿足LIS(非連續嚴格遞增子序列)為K的個數? 如區間[123,321]中的124的LIS為3; <1> 總結數位DP的優化方式: 歸納高位之間的相同點,就是狀態的轉化是關鍵; 例: 1.
  • 例1:求學生的平均分 1 public static void main(String[] args) { 2 Scanner input=new Scanner(System.in); 4 int scores []=new int[5]; 5 int sum=0; 6 7 System.out.
  • MySQLdb安裝失敗了,直接使用pymysql,安裝了pymysql。 並學習了使用使用pymysql創建資料庫和表,並插入數據。 __author__ = 'Administrator' import pymysql try: conn= pymysql.connect(host='localh...
  • __author__ = 'Administrator' from tkinter import * import tkinter.messagebox class MainWindow: def buttonListener1(self,event): tkinter.messagebox.sho...
  • 1.memset #include <stdio.h> #include <string.h> int main() { //char *s="My Dream Come true";//用來初始化字元指針的字元串常量會被編譯器安排到只讀數據存儲區,是不可以修改的 char s[] ="My Dre
  • 參考老師的博客: 金角:http://www.cnblogs.com/alex3714/articles/5143440.html 銀角:http://www.cnblogs.com/wupeiqi/articles/4963027.html 一、常用函數說明: ★ lamba python lam
  • 一、什麼是裝飾模式 通過關聯機制給類增加行為,其行為的擴展由修飾對象來決定; 如JAVA IO流里的以下形式,BufferedReader為裝飾類,其關聯了一個具體對象(new FileReader(new File("test.txt"))),並對其進行裝飾,裝飾後擁有readLine行為(方法)
  • 2.15 max 2.15.1 語法: _.max(list, [iteratee], [context]) 2.15.2 說明: 返回list中的最小值。 list為集合,數組、對象、字元串或arguments iteratee作為返回最大值的依據 iteratee的參數(value, key,
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...