margin系列之佈局篇
原文地址:margin系列之佈局篇 by @doyoe
前端工程師對CSS的基本訴求
佈局能力或許是Web前端工程師對CSS的最基本的訴求,當開始進入到這個崗位,就避免不了要和CSS打交道,而和CSS交往,佈局當然是不可或缺的。
很遺憾的是,CSS2.1之前都沒有出現真正意義上的佈局屬性,直至現如今的CSS3,才開始出現了一些,如:flex, grid 等,不過其相容性及國內瀏覽器的使用情況,真令人捉急。
不過,有需求就會有變通,對於達成佈局目的,已衍生出各式各樣的方法,如:float, inline-block, table, absolute 等等。
margin的佈局之道
其實,這個話題有點脫離 margin
的能力範圍,因為單純的 margin
並無法完成複雜佈局,它更多做的是輔助,但卻又難以替代。
經典左右結構
兩欄結構應該是最常見和經典的網頁呈現之一吧?如下 圖一
:
(圖一)
相信對於這樣一個網頁呈現,你不會陌生。那麼你有多少種方案可以達成該佈局?我想,4至5種應該是保守估計吧?
這次,我們只看 margin
是如何做的。
absolute + margin 方式
HTML
<header id="hd">頭部</header>
<div id="bd">
<aside id="aside">側邊欄固定寬度</aside>
<div id="main">主內容欄自適應寬度</div>
</div>
<footer id="ft">底部</footer>
CSS
#aside{
position:absolute;
top:0;
left:0;
width:200px;
}
#main{
margin-left:210px;
}
如上關鍵程式碼,我們即可實現 圖一
佈局,該佈局有一個特點就是,#main
可以自適應可用空間。
假定 HTML
是給定的,我們來解讀一下 CSS
程式碼:
我們知道塊級元素的特性之一是換新行,也就是說,如果想讓 #main
和 #aside
在同行顯示,我們要麼改變其顯示屬性為 inline-level
(即之前說的inline-block佈局方式),要麼改變其流方式(absolute, float, flex and etc...)。
如上述程式碼,我們使用了 absolute
,即讓 '#aside' 脫離常規流,通過絕對定位到想要的位置。
主內容欄自適應寬度
同時你會發現,我們並有改變 #main
的顯示屬性或者流方式,也就是說其仍然具備塊級元素的特性,所以它會自動適應剩餘寬度,即我們常說的自適應寬度。
我們並不希望 #main
區域會包含 #aside
在內,於是利用 margin
給 '#aside' 預留出足夠其顯示的空間,即可達成我們所要的佈局。
可能你會問為什麼是 margin-left:210px
而不是 200px
,實際確實應該是 200px
,多出來的 10px
只是為了建立一個列間隙,與佈局實現無關。
來看看具體的實現 DEMO1
: margin+absolute佈局:左欄固定主內容自適應
就這樣,是不是很簡單?其實它還有亮點,那就是:
任意調整列順序
在不修改 HTML
的情況下,只需簡單的修改 CSS
,我們即可讓左右兩欄的順序調換,來看程式碼:
CSS
#aside{
position:absolute;
top:0;
right:0;
width:200px;
}
#main{
margin-right:210px;
}
其實現原理沒變,同樣看看 DEMO2
: margin+absolute佈局:右欄固定主內容自適應
主內容優先顯示
可以更Cool一點,你覺得呢?很多時候,你也許會考慮到,不論在何種情況下,總想保證主要的內容優先於次要的內容呈現給使用者,那麼,怎麼做?
很簡單,只需要將主要內容的HTML排在次要內容的HTML之前即可,因為它是順序載入渲染的。我們可以這樣:
HTML
<header id="hd">頭部</header>
<div id="bd">
<div id="main">主內容欄自適應寬度</div>
<aside id="aside">側邊欄固定寬度</aside>
</div>
<footer id="ft">底部</footer>
是的,我們只需要將 #main
的HTML挪到 #aside
的HTML前面,令人興奮的是,改變HTML之後,CSS不需要做任何改變。我們來看 DEMO3
: margin+absolute佈局:左欄固定主內容自適應,主內容有限顯示
當然,調正列順序的 DEMO4
: margin+absolute佈局:右欄固定主內容自適應,主內容有限顯示 也同樣簡單,我們只需要寫HTML時注意一下即可。
致命缺陷
列舉了 absolute+margin
佈局的很多優點,但只說一個問題,就足以讓你在是否選用這種方式時深思熟慮,是什麼呢?
我們知道 absolute
是定位流,脫離正常排版,也就是說絕對定位元素不影響其上下文的排版方式,你意識到我想說什麼了麼?
OK,用程式碼來演示:
HTML
<header id="hd">頭部</header>
<div id="bd">
<div id="main">主內容欄自適應寬度</div>
<aside id="aside">側邊欄固定寬度,我的內容可能比主內容多,高度比主內容欄高</aside>
</div>
<footer id="ft">底部</footer>
看完程式碼,估計你猜到了。是的,#aside
無法撐開父元素的高度,它將會溢位父元素區域,結果如下圖:
(圖二)
來看看這缺陷所導致的情況 DEMO5
: margin+absolute佈局的致命缺陷
此時假設你設定父元素 overflow:hidden
那麼溢位部分將會被裁減,同樣不符合佈局意圖,無法可破。所以在內容量不可控的場景,不推薦使用這種方式。
float + margin 方式
和 absolute + margin
方式一樣,float + margin
方式一樣是經典的利用來佈局的方案,並且被更廣泛使用。我們仍然以 圖一
為例,來看程式碼:
HTML
<header id="hd">頭部</header>
<div id="bd">
<aside id="aside">側邊欄固定寬度</aside>
<div id="main">主內容欄自適應寬度</div>
</div>
<footer id="ft">底部</footer>
CSS
#aside{
float:left;
width:200px;
}
#main{
margin-left:210px;
}
如上述程式碼,我們使用了 float
,即從圖文環繞形態演變而來。當 #aside
定義了 float
,那麼緊隨其後的元素將會環繞在其周圍。不過環繞並不是我們想要的結果,我們想要的是 '#main' 也自成封閉矩形,所以利用 margin
留出足夠 #aside
顯示的空間,中斷環繞即可。
當然,此時 #main
也是自適應寬度的,來看具體例項 DEMO6
: margin+float佈局:左欄固定主內容自適應
它是否也具備可任意調整列順序的特點?何不一試?
CSS
#aside{
float:right;
width:200px;
}
#main{
margin-right:210px;
}
看過 DEMO7
: margin+float佈局:右欄固定主內容自適應,你會發現,是的,這種方式也支援任意調整列順序,很棒。
從這種趨勢看來,貌似 float + margin
的方式會成為黑馬,不過遺憾的告訴你,這種方式無法支援主內容優先顯示。但我們有更Cool的解決方案。
float + 負margin 方式
接下來我要說的大家可能都猜到了,對,經典的聖盃佈局。至於聖盃的名字由來,大家可以自行Google,這裡不做贅述。
恩,HTML當然是使用主內容優先顯示的那種:
HTML
<header id="hd">頭部</header>
<div id="bd">
<div id="main">主內容欄自適應寬度</div>
<aside id="aside">側邊欄固定寬度</aside>
</div>
<footer id="ft">底部</footer>
CSS
#bd{
padding-left:210px;
}
#aside{
float:left;
position:relative;
left:-210px;
width:200px;
margin-left:-100%;
}
#main{
float:left;
width:100%;
}
如上程式碼,既是聖盃佈局的核心Code,如果你看懂了,你會發現,這其實很簡單,不是麼?
簡單解釋一下上面的CSS Code,首先我們是在做一個左側固定寬度,右側自適應寬度的佈局。我們說過要讓塊級元素在同行顯示的條件:改變顯示方式,改變流方式,這裡我們選擇了使用 float
來將 #main
和 #aside
變成浮動流。
OK,這時我們具備 #main
和 #aside
能在同行顯示的前置條件。我們知道,浮動元素其寬度如果沒有顯式定義,則由其內容決定。正好,#aside
是定寬的,所以顯示給它定義 width:200px
,但此時 #main
該怎麼辦?不設定 width
不對,因為寬度將被內容左右,設定 width:100%
也不對,因為這樣的話,就沒有 #aside
的立足之地了,正確的應該是 width: calc(100% - 200px)
,不是麼?可惜,這是新特性,只好作罷。
變通?是的,有的時候稍微換個思路,你會覺得豁然開朗。
#main
不是要自適應嗎?那就給它個 100%
,怎麼做?我們在包含塊 #bd
中就將 #aside
的寬度刨除,寬度全部都給 #main
。恩,我們只需要這樣 #bd{padding-left:210px;}
(10px仍然是用來做間隙的),這時 #main
就可以設定 width:100%
了,由於 #bd
設定了 padding
,所以已在左邊預留出了一塊寬 210px
的區域。此時的問題在於如果將 #aside
挪到這個地方,你想對了,我們是在聊 負margin
佈局,自然需要利用上。
#aside{margin-left:-100%;}
這樣可以了嗎?很明顯,這樣還不行,此時 #aside
和 #main
的起始位置將會重合,因為 #aside
的 margin-left
計算值是相對包含塊來計算的,而此時包含塊的寬度等於 #main
的寬度。
如何讓 #aside
再向左偏移 210px
?顯然 margin
是不行了,因為我們已經用掉它了。如果你看過之前的文章的話,你可能還記得,有一篇文章講 margin系列之與相對偏移的異同。恩,是的,這時我們可以藉助相對偏移。
向左偏移 210px
是件很簡單的事:#aside{position:relative;left:-210px;}
。
至此,你的佈局OK了,這就是聖盃的實現方式。來看已實現好的示例 DEMO8
: 聖盃:左欄固定主內容自適應
當然,聖盃佈局必須可以任意調整列順序,要不,怎麼能說是更Cool些的方案呢?
CSS
#bd{
padding-right:210px;
}
#aside{
float:left;
position:relative;
right:-210px;
width:200px;
margin-left:-200px;
}
#main{
float:left;
width:100%;
}
這個就直接看示例好了,不再一一解釋程式碼 DEMO9
: 聖盃:右欄固定主內容自適應
所以聖盃佈局具備前兩種方式共同的優點,同時沒有他們的不足,但聖盃本身也有一些問題,在IE6/7下報廢,不過不用慌,因為它可被修復。
你想到方法了嗎?
margin系列文章:
相關文章
- margin系列之內秀篇
- margin系列之內秀篇(二)
- CSS系列之常用佈局CSS
- css flex佈局中妙用margin: autoCSSFlex
- Flutter系列之Flex佈局詳解FlutterFlex
- Flutter實戰之基本佈局篇Flutter
- margin系列之bug巡演
- margin為負值對佈局的影響
- css佈局系列1——盒模型佈局CSS模型
- margin系列之bug巡演(二)
- margin系列之bug巡演(三)
- margin系列之keyword auto
- flutter系列之:在flutter中使用流式佈局Flutter
- 視覺化拖拽 UI 佈局之拖拽篇視覺化UI
- css經典佈局系列一——垂直居中佈局CSS
- css經典佈局系列二——等分等高佈局CSS
- Flutter佈局篇(1)–水平和垂直佈局詳解Flutter
- Flutter佈局篇(1)--水平和垂直佈局詳解Flutter
- 保安日記:前端學習第十三篇之移動端佈局rem佈局前端REM
- 三欄佈局之自適應佈局
- 移動佈局基礎之 流式佈局
- CSS經典佈局之Sticky footer佈局CSS
- margin系列之百分比
- html+css 佈局篇HTMLCSS
- CSS 三欄佈局之聖盃佈局和雙飛翼佈局CSS
- css經典佈局系列三——三列布局(聖盃佈局、雙飛翼佈局)CSS
- 面試之CSS篇 - 實現三欄佈局的延伸面試CSS
- CSS:三欄佈局之雙飛翼佈局CSS
- CSS之居中佈局CSS
- ionic之基本佈局
- web前端佈局篇(切圖)Web前端
- Flex 佈局教程:例項篇Flex
- Flex 佈局教程:語法篇Flex
- 3D拓撲自動佈局之Web Workers篇3DWeb
- 三星手機佈局異常(margin有效)的問題
- margin系列之與相對偏移的異同
- PCB之AD快速佈局
- 前端css佈局之BFC前端CSS