深入研究顯示屬性:框生成
已發表: 2022-03-10display
屬性系列,這次 Rachel Andrew 看看控制框生成的值,對於那些你根本不想生成框的時候。 這是關於 CSS 中display
屬性的短系列文章中的第二篇。 您可以在“展示的兩個價值”中閱讀該系列的第一篇文章。 display
規範是一個非常有用的規範,因為它支持我們擁有的所有不同佈局方法。
雖然display
的許多值都有自己的規範,但display
中詳細說明了許多術語和想法。 這意味著理解此規範有助於您理解本質上詳細說明display
值的規範。 在本文中,我將看看display
- none
和contents
的框生成值。
一切都是一個盒子
在 CSS 中,一切都會生成盒子。 網頁本質上是一組塊和內聯框,如果您在最喜歡的瀏覽器中打開 DevTools 並開始選擇頁面上的元素,您就會很好地理解這一點。 您可以看到構成佈局的框,以及如何應用它們的邊距、填充和邊框。
控制盒子的生成
display
的none
和contents
值處理是否應該出現框。 如果您的標記中有元素並且不希望它們在 CSS 中生成框,那麼您需要以某種方式抑制框的生成。 您可能想做兩件事。 哪個是:
- 防止生成一個盒子及其所有子代。
- 防止生成框,但仍顯示子項。
我們可以依次看看這些場景中的每一個。
顯示:無
display
的none
值是我們如何防止生成一個盒子和該盒子的所有孩子。 就好像該元素根本不存在一樣。 因此,它在您打算完全隱藏該內容的情況下很有用,這可能是因為它稍後會在激活鏈接後顯示出來。
如果我有一個帶有段落、無序列表和另一個段落的示例,您可以看到這些項目以正常流程顯示。 ul
應用了背景和邊框,以及一些填充。
如果我向ul
添加display: none
,它會從視覺顯示中消失,同時ul
的子項以及背景和邊框。
如果您使用display: none
它會向網站的所有用戶隱藏內容。 這包括屏幕閱讀器用戶。 因此,只有當您的意圖是盒子和里面的所有東西對所有人都完全隱藏時,您才應該使用它。
在某些情況下,您可能希望為屏幕閱讀器等輔助技術的用戶添加其他信息,但對其他用戶隱藏它; 在這種情況下,您需要使用不同的技術。 Scott O'Hara 在他的文章“Inclusively Hidden”中提出了一些很好的建議。
因此,使用display: none
非常簡單。 在您希望盒子和內容從顯示器、盒子樹和可訪問性樹中消失的情況下使用它(就好像它從一開始就不存在一樣)。
顯示:內容
對於第二種情況,我們需要查看一個更新的 display 值。 值display: contents
會以與display: none
相同的方式從盒子樹中刪除它所應用的盒子,但將子元素留在原處。 就我們可以在佈局中執行的操作而言,這會導致一些有用的行為。 讓我們看一個簡單的例子,然後進一步探索。
我使用與以前相同的示例,但這次我在ul
上使用了display: contents
。 列表項現在是可見的,但是,它們沒有背景和邊框,就像您在頁面中添加了li
元素而沒有任何封閉的ul
一樣。
刪除一個盒子並保留孩子很有用的原因是由於display
的其他值的行為方式。 當我們改變display
的值時,我們會在一個盒子和那個盒子的直接孩子上這樣做,正如我在上一篇文章中描述的那樣。 如果我將display: flex
添加到元素的 CSS 規則中,則該元素將成為塊級框,而直接子項將成為 flex 項。 這些 flex 項的子項返回正常流程(它們不是 flex 佈局的一部分)。
您可以在下一個示例中看到此行為。 這裡我有一個包含元素集來顯示 flex,它有四個直接子元素、三個 div 元素和一個ul
。 ul
有兩個列表項。 直接子元素都參與了彈性佈局並作為彈性項目佈局。 列表項不是直接子項,因此在ul
的框內顯示為列表項。
如果我們舉這個例子並將display: contents
添加到ul
,則該框將從視覺顯示中刪除,現在孩子們參與了 flex 佈局。 您可以看到它們不會成為直系子代。 它們不像 div 和ul
元素那樣被直接子通用選擇器 ( .wrapper > *
) 選擇,並且它們保持給它們的背景。 所發生的只是包含ul
的框已被移除,其他一切都照常進行。
如果我們考慮 HTML 中的元素對可訪問性和語義數據很重要,但會生成一個額外的框,這可能會阻止我們使用 flex 或網格佈局來佈局內容,這可能具有非常有用的含義。
這不是 CSS “重置”
您可能已經註意到使用display: contents
的一個副作用是元素上的邊距和內邊距被移除。 這是因為它們與盒子有關,盒子是 CSS 盒子模型的一部分。 這可能會導致您認為display: contents
是快速擺脫元素上的填充和邊距的好方法。
這是 Adrian Roselli 在野外發現的一種用途。 他非常擔心,寫了一篇詳細的文章來解釋這樣做的問題——“ display: contents
不是 CSS 重置。” 他提出的一些問題是由於當前具有顯示的瀏覽器中的一個不幸的可訪問性問題:我們將在下面討論的內容。 然而,即使這些問題得到解決,從盒子樹中刪除一個元素只是為了擺脫邊距和填充有點極端。
如果不出意外,這對網站的未來維護會產生問題,未來的開發人員可能想知道為什麼他們似乎無法對這個神秘的盒子應用任何東西——錯過了它已被移除的事實! 如果您需要 margin 和 padding 為0
,請幫您未來的自己一個忙,並以一種歷史悠久的方式將它們設置為0
。 保留使用display: contents
用於您確實想要刪除框的特殊情況。
還值得注意的是display: contents
和 CSS Grid Layout subgrid 之間的區別。 其中display: contents
從顯示中完全刪除了框、背景和邊框,使網格項成為子網格將保持該項上的任何框樣式,並且只需通過軌道大小調整,以便嵌套項可以使用相同的網格。 在我的文章“CSS Grid Level 2: Here Comes Subgrid”中了解更多信息。
可訪問性問題和顯示:內容
目前一個嚴重的問題是display: contents
對它最有用的東西沒有用。 明顯的display: contents
是需要額外的框來添加標記的情況,使使用屏幕閱讀器或其他輔助設備的人更容易理解您的內容。
我們第一個display: contents
的列表中的ul
元素:contents CodePen 就是一個完美的例子。 通過展平標記而不使用列表,您可以獲得相同的視覺效果。 但是,如果內容在語義上是一個列表,屏幕閱讀器可以最好地理解和讀出該列表作為一個列表,那麼它應該被標記為一個。
如果您希望子元素成為 flex 或網格佈局的一部分,就像ul
的框不存在一樣,您應該能夠使用display: contents
來魔術框並使其如此——但離開語義到位。 規範說應該是這種情況,
“display
屬性對元素的語義沒有影響:這些是由文檔語言定義的,不受 CSS 影響。 除了會影響元素及其後代的聽覺/語音輸出和交互性的 none 值之外,display
屬性只影響視覺佈局:它的目的是允許設計人員自由更改元素的佈局行為而不影響底層文檔語義。”
正如我們已經討論過的, none
值確實對屏幕閱讀器隱藏了元素,但是display
的其他值純粹是為了讓我們改變事物的視覺顯示方式。 他們不應該觸及文檔的語義。
出於這個原因,我們很多人都驚訝地意識到display: contents
實際上是從實現它的兩個瀏覽器(Chrome 和 Firefox)的可訪問性樹中刪除元素。 因此更改文檔語義,使屏幕閱讀器在使用display: contents
刪除ul
後不知道列表是列表。 這是一個瀏覽器錯誤——而且是一個嚴重的錯誤。
去年,Hidde de Vries 在他的帖子“使用display:contents
的更易於訪問的標記”中寫下了這個問題,並幫助提出了針對各種瀏覽器的問題,以提高認識並讓他們進行修復。 Firefox 已部分解決了該問題,但某些元素(例如按鈕)仍然存在問題。 該問題正在 Chrome 中積極解決。 WebKit 也有一個問題。 如果您有用於顯示的用例,我鼓勵您為這些錯誤加註星標:受問題影響的內容。
在這些問題得到解決並且出現問題的瀏覽器版本不再使用之前,您在使用 display: content 時需要非常小心,因為它可以傳達語義信息並需要暴露於輔助技術。 正如阿德里安·羅塞利所說,
“目前,如果您要使用輔助技術進行測試並且可以確認結果對用戶有效,請僅使用 display: contents。”
有些地方你可以安全地使用display: contents
而不用擔心。 一種是如果您需要添加額外的標記來為舊瀏覽器中的 flex 佈局網格創建回退。 支持display: contents
的瀏覽器也支持 grid 和 flexbox,因此你可以display: contents
去掉多餘的div
元素。 在下面的示例中,我創建了一個基於浮動的網格,並帶有行包裝器。
然後我使用display: contents
刪除行包裝,以允許所有項目成為網格項目,因此能夠成為網格佈局的一部分。 這可以在為高級佈局創建後備時為您提供額外的工具,如果您確實需要添加額外的標記,您可以在執行網格或彈性佈局時使用 display: contents 刪除它。 我不認為這種用法會導致任何問題——儘管如果有人比我有更好的可訪問性信息並且可以指出問題,請在評論中這樣做。
包起來
本文研究了display
屬性的框生成值。 我希望你現在理解display: none
的不同行為——它完全刪除一個盒子和所有的孩子,而display: contents
只刪除盒子本身。 您還應該了解在涉及可訪問性時使用這些方法的潛在問題。