[譯]HTML&CSS Lesson5: 定位

amhuang發表於2019-03-01

CSS最大的用處之一就是可以將內容和元素定位到任何我們想要的位置,使我們的設計具有結構,使內容更加易懂。

CSS有好幾種不同的定位屬性,每種都有自己的使用場景。在這節課中我們會通過不同的案例——可複用的佈局和針對單元素的佈局——來介紹每種方法。

浮動

定位的其中一種方法就是使用float屬性。float屬性非常好用,可以用在很多地方。

本質來說,float屬性是使元素脫離正常的流式佈局,並將它放置在父元素的左側或右側。然後頁面中所有的元素都會環繞浮動元素佈局。例如我們將段落間的一張圖片設定為浮動,那麼這些段落都會圍繞圖片換行。

當我們將多個元素同時設定為浮動元素,那麼這些元素將呈現相鄰或相對佈局,如多列布局。

float有好幾個值,最常用的值是leftright。使元素浮動到父級元素的左側或右側。

img {
  float: left;
}複製程式碼

浮動練習

我們先建立一個通用頁面,含有頁頭,頁尾,中間有兩列。最理想的情況就是在<body>元素內建立第二節課"瞭解HTML"中提到的<header><section><aside><footer>元素。

<header>...</header>
<section>...</section>
<aside>...</aside>
<footer>...</footer>複製程式碼

img
img

<section><aside>元素都是塊狀元素,它們預設上下佈局。但我們實際上想要它們並排顯示。所以在此,我們就可以將<section>元素設為左浮動,將<aside>元素設為右浮動,使它們呈現彼此相對的兩列。
CSS程式碼如下:

section {
  float: left;
}
aside {
  float: right;
}複製程式碼

在此提一下,元素設為浮動後,會浮動到父級元素的邊緣。如果沒有父級元素,那麼它會浮動到頁面的邊緣。

當我們設定一個元素為浮動,我們就將它從HTML文件的正常流式佈局中取出,這就導致元素的預設寬度取決於其內容的寬度。有時我們用可複用的佈局建立多列的時候並不希望如此,那就可以為列設定一個固定寬度。另外,為了防止浮動元素緊靠在一起,使內容彼此緊貼,可以使用margin屬性來建立元素間的空隙。
如下所示:

section {
  float: left;
  margin: 0 1.5%;
  width: 63%;
}
aside {
  float: right;
  margin: 0 1.5%;
  width: 30%;
}複製程式碼

img
img


浮動會改變元素display的狀態
有一個重要的點需要記住:將元素設為浮動就是將它從正常的流式佈局中脫離,而這會改變元素預設的display值。float屬性依賴於display屬性為block的元素。如果一個元素的預設display值不是block,那麼它會將預設值改成block

例如,span是一個內聯元素,它預設的display值為inline,widthheight值是不生效的。然而,如果我們將這個內聯元素設定為浮動,那麼它的預設display值會變成block,這時候widthheight值就生效了。

當我們設定元素為浮動時,都需要注意display值的變化。


若只有兩列,我們可以將其中一個元素設定為左浮動,另一個元素設定為右浮動,但若是多列的時候就需要換一種方法。例如,我們希望在<header><footer>元素之間新增一行三列的結構,可以先刪掉之前寫的<aside>元素並使用三個<section>元素,如下所示:

<header>...</header>
<section>...</section>
<section>...</section>
<section>...</section>
<footer>...</footer>複製程式碼

要將三個<section>元素並排顯示,我們不再用之前的左浮動加右浮動的模式,而是將三個元素都設定為左浮動。同時也要為元素設定寬度使其排列更合理。

section {
  float: left;
  margin: 0 1.5%;
  width: 30%;
}複製程式碼

現在呈現在我們眼前的就是三列寬度和外邊距一致,都向左浮動的元素。

img
img

清除浮動

float元素最初的設定是為了在內容中插入圖片,使內容自然地環繞圖片顯示。雖然它在圖片中使用非常完美,但是float屬性並不是為了定位和佈局設計的,所以在這方面存在一些缺陷。

其中一個缺陷就是浮動元素的下一個兄弟元素和父元素的樣式可能會渲染異常。當元素浮動時它脫離了正常佈局,導致圍繞在浮動元素周圍的元素的樣式都受到了影響。

最常見的就是marginpadding屬性值渲染異常,因為它們shi與浮動元素融為一體。當然,也有一些其它的樣式也受到了影響。

另一個缺陷是有時我們不想內容圍繞環繞浮動元素顯示。浮動元素會從檔案流中脫離,其他元素會完全佔有它周圍的空間,但很多時候我們並不希望這樣。

