深入理解CSS的display屬性

w3cplus - 靜子發表於2016-07-01

在佈局中,display屬性是最重要的CSS屬性之一。其最常見的屬性值有block,inline,none,table以及inline-block。最近的新寵為flex,因為它是專門為佈局建立的display屬性。新出現的grid(最近仍比較活躍)是另外一個指定的佈局屬性,其很快就會廣泛被使用。

這篇文章比我預期的要長很多,你可以選擇性進行閱讀,但是我更希望你可以靜下心來閱讀整篇文章。

表內容

通過建立各種響應式設計,對於display以及position屬性我學習到了很多,關於他們的工作原理以及如何和媒體查詢相結合實現所需的佈局。我會簡短的介紹每一個值,並且會提及之前建立的與之有很強依賴性的一些響應式元件。

如果不涉及盒子樹(box tree)我們是沒有辦法談及這些屬性的。瀏覽器基本上是通過生成盒子樹解析CSS並進行相關渲染呈現,這裡盒子樹是指呈現文件的格式結構。display屬性定義了盒子的顯示型別。

關於瀏覽器如何進行渲染在螢幕上顯示這個話題,真的令人十分陶醉。這裡我建議你閱讀Talia Garsiel書寫的瀏覽器工作原理: 現代web瀏覽器的幕後。另外一篇必讀的文章是Fantasai書寫的CSS佈局演變: 始於1990年終於未來,該作者目前在W3C CSS規範組工作。她曾有一個優秀的演講:用於企業會議的新興技術,如果你對視訊不感興趣,還有一篇相關文章講解。

我們瞭解到的已經相當不錯了

有趣的事實: 我們所使用的display屬性值實際上有很大的限制。如:block在塊流中有很大限制。請參考規範獲取完整的列表。

所有的元素都有一個預設的display值,但是均可以被顯式設定所重寫。

display: none;

將元素與其子元素從普通文件流中移除。這時文件的渲染就像元素從來沒有存在過一樣,也就是說它所佔據的空間被摺疊了。元素的內容也會被螢幕閱讀所忽略。

display: inline;

Inline Elements

該元素生成一個或多個行內框。就如名字般,行內級元素所佔具的空間就是他的標籤所定義的大小。可以被視為對塊級元素的補充。

display: block;

Block Elements

該元素生成塊級框。除特殊宣告外,所有的塊級元素開始於新的一行,延展到其容器的寬度。

display: list-item;

元素被渲染為列表項呈現的方式,確切說就像是一個塊級元素,但是會生成一個可以被list-style屬性進行樣式修飾的標記框。只有<li>元素可以具有list-style的預設值。通常將<li>元素重置為預設行為。

display: inline-block;

該元素生成一個塊級別框,但是整個框的行為就像是一個內聯元素。嘗試在Codepen書寫此示例,改變視窗的大小,這樣會更有意義。

一個響應式的數字計數

我建立的元件之一是針對不同旅客使用的數字疊加器。我得到了一個用於移動佈局與一個用於桌面佈局的靜態的photoshop檔案。但是他們都具有一箇中間寬度以防“打破”佈局。

這主要是由於括號內的文字沒有很好的摺疊在一起。所以我需要使用媒體查詢進行寬度調整。使相關元素以不同的寬度顯示。在Codepen中查閱全尺寸效果並觀察該元件在不同寬度視窗的顯示。

是否記住基於表格的佈局?

這有一組display值允許你的元素表現類似於HTML表格。新加坡的開發人員Colin Toh寫了一篇優秀的有關於display為表格屬性的文章,你應該認真看一下。

雖然我們大多數的人都不在使用基於表格的佈局,display: table在一定的情況下還是十分有用的。如: 如果你想要在更廣泛的佈局上使用表格,但是在在較小寬度上保持典型的塊佈局。這可以同時結合媒體查詢與display(為了採取更好的措施,使用偽元素)進行實現,僅需要調整視窗的大小觀看實現的效果。

