浮動
float
屬性最初只用於在成塊的文本內浮動圖像,但是現在它已成為在網頁上創建多列布局的最常用工具之一。本文將闡述它的有關知識。
浮動的背景知識
最初,引入 float
屬性是為了能讓 web 開發人員實現簡單的布局,包括在一列文本中浮動的圖像,文字環繞在它的左邊或右邊。你可能在報紙版面上看到過。
但 Web 開發人員很快意識到,任何東西都可以浮動,而不僅僅是圖像,所以浮動的使用范圍擴大了。之前的 fancy paragraph example 的課程展示了如何使用浮動創建一個有趣的drop-cap(首字下沉)效果。
浮動曾被用來實現整個網站頁面的布局,它使信息列得以橫向排列(默認的設定則是按照這些列在源代碼中出現的順序縱向排列)。目前出現了更新更好的頁面布局技術,所以使用浮動來進行頁面布局應被看作傳統的布局方法。
在這一章中,我們僅就浮動這一命令本身的性能展開講解。
簡單的例子
讓我們來探討如何使用浮動。我們將從一個非常簡單的例子開始,包括在圖像周圍浮動一個文本塊。你可以跟隨在你的電腦上創建新的 index.html
文件,以填充它 simple HTML template, 以下代碼插入它在適當的地方。底部的部分你可以看到一個它應該是什么樣子的例子。
首先,我們寫一些簡單的HTML——添加以下到HTML的<body>
內,刪除之前<body>
里面的東西:
<h1>Simple float example</h1> <img src="https://mdn.mozillademos.org/files/13340/butterfly.jpg" alt="A pretty butterfly with red, white, and brown coloring, sitting on a large leaf"> <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. Curabitur vehicula tellus neque, ac ornare ex malesuada et. In vitae convallis lacus. Aliquam erat volutpat. Suspendisse ac imperdiet turpis. Aenean finibus sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit quam nec lacus varius commodo et a urna. Ut id ornare felis, eget fermentum sapien.</p> <p>Nam vulputate diam nec tempor bibendum. Donec luctus augue eget malesuada ultrices. Phasellus turpis est, posuere sit amet dapibus ut, facilisis sed est. Nam id risus quis ante semper consectetur eget aliquam lorem. Vivamus tristique elit dolor, sed pretium metus suscipit vel. Mauris ultricies lectus sed lobortis finibus. Vivamus eu urna eget velit cursus viverra quis vestibulum sem. Aliquam tincidunt eget purus in interdum. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p>
現在將以下CSS應用到您的HTML (使用一個<style>
元素或一個<link>
到一個單獨的 .css
文件——你來選擇):
body { width: 90%; max-width: 900px; margin: 0 auto; } p { line-height: 2; word-spacing: 0.1rem; }
如果你現在保存並刷新,你會看到和你預期的效果差不多——圖片坐落在文本的上方,目前看起來有點丑陋。我們本可以讓圖片在它的容器內居中,但取而代之,我們將使用float來讓圖片周圍的文本浮起來。將以下規則添加到你之前的規則下面:
img { float: left; margin-right: 30px; }
現在,如果您保存和刷新,你會看到類似下面的東西:
因此,讓我們考慮一下浮動是如何工作的——浮動元素 (這個例子中的<img>
元素)會脫離正常的文檔布局流,並吸附到其父容器的左邊 (這個例子中的<body>
元素)。在正常布局中位於該浮動元素之下的內容,此時會圍繞着浮動元素,填滿其右側的空間。
注意浮動內容仍然遵循盒子模型諸如外邊距和邊界。我們設置一下圖片右側的外邊距就能阻止右側的文字緊貼着圖片。
向右浮動的內容是一樣的效果,只是反過來了——浮動元素會吸附到右邊,而其他內容將從左側環繞它。嘗試將上一個例子中的浮動值改為 right
,再把 margin-right
換成 margin-left
,看看結果是什么。
再看我們的首字下沉例子
如上所述,我們的 fancy paragraph example 從早先的課程精選了一個漂亮的首字下沉。在這個例子中,我們有一個簡單的段落:
<p>This is my very important paragraph. I am a distinguished gentleman of such renown that my paragraph needs to be styled in a manner befitting my majesty. Bow before my splendour, dear students, and go forth and learn CSS!</p>
我們的CSS看起來像這樣:
p { width: 400px; margin: 0 auto; } p::first-line { text-transform: uppercase; } p::first-letter { font-size: 3em; border: 1px solid black; background: red; float: left; padding: 2px; margin-right: 4px; }
結果如下:
這里的效果與我們在圖像的第一個例子中所做的沒有很大的不同,但是這一次,我們在信中的第一個字母后面的其余部分是浮動的,在使這封信看起來顯得又大又大膽又有趣之后。
你可以漂浮任何的東西,只要有兩個項目的空間,以配合在一起。這使我們很好地談論多列布局。
多列浮動布局
浮動通常用於創建多個列布局,並且由於其廣泛的瀏覽器支持已經有相當一段時間。盡管事實上,他們不是真的打算這個工作,並有一些奇怪的副作用必須處理,你會在后面的文章中看到。
兩列布局
讓我們先從最簡單的例子——兩列布局。您可以通過創建一個新的 index.html
文件在您的計算機上,用simple HTML template填充它, 並在適當的地方插入下面的代碼。在本節的底部,您可以看到一個活的例子,最終代碼應該看起來像。
首先,我們需要一些內容放入我們的列。使用以下內容替換body中的任何內容:
<h1>2 column layout example</h1> <div> <h2>First column</h2> <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. Curabitur vehicula tellus neque, ac ornare ex malesuada et. In vitae convallis lacus. Aliquam erat volutpat. Suspendisse ac imperdiet turpis. Aenean finibus sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit quam nec lacus varius commodo et a urna. Ut id ornare felis, eget fermentum sapien.</p> </div> <div> <h2>Second column</h2> <p>Nam vulputate diam nec tempor bibendum. Donec luctus augue eget malesuada ultrices. Phasellus turpis est, posuere sit amet dapibus ut, facilisis sed est. Nam id risus quis ante semper consectetur eget aliquam lorem. Vivamus tristique elit dolor, sed pretium metus suscipit vel. Mauris ultricies lectus sed lobortis finibus. Vivamus eu urna eget velit cursus viverra quis vestibulum sem. Aliquam tincidunt eget purus in interdum. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p> </div>
每個列都需要一個外部元素來包含其內容,並讓我們一次操作它的所有內容。在這個例子中,我們選擇了<div>
,但你可以選擇更多語義合適的東西<article>
、<section>
、和<aside>
,諸如此類。
現在為CSS將以下內容應用到HTML以提供一些基本設置:
body { width: 90%; max-width: 900px; margin: 0 auto; }
在寬度達到900px之前,整個視圖的寬度將達到90%,在超過900px后,它將保持在這個寬度,並在視口中居中。默認情況下,子元素(這個<h1> (en-US) 和兩個 <div>
)將跨越整個body寬度的100%。如果我們希望將兩個<div>
放在一起,那么我們需要將它們的寬度設置為父元素的寬度的100%,或者更小,這樣它們就可以彼此匹配。將下面的內容添加到CSS的底部:
div:nth-of-type(1) { width: 48%; } div:nth-of-type(2) { width: 48%; }
在這里我們設置了他們的父親的寬度的48% —— 這總計96%,留下我們4%自由作為兩列之間的溝槽,給內容一些空間呼吸。現在我們只需要浮動列,像這樣:
div:nth-of-type(1) { width: 48%; float: left; } div:nth-of-type(2) { width: 48%; float: right; }
把這些結合在一起應該跟我們結果一樣:
你會注意到,我們所有列使用寬度百分比——這是一個很好的策略,因為它創建一個流式布局(liquid layout),一種調整為不同的屏幕尺寸,並在較小的屏幕尺寸下保持相同的列寬度比例。請嘗試調整瀏覽器窗口的寬度,以便自己查看。這是響應式網頁設計的一個有價值的工具,我們將在以后的模塊中討論。
注意:你可以看到這個例子運行在 0_two-column-layout.html (參見 the source code).
需要注意的一件事是,當它們變得非常窄時,列就會變得很糟糕。切換回窄屏幕的單列布局通常是有意義的(如手機),使用媒體查詢可以實現這一功能。再一次,你們將在未來的響應式網頁設計模塊中學習這些知識。
另一種選擇是將寬度設置為一個固定的單位如rem或像素——你可以看到一個例子two-column-layout-fixed.html
(see source code),或者通過刪除max-width
聲明來轉換您自己的示例,並改變各個寬度為 900px
, 430px
和 430px
。這就是固定寬度布局(fixed-width layout)——如果您現在調整瀏覽器大小,您將看到布局不再調整以適應視圖寬度,在尺寸更小時您將需要滾動來查看它的全部。
現在我們將轉去使用流體布局。
三列布局
你已經有了一個兩列布局工作,添加一個第三列(或更多)並不是太難。你只需要添加另一個列在同一個父元素。開始通過添加以下 <div>
就在另外兩個后面(或使用 0_two-column-layout.html
作為開始):
<div> <h2>Third column</h2> <p>Nam consequat scelerisque mattis. Duis pulvinar dapibus magna, eget congue purus mollis sit amet. Sed euismod lacus sit amet ex tempus, a semper felis ultrices. Maecenas a efficitur metus. Nullam tempus pharetra pharetra. Morbi in leo mauris. Nullam gravida ligula eros, lacinia sagittis lorem fermentum ut. Praesent dapibus eros vel mi pretium, nec convallis nibh blandit. Sed scelerisque justo ac ligula mollis laoreet. In mattis, risus et porta scelerisque, augue neque hendrerit orci, sit amet imperdiet risus neque vitae lectus. In tempus lectus a quam posuere vestibulum. Duis quis finibus mi. Nullam commodo mi in enim maximus fermentum. Mauris finibus at lorem vel sollicitudin.</p> </div>
現在更新你的CSS如下:
body { width: 90%; max-width: 900px; margin: 0 auto; } div:nth-of-type(1) { width: 36%; float: left; } div:nth-of-type(2) { width: 30%; float: left; margin-left: 4%; } div:nth-of-type(3) { width: 26%; float: right; }
這將給我們以下結果:
這個例子我們已經很熟悉了;唯一真正的區別是我們有了這個額外的列——為了讓它放到合適的位置我們已經把它放在左邊了;我們還給了它一個4%的 margin-left
,來在第一和第二列之間拉開一段距離。我們設置了列的寬度以便它們都能匹配——36% + 30% + 4% + 26% = 96%,在第二和第三列之間有4%的空間。(這個空間總是出現在向左浮動的第二列和向右浮動的第三列之間。)
這里需要注意的一點是,您必須仔細考慮將列放在什么位置,以及如何浮動它們,以獲得所需的結果。你的內容應該是有意義的,當你閱讀它的源代碼和它的視覺布局的時候;但是,使用浮動可以使可視化布局與源順序不同。來說明我們的意思,嘗試改變第二列的 float
值為 right
(或者看一看three-column-layout-wrong-order.html (源碼))你會看到現在的視覺順序是這樣的:
div1 div3 div2
這是因為第二個<div>源代碼順序上比第三個<div>等級要高 (DOM上第二個<div>先出現並聲明了float: right;
) ,所以在浮動順序上也會比第三個<div>等級要高。又因為兩者同時向右浮動,第二個<div>就會更加地靠右。
然而視覺受損的人使用屏幕閱讀器來聽你的內容,仍然會聽到這個順序的內容:
div1 div2 div3
內容布局和樣式對它們沒有影響。無論用戶如何消費,內容都應該是合理的。
注意:完成了這一點您可以找到的例子1_three-column-layout.html (see source code).
清除浮動
現在你已經知道了關於 float 屬性的一些有趣事實,不過你很快就能夠碰到一個問題——所有在浮動下面的自身不浮動的內容都將圍繞浮動元素進行包裝,如果沒有處理這些元素,就會變得很糟糕。為了說明我們的意思,嘗試在第三個<div>
元素下面添加以下HTML(並檢出2_float-disaster.html
(source code)):
<footer> <p>©2016 your imagination. This isn't really copyright, this is a mockery of the very concept. Use as you wish.</p> </footer>
你會看到頁腳在最長的列旁邊環繞着,這看起來很糟糕——我們希望頁腳保持在底部,在所有的列下面。幸運的是,有一種簡單的方法可以解決這個問題—— clear
屬性。當你把這個應用到一個元素上時,它主要意味着"此處停止浮動"——這個元素和源碼中后面的元素將不浮動,除非您稍后將一個新的float
聲明應用到此后的另一個元素。
所以,要解決我們的問題,添加以下規則到您的CSS:
footer {
clear: both;
}
這將會給你一個頁腳,它會在你的列下面,就像它應該做的那樣:
clear
可以取三個值:
left
:停止任何活動的左浮動right
:停止任何活動的右浮動both
:停止任何活動的左右浮動
你通常只想設定一個 clear: both
在你想讓浮動停止的元素上。在某些情況下,你會想要只取消left
或 right
引用。
注:你可以在這個階段找到例子 2a_fixed-by-clear.html
(see source code).
浮動問題
以上部分提供了使用浮動創建簡單布局的基礎,但是還有一些問題需要解決。 讓我們談談這些問題。
整個寬度可能難以計算
到目前為止,我們的例子是沒有應用樣式的浮動框——這很容易。當你開始給這些框加上樣式時,比如添加背景、外邊距、內邊距等等,問題就來了。為了演示這個問題,可以將下面的 CSS 加入到你的代碼里 (你也可以看這個例子 3_broken-layout.html
(source code)):
div, footer { padding: 1%; border: 2px solid black; background-color: red; }
此時,您將看到您的布局已損壞 —— 由於內邊距和邊界引入的額外寬度,一行容納不下三列了,因此第三列下降到另外兩列之下。
有兩個方法可以解決問題,最好的方法是給你的html加上下面的css。
* { box-sizing: border-box; }
box-sizing
通過更改盒模型來拯救我們,盒子的寬度取值為 content + padding + border,而不僅是之前的content——所以當增加內邊距或邊界的寬度時,不會使盒子更寬——而是會使內容調整得更窄。
我們有另一個問題——頁腳正壓在最長列上, 在這一點並不理想——我們來試着清除頁腳浮動的同時給出一些頂部外邊距( margin-top
)來解決這個問題:
footer {
clear: both;
margin-top: 4%;
}
然而,這不起作用 ——浮動的元素存在於正常的文檔布局流之外,在某些方面的行為相當奇怪:
- 首先,他們在父元素中所占的面積的有效高度為0 ——嘗試在瀏覽器中加載 1_three-column-layout.html 並用開發工具查看
<body>
的高度,你將會看到我們的意思是什么——所報告的正文高度只有 <h1> (en-US) 的高度 。這個可以通過很多方式解決,但是我們所依賴的是在父容器的底部清除浮動,如我們在我們的當前示例所做的那樣。 如果檢查當前示例中正文的高度,您應該看它的高度是行為本身。 - 其次,非浮動元素的外邊距不能用於它們和浮動元素之間來創建空間——這是我們在這里眼前的問題,我們將在下面實施修復。
- 還有一些關於浮動的奇怪的事情——Chris Coyier優秀的關於Floats文章概述了其他一些以及修復這些。
所以,讓我們解決這個! 首先,在HTML的代碼里添加新的<div>
元素,位於在<footer>標簽的上方:
<div class="clearfix"></div>
如果您沒有一個可用的元素來清除您的浮動(比如我們的頁腳),在您想要清除的浮動之后添加一個看不見的“clearfix div”是非常有用的,但是在這里頁腳也要用到。接下來我們要做的是,移除頁腳樣式規則中的 clear: both;
聲明,取而代之將其放在clearfix div中:
.clearfix { clear: both; }
我們的頁腳現在有一個很好的頂部外邊距,但也有另一個問題——clearfix div 背景、內邊距和邊界與我們的列和頁腳相同!為了解決這個問題,讓我們先給每個列塊一個類( class
)column
:
<div class="column"> ... </div>
現在讓我們改變應用盒子樣式的規則到這些塊和頁腳,這樣只有列塊被樣式化:
.column, footer { padding: 1%; border: 2px solid black; background-color: red; }
至此,修復問題大概就那樣。
注: 查看在這個階段最后一個解決的例子4_fixed-layout-border-box.html (source code)。
這里要注意的另一小點是,box-sizing
出現可以追溯到Internet Explorer 8——如果您明確需要支持較老的瀏覽器,您可能需要手動調整列的寬度,以允許內邊距和邊界寬度。這不是一種非常精確的技術,特別是考慮到你不能用百分比來確定邊界——你只需要在盡可能充滿父寬度的同時留出足夠的空間。你可以看到這樣的實戰修復fixed-layout-adjusted-percentages.html
(見源代碼)。
浮動項目的背景高度
到目前為止,我們建好的示例是有效的,但另一個問題是列高度是不同的—— 如果列都是相同的高度,它看起來會更好。
我們可以通過給所有的列固定height
來解決這個問題(see 5_fixed-height-columns.html
(源代碼):
.column { height: 550px; }
然而在許多情況下這並不理想——它使設計呆板。如果你能保證列中總是有相同數量的內容,這是可以的,但這並不總是如此——在很多類型的網站上,內容也會定期更改。
這正是像flexbox這樣的新布局技術所解決的問題。Flexbox可以自動地延長列,這樣他們就會像最長的一列一樣。
你也可以考慮:
清除浮動會變復雜
我們在文章中建立的簡單例子很容易理解,但是當布局變得更加復雜清理(clearing)也會變得更加復雜。你需要確保所有的浮動都能盡快清除,以避免它們給下方的內容制造麻煩。如果您沒有一個方便的容器來進行清理,那么在必要的時候使用clearfix塊。