在上述兩個元素並排顯示的例子中, 我們將<section>元素和<aside>元素設為浮動。在設定元素的width屬性之前,我們可以看到<footer>元素環繞兩個浮動元素顯示,佔用所有可用空間。如此,<footer>元素就顯示在兩個浮動元素之間的凹槽中。如下所示:

img
img

為了避免這種情況,我們就需要將浮動元素包裹起來或者清除浮動,使它們回到正常檔案流中。接下來,我們先著眼於如何清除浮動,再來介紹怎麼包裹浮動元素。

清除浮動

清除浮動需要用到clear屬性,它最常用的屬性值是:leftrightboth

div {
  clear: left;
}複製程式碼

屬性值left清除左浮動,right清除右浮動。both清除同時左浮動和右浮動,這也是我們最推薦使用的屬性值。

回到上例中,我們為<footer>元素新增clear:both屬性就可以清除浮動了。清除浮動可以使頁面迴歸正常檔案流,所以非常重要。

footer {
  clear: both;
}複製程式碼

img
img

包裹浮動元素

除了清除浮動,還可以包裹浮動元素。這兩種方式頁面呈現的效果是差不多的,但包裹元素的方式還有助於確保樣式都渲染正常。

包裹元素就是將浮動元素置於父元素中,父元素作為容器會置於正常的檔案流中。我們為父元素新增一個class屬性group,併為其設定CSS:

.group:before,
.group:after {
  content: "";
  display: table;
}
.group:after {
  clear: both;
}
.group {
  clear: both;
  zoom: 1;
}複製程式碼

上述寫了很多程式碼,但實際上就是為class值為group元素中的浮動元素清除浮動,使其迴歸正常檔案流。

再具體點,程式碼中使用了在第四節中有提到過的:before:after兩個偽類,它們在class為group的元素前後分別新增了一個動態元素。這些元素不包含任何內容,並以與塊狀元素block很相似的表格元素table的形式呈現。動態生成的元素:after清除了class為group的元素內的元素浮動。在.group中設定的清除浮動則清除了排版在它之上的兄弟元素的浮動。老版本的瀏覽器也可以很好的相容。

clear:both單獨宣告會很合適。

回到示例,我們可以將<section><aside>元素放置在一個父元素內,如下所示:

HTML

<header>...</header>
<div class="group">
  <section>...</section>
  <aside>...</aside>
</div>
<footer>...</footer>複製程式碼

CSS

.group:before,
.group:after {
  content: "";
  display: table;
}
.group:after {
  clear: both;
}
.group {
  clear: both;
  zoom: 1;
}
section {
  float: left;
  margin: 0 1.5%;
  width: 63%;
}
aside {
  float: right;
  margin: 0 1.5%;
  width: 30%;
}複製程式碼

img
img

這種包裹元素清除浮動的方式被稱為clearfix,我們可以很容易在其它網站中找到定義它的class名clearfixcf。我們示例中使用了group,它代表一組元素,更好地表達了內容的意義。

設定浮動元素時我們要時刻注意它是否影響了頁面的佈局,並確認是否已根據需要清除浮動。不清除浮動會導致很多頭疼的問題,尤其當頁面多行多列排版的時候。

練習

接下來,我們開啟“樣式討論會”網站來嘗試將一部分內容浮動。

  • 在設定元素浮動之前,我們先在main.css中的grid樣式下新增清除浮動的樣式group,如下所示:
/*
  ========================================
  Clearfix
  ========================================
*/
.group:before,
.group:after {
  content: "";
  display: table;
}
.group:after {
  clear: both;
}
.group {
  clear: both;
  zoom: 1;
}複製程式碼
  • 現在我們要將<header>元素內的<h1>設定為左浮動,其他元素環繞這個元素顯示。
    先為<h1>新增一個class屬性,值為logo,並在CSS中將其設定為左浮動:

HTML

<h1 class="logo">
  <a href="index.html">Styles Conference</a>
</h1>複製程式碼

CSS

/*
  ========================================
  Primary header
  ========================================
*/

.logo {
  float: left;
}複製程式碼
  • 這步完成之後,我們為logo新增更多細節。先在單詞"Style"和"Conference"之間新增一個<br/>元素,使兩個單詞分兩行顯示。
    在CSS中我們為logo新增上邊框和縱向的padding

HTML

<h1 class="logo">
  <a href="index.html">Styles <br> Conference</a>
</h1>複製程式碼

CSS