table 對應於HTML元素中的<table>。定義了一個塊級框。
table-header-group 對應於HTML元素中的<thead>
table-row 對應於HTML元素中的<tr>
table-cell 對應於HTML元素中的<td>
table-row-group 對應於HTML元素中的<tbody>
table-footer-group 對應於HTML元素中的<tfoot>
table-column-group 對應於HTML元素中的<colgroup>
table-column 對應於HTML元素中的<col>
table-caption 對應於HTML元素中的<caption>
inline-table 這是唯一沒有直接對映到HTML元素的值。這個元素的表現形式將為表格HTML元素,但是是一個內聯塊而不是塊級元素。
@media screen and (min-width: 720px) {
  .table {
    display: table;
    width: 100%;
    border-collapse: collapse;
  }
}

.tr {
  margin-bottom: 1.6rem;
}

@media screen and (min-width: 720px) {
  .tr {
    display: table-row;
  }
}

@media screen and (min-width: 720px) {
  .td {
    display: table-cell;
    border: #f0f0f0 1px solid;
    padding: 0.4rem;
  }
  .td:first-child {
    width: 11em;
  }
}

.th {
  font-size: 1rem;
  line-height: 1.6rem;
  font-family: "Palo Alto";
}

@media screen and (min-width: 720px) {
  .th {
    font-size: 1.294rem;
    line-height: 1.6rem;
  }
}

@media screen and (min-width: 720px) {
  .th {
    font-size: 0.8rem;
    line-height: 1.6rem;
    font-family: "Roboto Slab", Rockwell, serif;
    font-weight: 700;
  }
}

@media screen and (min-width: 720px) and (min-width: 720px) {
  .th {
    font-size: 1rem;
    line-height: 1.6rem;
  }
}

.th::before {
  content: 'display: ';
}

@media screen and (min-width: 720px) {
  .th::before {
    content: '';
  }
}

.th::after {
  content: ';';
}

@media screen and (min-width: 720px) {
  .th::after {
    content: '';
  }
}

塊的新屬性

Tab Atkins Jr.是Flexbox以及網格規範的主要作者,關於新佈局規範的顯示模式提出了最突出的一點。

Flexbox是一維佈局 — 用於任何需要在一條直線上顯示的佈局(或者是中斷線,如果他們迂迴在一起則會表現為單一的直線)。 網格是二維佈局,它可以用於低功能的flexbox的替代品(我們已經測試過單一的行/列的形式十分近似於flexbox),但是不可以用於完全替代。 – Tab Atkins Jr. to www-style

需要時刻牢記於心,在工作中使用這些新CSS佈局,並在使用過程中對其充滿了困惑。

display: flex;

引入flexbox佈局模組或CSS彈性框,標誌著我們第一次有了專門為瀏覽器內容進行佈局的規範。自從HTML被引入之後,網頁內容佈局已經演變了很多。當設計者想要建立一些富有創意的設計時,使用的第一種方法就是巢狀的HTML表格,或者我們所說的基於表格的佈局。

當CSS開始升溫的時候,我們轉向了基於浮動的佈局,通過將內容巢狀在不同的div中進行浮動實現想要的效果。基於浮動的佈局仍然十分常見,但是隨著時間的推移,所有當代瀏覽器均支援flexbox佈局。我相信不久的將來基於flexbox與網格的佈局將會成為佈局的普遍方式。

這裡我要引用Scott Vandehey的文章 - 什麼是Flexbox?。這是其向Tab Atkins Jr.探索Flexbox歷史時所書寫的一篇文章。最早的草案規範日期為2009年7月23日,但是討論始於幾年之前。

然而並沒有什麼正式的結構,各瀏覽器供應商也已經實現了flexbox,但是並沒有真正的遵循規範。這也是為什麼felxbox語法變得一團糟的原因(向後相容一些老的瀏覽器時也是如此)。