.logo {
  border-top: 4px solid #648880;
  padding: 40px 0 22px 0;
  float: left;
}複製程式碼
  • 由於我們將<h1>設定為浮動,那麼就需要在最靠近它的父級元素<header>上新增class屬性值group來清除浮動:
<header class="container group">
  ...
</header>複製程式碼
  • <header>元素上的操作已經完成,接著我們來處理<footer>元素。與<header>元素設定相似,我們將包含版權資訊的<small>設定為左浮動,其他元素圍繞這個元素顯示。
    不過與<header>不同的是,我們不直接在浮動元素上新增class屬性設定浮動。我們先為其父元素新增一個class屬性值,並且使用這唯一的選擇器選中元素設定浮動。首先在<footer>上新增class屬性值primary-footer。由於我們已事先知道了要將<footer>元素中的某個元素設為浮動,所以在<footer>中新增class屬性值group
<footer class="primary-footer container group">
  ...
</footer>複製程式碼
  • 現在我們已在<footer>上新增了class屬性值primary-footer。我們可以以其為預選擇器選中<small>元素並新增左浮動。如下所示:
/*
  ========================================
  Primary footer
  ========================================
*/

.primary-footer small {
  float: left;
}複製程式碼
  • 上述程式碼中我們選中的是class屬性值為primary-footer的元素內的<small>元素,例子中對應的就是<footer>元素。
  • 最後一步,我們為<footer>元素設定縱向padding,使<footer>的內容與其它內容分離。我們可以直接在primary-footer上新增樣式:
.primary-footer {
  padding-bottom: 44px;
  padding-top: 44px;
}複製程式碼
  • 完成了<header><footer>的設定之後,我們要將這些修改應用到每個頁面中。

img
img

Inline-Block

除了浮動,我們也可以通過display:inline-block來佈局定位。它主要是幫助我們做頁面佈局或同行元素間的的佈局。

在此回顧一下,display:inline-block使元素同行顯示外,接受所有盒子模型的屬性,包括heightwidthpaddingbordermargininline-block可以充分使用盒子模型的所有屬性,並且不需要清除浮動。

Inline-Block練習

我們來看上述三列並排顯示的例子,HTML結構如下:

<header>...</header>
<section>...</section>
<section>...</section>
<section>...</section>
<footer>...</footer>複製程式碼

之前我們為<section>元素設定了浮動,現在我們以display:inline-block來代替,並保留之前設定的marginwidth。 CSS呈現如下:

section {
  display: inline-block;
  margin: 0 1.5%;
  width: 30%;
}複製程式碼

此時,程式碼並沒有很好的解決問題,最後一個<section>元素掉到了下一行。行內塊元素是行內一個接著一個佈局,但它們之間有一個空格。當我們將空格佔用的空間和所有元素的widthmargin相加,那麼佔用寬度會非常大,會將最後一個<section>擠到下一行。為了讓所有<section>顯示在同一行,我們就需要把這些空格移除。

img
img

移除inline-block元素之間的空格

有好幾種方法可以移除掉空格,但有些方法會相對複雜一些。我們將介紹兩種最簡單的方法,都是應用在HTML中的。

第一中解決方案是將<section>的開始標籤和前一個<section>的結束標籤寫在同一行。一行內的程式碼以開始標籤為結尾,如下所示:

<header>...</header>
<section>
  ...
</section><section>
  ...
</section><section>
  ...
</section>
<footer>...</footer>複製程式碼

用這種方法要確保HTML在書寫時元素之間時沒有空格,那麼最終渲染時頁面也不會呈現出空格。

img
img

另一種方法是在元素之間新增註釋。結束標籤和開始標籤之間以註釋連線,註釋必須緊跟元素。這麼寫可以允許HTML元素在書寫時換行,程式碼如下:

<header>...</header>
<section>
  ...
</section><!--
--><section>
  ...
</section><!--
--><section>
  ...
 </section>
 <footer>...</footer>複製程式碼

這兩種方法沒有一種是非常完美的,但它們都很好用。我(作者)更傾向於新增註釋的方案,因為它更利於排版,但你完全可以根據你的喜好來選擇。

建立可複用的佈局

在構建網站時,編寫可複用的模組是非常有益的,而可複用的佈局就是可複用程式碼中非常重要的一部分。佈局可以使用float或者inline-block元素的方法實現,但那一種方法更好呢?

這是值得商榷。我(作者)的做法是使用inline-block元素實現頁面的網格或佈局,而當我想讓某部分內容環繞某個元素顯示時會使用floatfloat本來是用於處理圖片的)。而且我也發現inline-block元素的佈局方式更簡單,更易處理。

和前面說的一樣,你可以根據自己的需要選擇最合適的方案,如果你對其中一種方法更滿意,那你就可以選擇它。

目前,新的CSS規範提到了flexgrid-開頭的屬性——它們有助於實現頁面的最佳佈局。要時常關注留意這些新的方法。

練習

對可複用的佈局有所瞭解之後,我們將其實施到我們的Styles Conference網站。

  • 我們將使用inline-block元素來實現一個一排三列的可複用佈局。可以將其分為等寬的三列,或者分為兩列,一列佔2/3寬,一列佔1/3寬。
    首先,我們使用class選擇器定義列寬width,在main.css檔案中定義佔1/3寬的選擇器col-1-3,佔2/3寬的選擇器col-2-3。如下所示:
.col-1-3 {
  width: 33.33%;
}
.col-2-3 {
  width: 66.66%;
}複製程式碼
  • 我們想使這些列都以inline-block元素的方式呈現,我們就需要確保它們垂直對齊為頂部對齊。
    程式碼如下所示,建立由兩個選擇器共享的樣式:
.col-1-3,
.col-2-3 {
  display: inline-block;
  vertical-align: top;
}複製程式碼
  • 這段css程式碼中,col-1-3col-2-3之間用逗號,隔開。逗號表示第一個選擇器結尾,後面跟著第二個選擇器。第二個選擇器後跟隨大括號{標識樣式開始申明。用逗號隔開選擇器可以讓共用的樣式同時繫結到多個選擇器上。
  • 接下來我們想在每列之間存設定空隙,使內容隔開。我們可以在選擇器中新增橫向的padding
    設定之後我們可以看到,當兩列元素挨著排列時,它們之間的空隙會是行開始和末尾空隙的兩倍,為了使空隙一致,我們使用一個元素將這些列包裹起來,併為它設定相同的padding屬性。
  • 我們為這個包裹元素設定一個名為gridclass選擇器,將其新增到共用的padding定義中。程式碼如下所示,選擇器之前同樣用逗號隔開:
.grid,
.col-1-3,
.col-2-3 {
  padding-left: 15px;
  padding-right: 15px;
}複製程式碼
  • 當我們設定橫向padding後,我們需要小心。上節課中,我們建立了一個寬度為960px,class名為container的元素,並相對於頁面左右居中。現在如果我們將grid元素嵌入container元素中,那麼它們的橫向padding就會相加,我們的列與其他的部分呈現出的寬度會不一致。
    我們不希望發生這樣的事,所以我們要讓containergrid選擇器共享一部分樣式。具體的來說,就是共享寬度width(確保我們的頁面固定在960px寬)和外邊距margin(使grid元素居中),程式碼如下所示:
.container,
.grid {
  margin: 0 auto;
  width: 960px;
}
.container {
  padding-left: 30px;
  padding-right: 30px;
}複製程式碼
  • 現在每個class屬性包含有container或者grid的元素寬度都為960px,並相對於頁面居中。此外,我們也將container選擇器的橫向padding分離寫到了另一個樣式集中。

  • 到目前為止,所有繁重的可複用網格佈局的樣式已經寫完了。現在我們要將其新增到HTML中,看看它們呈現的結果。
    我們從index.html主頁的三個宣傳欄開始,將它們設定為三列。現在它們由一個class名為container<section>包裹。我們要將這個container替換為grid,如下所示:

<section class="grid">
  ...
</section>複製程式碼
  • 隨後我們將class屬性col-1-3新增到每個gird元素內的<section>元素上:
<section class="grid">

  <section class="col-1-3">
    ...
  </section>

  <section class="col-1-3">
    ...
  </section>

  <section class="col-1-3">
    ...
  </section>

</section>複製程式碼
  • 最後,因為我們的列都是inline-block元素,我們要確保我們移除了它們之間的間隙。我們用註釋來完成這一工作,並在每塊中新增一些模組說明,以便更好的組織我們的程式碼。
<section class="grid">

  <!-- Speakers -->

  <section class="col-1-3">
    ...
  </section><!--

  Schedule

  --><section class="col-1-3">
    ...
  </section><!--

  Venue

  --><section class="col-1-3">
    ...
  </section>

</section>複製程式碼
  • 上述程式碼中,我們在第3行的中新增了用以標識的註釋“Speakers”第7行我們在結束標籤<\section>後緊跟了註釋,在第9行新增了用以標識的註釋“Schedule”,並在11行開始標籤<section>前閉合了註釋。相同的註釋結構貫穿第13行和第17行,標識內容替換為Venue。總的來說我們已經將所有的間隙都註釋掉了併為每一塊<section>新增了標識。
    現在我們有了可複用的三列網格,可以使用1/3寬的列和2/3寬的列。主頁中我們用它來佈局了宣傳欄,最終結果如圖所示:

img
img

演示原始碼

這是練習的原始碼。點選下載

獨特的定位元素

我們常常想要定位一個元素,但floatinline-block並不能滿足這種需求。浮動將元素從正常的文件流中移除,經常出現我們不希望得到的環繞浮動元素顯示的佈局。inline-block元素,除非我們建立多列,否則不易實現我們想要的定位。針對這些情況,我們可以使用position屬性來做位置偏移。

position屬性表示元素應該怎樣定位在頁面中,是否按正常文件流顯示。這需要結合盒子的位移屬性——toprightbottomleft——通過定義位移值設定不同方向的位p移來定位元素在什麼位置顯示。

position屬性的預設值為static,他表示元素以正常文件流呈現,並且不接受盒子位移屬性。static常常會被relativeabsolute這兩個值複寫。這就是我們接下來要講的內容。

相對定位

position:relative在允許元素以正常文件流呈現,保留元素的空間不被其他元素佔用外,也允許元素通過修改位移屬性來定位,如下所示:

HTML

<div>...</div>
<div class="offset">...</div>
<div>...</div>複製程式碼

CSS

div {
  height: 100px;
  width: 100px;
}
.offset {
  left: 20px;
  position: relative;
  top: 20px;
}複製程式碼

img
img

例子中第二個<div>元素設定了class屬性為offsetoffset選擇器設定了position:relative和兩個位移屬性lefttop。這保留了元素原來的位置,不會被其他元素佔用。另外位移屬性重新定位了元素的位置,使它向右偏移20px,向下偏移20px

使用相對定位有一個重要的點要知道:盒子位移屬性是根據元素本身的位置來進行位移的。所以設定left:20px就是將元素從左向右位移20pxtop:20px就是元素至上向下位移20px

當使用position對元素進位移時,該元素會與其他元素重疊,而不是將其他元素像使用了marginpadding一樣移到下面。

絕對定位

position:absolute為絕對定位,它與相對定位不同,絕對定位脫離了文件流,而它原有的位置不會被保留。

另外,絕對定位的元素位移與離他最近的設定了相對定位的父級元素有關。如果沒有相對定位的父級元素,那麼絕對定位會根據<body>來定位(譯者:根據我的實踐,瀏覽器在絕對定位的元素沒有相對定位的父級元素時,並不是根據<body>定位,而是通過視窗的位置定位,有興趣的讀者可以嘗試一下)。這裡的資訊量比較多,我們通過例子來看一下:
HTML

<section>
  <div class="offset">...</div>
</section>複製程式碼

CSS

section {
  position: relative;
}
div {
  position: absolute;
  right: 20px;
  top: 20px;
}複製程式碼

img
img

在這個例子中,<section>元素是不包含位移屬性的相對定位的元素,所以它沒有位移。div元素設定了包含position: absoluteclass屬性offset。由於<section>是離它最近的設定了相對定位的父級元素,所以div依賴<section>元素的位置進行偏移

由於設定了righttop位移,<div>根據<section>元素從右向左位移20px,從上向下位移20px

由於<div>元素是絕對定位,它不在頁面的正常文件流中,會與它周圍的元素重疊。另外,<div>元素原來的位置也沒有被保留,其他元素可以佔據這個位置。

通常情況下,大多數的定位都不需要通過定位和位移屬性來處理,但在某些情況下它們確實非常有用。

總結

學習如何通過HTML和CSS來定位內容是掌握這兩門語言非常重要的一步。再加上盒子模型,我們正走在成為前端開發者的路上。

回顧一下,在這節課中我們所碰到的知識點:

  • 什麼是浮動,怎麼通過浮動定位內容
  • 怎麼清除和包裹浮動元素。
  • 怎麼通過inline-block元素定位內容。
  • 怎麼移除inline-block元素間的間隙。
  • 怎麼使用相對定位和絕對定位定位內容。

我們每節課都在學習新的技能,所以讓我們繼續。接下來,排版!

文章來源

learn.shayhowe.com/html-css/po…

最後的最後:
聽說寫文章可以得非同步社群的書,非同步社群作為國內頂尖的IT專業圖書社群,它的書我非常想要,尤其是這本書《HTML5 Canvas開發詳解》,大家如果覺得好給我點個贊吧

《HTML5 Canvas開發詳解》
《HTML5 Canvas開發詳解》

相關文章