flexbox模型是十分強大的,它可以實現很多功能,如果想要徹底搞明白flexbox的工作原理以及如何使用它,你需要多花點心思。flexbox以及網格佈局需要長篇的文章進行深度覆蓋,這裡我列舉了一些有關於flexbox的相關文章:

在一個元素上宣告dispaly: flex,它就會變為flex容器,同時它的子元素就會變為flex項。這不會被繼承即其子元素的下一代不會具有felx屬性。flex容器和flex項都有各自的flex屬性。

再次強調,我希望你認真查閱上述有關於flexbox的資源列表,這將會有助於你更好地理解並使用flexbox。

flex容器屬性

flex-direction 定義了主軸以及flex項的方向。flex-direction值的完整列表
flex-wrap 指定flex項的調整,單行顯示亦或允許多行顯示。flex-wrap值的完整列表
flex-flow flex-direction以及flex-wrap屬性的補充。flex-flow值的完整列表
justify-content 定義flex項沿主軸分佈時的間隙大小。justify-content值的完整列表
align-items 定義flex項在垂直主軸分佈時的間隙大小。align-items值的完整列表
align-content 指定行flex項在flex容器內如何分佈,如果flex項為單獨一行則不適用。align-content值的完整列表

flex項的相關屬性

order 指定flex項的佈局順序,按順序值進行升序,若值相同根據源順序進行佈局。order值的完整列表
flex-grow 若有足夠空間,定義元素是否可擴充套件,根據此值確定該元素擴充套件的空間比例(這有些小複雜)。flex-grow值的完整列表
flex-shink 若沒有足夠空間,定義元素是否可縮小,該值決定了元素可縮小的比例。flex-shink值的完整列表
flex-basis 制定了flex項在主軸方向上的輸出大小。flex-basis值的完整列表
flex flex-grow,flex-shrink,flex-basis屬性的補充。felx值的完整列表
align-self 指定單個flex項的被重寫的對齊方式。align-self值的完整列表

display: grid;

任何有關網格佈局的,我都會去參考Rachel Andrew - 我認為她是CSS網格大師。她一直在帶頭努力提高人們對這個新的display屬性的認識,通過一些演講,文章以及教程。

CSS網格使我們可以建立網格系統並且可以純粹使用CSS控制網格項的定位,實現了與HTML的分離。當結合使用媒體查詢時,CSS網格變成了一個有用的工具用於設計並建立一些靈活的佈局。

當前的CSS網格佈局模組1草案始於2011年。像flexbox,本規範的成熟需要一個用於佈局的適當的方法,奠定網頁內容而不損害HTML語義。

注意,雖然Microsoft Edge以及Internet Explorer可以使用-ms-實現舊版本瀏覽器的支援,CSS網格還沒有在所有的瀏覽器中實現。這並不足以為奇,因為最原始的網格規範的編輯大部分來自於Microsoft。

在flexbox規範凌亂的實施之後,正在發展的CSS網格採取了不同的做法。瀏覽器供應商使用不同的供應商字首將正在實驗的功能新增到瀏覽器中以便於開發人員的測試。這十分有助於規範的制定,並且在正式規範形成之前找到所有的缺陷。

為了這樣子實施,CSS網格發展了一個標記。它必須由開發人員手動啟動。在Chrome和Opera中,分別導航到chrome://flagsopera://flags,並啟動“網頁實驗平臺功能”。對於 Firefox,導航到about:config並將layout.css.grid.enabled以及layout.css.grid-template-subgrid-value.enabled設定為true。

CSS網格的關鍵術語

Grid Container 相似於flex容器的概念,元素宣告為display: grid;。其直接後代(子元素)為網格項
Grid Item 如果父元素為display: grid;, 那麼這個元素就被視為網格項。網格項的子元素不被視為網格項。
Grid Track 可以為網格的行或列。
Grid Line 定義網格結構的線,被視為網格軌道之間的界限。
Grid Cell 單個的網格單元,由相鄰的水平和垂直的網格線所包圍的空間。
Grid Area 最酷的一部分。由多個網格單元格組成的區域。

試圖用簡短的語言概述網格真的是一件十分具有挑戰的事情。請參考一下資源,並嘗試使用CSS網格進行實現。事實上,你可以現在進行網格相關實驗並且檢視Codepen有關於網格不同用例的相關連結的演示。

相對模糊並處於實驗性的

display: run-in;

這是十分有趣的一個,我之前都不知道它的存在知道我閱讀了CSS display 規範。並且我也閱讀了2010文章,Chris Coyier書寫的CSS Run-in Display值。不幸的是,瀏覽器廠商不喜歡這種規範已被移除,這樣你就可以認為這是一個備用的現實規範。

事實上,你將一個元素的display屬性設定為run-in,就會渲染一個run-in框。用例就是使用本地方法建立一個run-in標題,這在平面設計中的說法是和正文位於同一行的標題。

Sameen Shaw.Also known asIndigo Five Alpha,Dr. Sameen Shawor simplyShaw, is a physician and aformer operative for the U.S. ArmyIntelligence SupportActivity. Prior to joining the team Shaw was part of anoperation known as Catalyst Indigo, responsible for actingon relevant list intelligence delivered bythe Machine, whichshe knew only as “Research”.

你可以使用浮動實現相似效果,但是被視為一個hack方法。將標題的基線定位到正文基線上是具有挑戰性的,你需要調整標題字型大小以及正文的行高使之相匹配。並有可能出現標題多餘一行的情況。

如果你將標題的設定為display: inline,除非你將標題巢狀在段落元素內(p為塊元素),否則它不會工作的。但是這又會出現語義上的錯誤。就我個人而言我希望看到其可以實現,但是我想那時瀏覽器廠商會有更多的擔憂。

display: ruby;

介紹這一特定屬性之前需要首先介紹一下<ruby>元素。簡單地說,有一種元素用於在文字基線旁的註釋,通常是幫助發音。這對於東南亞語言是十分常見的,如漢語或者日語。我所研究的大多數文章是2010年左右,所以我使用<ruby>書寫了2016的狀態

display:ruby;display:table;有很大的相似之處,但是規範不鼓勵將ruby值應用到非ruby元素上,如使用span顯示ruby文字。相反,我們應該使用HTML ruby元素,所以螢幕閱讀器和非CSS渲染器可以解析ruby結構的內容。

ruby 對應於HTML元素中的<ruby>,它將生成一個ruby容器框,產生一個ruby格式上下文用於標記為內部ruby框的子元素。
ruby-base 對應於HTML元素中的<rb>,ruby格式上下文中的一個內部ruby框。
ruby-text 對應於HTML元素的<rt>,ruby格式上下文中的內部ruby框。
ruby-base-container 對應於HTML元素的<rbc>,ruby格式上下文中的一個內部ruby框。
ruby-text-container 對應於HTML元素中的<rtc>,ruby格式上下文中的一個內部ruby框。

display: contents;

元素本身不會產生任何框,但是其子元素和偽元素可以正常生成框。為了框的生成和佈局,需要將元素處理為好像和子元素或者偽元素一樣處於文件樹中。 – CSS Display Module Level 3

規範想表達的是,當你將一個元素設定為display:contents,它就會從DOM中消失,但是其子元素會保留並且佔據空間。不幸的是,本規範現在僅僅得到了火狐的支援。在火狐瀏覽器下,調整全尺寸的Codepen來感受其效果。

我已經嘗試概述迄今為止談及該屬性的兩篇文章,Sam Rueby書寫的火狐所支援的CSS屬性 – dispaly:contents以及Rachel Andrew書寫的display:contents與消失的的框。Rachel Andrew還介紹了使用flex-items書寫的有關於這個屬性的一個神奇的用例。

總結

這篇文章的長度超出了我的預期,如果你閱讀到此,我要表示真摯的感謝。我很高興不久的將來我們就可以在不使用hack的情況下使用這些佈局。同時,希望這篇文章可以幫助你瞭解到更多有關於CSS佈局相關的知識。

相關文章