那個盒子有多大? 了解 CSS 佈局中的大小

已發表: 2022-03-10
快速總結 ↬當開始使用 Flexbox 和 Grid 時,會發現我們有時沒有得到我們期望的佈局可能會令人沮喪。 這通常是由於在這些新佈局方法中計算尺寸的方式。 在這篇文章中,我試圖準確地解釋那個盒子有多大,以及它是如何變成那麼大的!

Flexbox 和網格佈局的一個關鍵特性是它們可以處理在網格和彈性項目之間、周圍和內部分配可用空間。 很多時候,這只是工作,我們得到了我們希望的結果,而不需要非常努力。 這是因為規範試圖默認使用最可能的用例。 但是,有時您可能想知道為什麼某些東西最終會變成它的大小。 或者,您可能想做一些與默認行為不同的事情。 為此,您需要了解底層算法如何確定如何分配空間。

在本文中,我將與您分享一些關於在 CSS 中調整框大小的有趣事情。 我從規格中挑選了一些東西,我認為這些東西對於準確理解那個盒子有多大至關重要。 花點時間通讀一遍,我想你會發現 Grid 中的大小調整不那麼神秘了!

仔細看看 BFC

如果您曾經使用 CSS 製作過佈局,那麼您可能知道 BFC 是什麼。 了解它為什麼起作用以及如何創建它很有用,並且可以幫助您了解佈局在 CSS 中的工作原理。 閱讀相關文章 →

長度單位

我們可以從最熟悉的尺寸開始。 CSS 值和單位模塊規範中描述的長度單位。 如果您將<length>視為 CSS 屬性的允許值,則它表示此處列出的值之一。 這些值都是距離,通常由一個整數加上單位標識符組成 - 例如12px1em 。 如果值為0 ,則可以省略單元標識符。 此外,長度單位分為相對長度和絕對長度。

跳躍後更多! 繼續往下看↓

相對長度

相對長度採用相對於其他事物的大小,因此如果它相對於事物發生變化,則使用相對長度定義的事物的最終大小可能會有所不同。

完整的相對單位集如下。 前四個單位是相對於字體的,而後四個是相對於視口的。

  • em
  • ex
  • ch
  • rem
  • vw
  • vh
  • vmin
  • vmax

由於這些值是相對於某物的,因此準確識別它們相對於什麼是很重要的。 對於字體相對單位rem那麼這總是相對於作為 HTML 文檔的根元素的大小是html元素。

在下面的第一個示例中,我將html元素的字體大小設置為 20 像素。 因此1rem是 20 像素。 如果我給一個元素寬度為10rem ,它將變為 200 像素寬(因為 20px 乘以 10 是 200)。

當其他字體相對單位( emexch )用於元素的長度時,它們與應用於該元素的字體大小相關。 在第二個示例中(框的寬度為10em ), em單元查看應用於它正在調整大小的元素的字體並基於該字體進行計算。 所以,這個盒子變成了 300 像素寬,因為盒子的 font-size 是30px

請參閱 Rachel Andrew (@rachelandrew) 在 CodePen 上使用 rems 和 em 進行的 Pen Sizing。

請參閱 Rachel Andrew (@rachelandrew) 在 CodePen 上使用 rems 和 em 進行的 Pen Sizing。

字體相對單位是根據字體大小計算的,視口相對單位是相對於稱為初始包含塊的矩形計算的。 在屏幕上,它具有視口的尺寸。 vw單位是視口寬度的1 / 100和高度的vh 1 / 100 。 一個寬度為50vw ,高度為50vh的盒子應該是視口寬度的一半和高度的一半。

一個盒子,它是視口高度的 50% 和寬度的 50%
vhvw單位,代表視口高度和寬度的1 / 100

vminvmax單位很有用,因為它們允許您相對於視口的較大或較小尺寸來調整某些東西的大小。 例如,這意味著您可以製作視口最長邊的 50%。 當有人可能以橫向或縱向模式持有設備時,這尤其有用。 vmin單元始終解析為 small 或vwvh ,而vmax解析為較大的vwvh 。 因此,如果您希望寬度始終為設備最長邊的 20%,則可以使用20vmax 。 如果設備處於縱向模式,則20vmax將與20vh相同。 如果設備處於橫向模式,它將與20vw相同。

下面的示例將使用vwvh大小的塊與使用vminvmax大小的塊進行比較。 在台式計算機或橫向模式下的手機上,兩個框的大小應相同。 將手機切換到縱向模式或拖動窗口以使寬度小於高度,您將看到第二個塊如何更改計算的維度。

請參閱 CodePen 上 Rachel Andrew (@rachelandrew) 的 Pen vw 和 vh、vmin 和 vmax。

請參閱 CodePen 上 Rachel Andrew (@rachelandrew) 的 Pen vw 和 vh、vmin 和 vmax。
一個盒子,它是視口高度的 50% 和寬度的 50%
vmaxvmin單位:在橫向格式中, vmax使用寬度,而vmin使用高度。
一個盒子,它是視口高度的 50% 和寬度的 50%
vmaxvmin單位:在縱向格式中, vmax使用高度,而vmin使用寬度。

絕對單位

絕對單位映射到物理尺寸並且不相對於屏幕上的其他事物進行縮放。 因此,當輸出環境已知時,它們最有用。

下面的列表顯示了 CSS 中允許的絕對單位:

  • cm
  • mm
  • Q
  • in
  • pc
  • pt
  • px

正如您所看到的,其中許多在屏幕上下文中幾乎沒有意義,但是,如果您正在創建用於打印的 CSS,那麼當您知道您的紙張大小時,使用ptin可能會很有意義。

像素被歸類為絕對長度單位,任何為 Retina 設備創建圖像的人都知道,就長度而言,像素與設備像素不同。 CSS 使用了參考像素的概念,規范建議像素單位是指最接近參考像素的設備像素的整數。

參考像素是像素密度為 96dpi 且距離閱讀器一臂遠的設備上一個像素的視角。 對於 28 英寸的標稱臂長,因此視角約為 0.0213 度。 對於在手臂長度上閱讀,1px 因此對應於大約 0.26 毫米( 1 / 96英寸)。 —“CSS 值和單位模塊第 3 級”,W3C

百分比

在大多數情況下,您可以使用百分比而不是長度單位來表示大小。 然後需要根據某些東西來計算這個百分比,就像解析相對長度單位一樣,您正在使用的佈局方法的規範將指示百分比應該是 的百分比

在規範中,您將<length-percentage>視為長度的允許值,這意味著百分比將在使用之前解析為長度。 在下面的示例中,外部元素的寬度為 400 像素,第一個子元素的寬度為 50%。 然後解析為 200 像素 - 400 的 50%。

第二個子元素的寬度使用calc ,將 50 像素添加到 50%,使該塊寬 250 像素。 因此,50% 被解析為一個長度,然後用於計算。

請參閱 Rachel Andrew (@rachelandrew) 在 CodePen 上的 Pen length-percentage。

請參閱 Rachel Andrew (@rachelandrew) 在 CodePen 上的 Pen length-percentage。

我們這些在響應式設計時代從事網絡工作的人已經習慣於使用百分比來創建看起來像是在網格上佈置的佈局。 以百分比工作給了我們一定程度的控制,我們需要開始放棄控制,以便充分利用 Grid 和 Flexbox 的力量!

CSS 內部和外部大小

到目前為止,我們已經了解瞭如何給盒子一個大小,以各種方式設置它們的寬度和高度,以及如何使用長度單位和百分比。 但是,您網頁上的框是有大小的——即使您沒有給它們一個大小。 了解元素在頁面上的佈局方式很重要,並且在使用 flexbox 和 Grid 佈局時,尺寸變得越來越重要。 Grid 和 flexbox 具有很多內置的靈活性,因為它們管理的情況是顯示項目所需的空間多於顯示項目所需的空間,或者項目需要容納的空間比空間無限大時它們佔用的空間要少。

定義事物大小並為您提供控制該大小的其他方法的模塊是 CSS Intrinsic and Extrinsic Sizing Module。 在下一節中,我們將看看這個模塊定義了什麼,以及為什麼它對你理解 flexbox 和 grid 中的佈局至關重要。

調整關鍵字大小

該模塊的摘要說:

該模塊使用代表基於內容的“內在”大小和基於上下文的“外在”大小的關鍵字擴展了 CSS 大小調整屬性,允許 CSS 更輕鬆地描述適合其內容或適合特定佈局上下文的框。

關鍵字可用於通常需要一定長度的任何屬性。 例如widthheightmin-width等,此外還指定用於 Grid Layout 軌道大小和 flexbox flex-basis 。 當前3 級核心規範編輯草案中定義的關鍵字值是:

  • max-content
  • min-content
  • fit-content(<length-percentage>)

讓我們看看如果我們將其中一些關鍵字用於 div 的寬度,它們會如何表現。 div 是塊級元素,因此,如果你不給它一個寬度,它會延伸到內聯維度中盡可能寬的寬度。 直到它到達視口或包含塊的邊緣。

如果一串文本比允許的空間長,它將包裹在 div 內,並且盒子會變得更高以容納它。 要給 div 一個寬度,而不是包含塊允許的空間,您可以使用前面討論的任何長度單位。 一旦達到該長度,文本就會開始換行。

您可能希望允許內容決定大小,而不是使用長度限制框或通過它撞擊包含塊的邊緣來限制框。 這就是這些新的基於內容的大小調整關鍵字的用武之地。

最小含量

在 div 上使用width: min-content ,現在 div 只會變得盡可能大,而內容在行內方向上變得盡可能小。 對於一串文本,這意味著文本會利用它所能提供的所有軟包裝機會。

請參閱 Rachel Andrew (@rachelandrew) 在 CodePen 上的 Pen min-content。

請參閱 Rachel Andrew (@rachelandrew) 在 CodePen 上的 Pen min-content。

這是此元素的最小內容大小。 它可以得到的最小的,沒有任何內容以某種方式溢出。

最大內容

如果我們使用width: max-content ,則會發生相反的行為。 現在盒子變得足夠大以容納內容,如果它在內聯維度上變得盡可能大的話。 我們的文本字符串現在伸展並且根本不換行。 如果它變得比這個 div 必須增長到的可用寬度更寬,這將導致溢出。

請參閱 Rachel Andrew (@rachelandrew) 在 CodePen 上的 Pen max-content。

請參閱 Rachel Andrew (@rachelandrew) 在 CodePen 上的 Pen max-content。
我可以使用屏幕截圖來調整內容大小的關鍵字嗎
圖片來源:我可以使用內在寬度關鍵字嗎

這些內容關鍵字正在傳送到瀏覽器中,您可以在 Chrome 中使用它們,也可以在 Firefox 中作為widthheight的值使用它們。 您可以將它們用於網格佈局中的軌道大小,正如我們將在下面探討的那樣,但它們在 flexbox 中還沒有實現flex-basis 。 但是,現在查看這些的真正原因是要了解存在min-contentmax-content ,因為一旦我們開始研究 Flexbox 和 Grid 中的空間分佈方式,具有最小和最大內容大小的事物就很重要。

CSS 網格佈局中基於內容的大小

CSS 網格佈局對我們剛剛探索的內容關鍵字進行了可靠的實現,用於調整網格軌道的大小。 這意味著您可以使內容決定網格上的軌道大小。 使用網格要記住的重要一點是它是一個二維佈局模型。 如果您要求列軌道變成min-content大小,那麼軌道將根據軌道中最寬的東西調整大小。

最小含量

在下一個示例中,我有一個三列跟踪網格。 使用min-content關鍵字調整列的大小。 其中一個單元格包含更多內容,您可以看到內容如何包裝到它能夠包裝的地方。 以min-content大小顯示此內容所需的大小成為整個軌道的大小。

請參閱 CodePen 上 Rachel Andrew (@rachelandrew) 的網格佈局中的 Pen min-content。

請參閱 CodePen 上 Rachel Andrew (@rachelandrew) 的網格佈局中的 Pen min-content。

最大內容

如果我們查看與min-content相同的示例,但將列更改為每個使用max-content ,您可以看到包含具有大量文本的項目的軌道如何增長以適應文本。 這導致軌道比我們定義網格的元素的大小更寬,所以它已經溢出。

請參閱 CodePen 上 Rachel Andrew (@rachelandrew) 的網格佈局中的 Pen max-content。

請參閱 CodePen 上 Rachel Andrew (@rachelandrew) 的網格佈局中的 Pen max-content。

適合內容

fit-content是我們尚未研究但已在 Grid Layout 中實現的關鍵字。 此關鍵字採用長度或百分比作為值。 當您使用fit-content進行軌道大小調整時,軌道將像max-content一樣運行,直到達到您傳入的值的大小。一旦達到該大小,軌道將停止增長,並且內容將換行。

下面示例中的所有三列軌道都使用fit-content(10em)調整大小。 如果軌道比 10em 窄,它的作用類似於max-content 。 運行時間更長的中心軌道一旦達到 10em 就會停止增長。

請參閱 CodePen 上 Rachel Andrew (@rachelandrew) 的網格佈局中的 Pen fit-content。

請參閱 CodePen 上 Rachel Andrew (@rachelandrew) 的網格佈局中的 Pen fit-content。

注意我創建了一個簡短的視頻教程來演示這些內容大小調整關鍵字

自動大小的軌道

在深入挖掘軌道尺寸的兔子洞之前,了解auto用於軌道尺寸的含義也很重要。 隱式網格軌道是使用auto調整大小創建的,當您開始使用 Grid 時,您通常會理解這一點。 您指定列軌道,然後將內容放入沒有明確定義的行中。 行軌道會增長以包含內容,因為auto會查看內容大小並創建足夠高的軌道以包含它。

但是, auto在規範中具有特定的含義。 在 Grid 和 flexbox 的情況下,如果您使用auto作為軌道大小或作為flex-basis的值,它將查看項目上是否有任何大小(或 Grid 的該軌道中的任何項目上)和將該尺寸用作基本軌道尺寸或flex-basis的值。 您可以在下面的 CodePen 中看到這種情況。 第一個示例是 Grid 佈局,第二個示例是 Flex 佈局。 Grid 佈局有三列軌道,它們都是auto調整大小的,Flex 佈局中的每個項目都可以從autoflex-basis擴展和收縮。

在這兩種佈局中,最終項目的寬度均為 200 像素。 您可以看到在計算軌道尺寸時如何使用該寬度。 它成為flex-basis作為最後一項,以及網格軌道的基本大小。 對於其他 Grid 軌道和彈性項目,沒有寬度,因此算法使用內容大小。

請參閱 CodePen 上 Rachel Andrew (@rachelandrew) 的 Pen Grid track and flex-basis of auto。

請參閱 CodePen 上 Rachel Andrew (@rachelandrew) 的 Pen Grid track and flex-basis of auto。

在轉向另一種調整網格軌道大小的方法之後,我們將回到auto的行為方式,以及它如何與其他軌道大小調整方法結合使用。

fr單位

本文開頭討論的所有長度單位也可用於網格佈局中的軌道大小。 我們在fr單元中還有一個額外的單元。 這僅適用於網格佈局,因此在網格規範中而不是在任何與尺寸相關的模塊中都有詳細說明。 fr單位是一個靈活的長度<flex> ,表示網格容器中剩餘空間的一小部分。

fr單位不是長度,它不能像百分比或長度單位一樣與calc()一起使用。

你經常會看到一個像下面這樣的演示,我們使用fr單元創建了三個相同大小的軌道。 網格容器中的空間被分成了三個,並平均分配給每個軌道。

請參閱 CodePen 上 Rachel Andrew (@rachelandrew) 的 Pen The fr 單元。

請參閱 CodePen 上 Rachel Andrew (@rachelandrew) 的 Pen The fr 單元。

如果您的flex-basis0 ,此處的fr單元的行為與 Flexbox 的行為非常相似。 網格佔用了網格容器中的所有空間,並將一個部分交給每個軌道。 但是,這樣做時 Grid 不會導致軌道溢出。 如果您認為1fr的三個軌道始終是三個大小相等的軌道,則此行為可能會令人困惑。

如果我們在中間軌道中添加一個很長的單詞,它不能軟換行,例如Supercalifragilisticexpialidocious ,那麼我們不會得到三個等寬的列。

請參閱 CodePen 上 Rachel Andrew (@rachelandrew) 的 Pen The fr unit 2。

請參閱 CodePen 上 Rachel Andrew (@rachelandrew) 的 Pen The fr unit 2。

Grid 僅在確保軌道足夠大以容納項目後才共享可用空間。 如果我們使用min-content ,網格會查看軌道的大小。 如果該大小小於將通過fr單元傳遞給軌道的大小,則不考慮內容。 如果該min-content大小大於fr單元給出的軌道,則在剩餘空間被共享之前,該min-content大小用於該軌道。

因此, fr單元的行為就像使用flex-basis0的 flexbox 一樣,除非該軌道的min-content大小更大,然後它的行為更像使用flex-basisauto的 flexbox。 就像我們在上一節中的auto示例一樣。 如果您的等寬軌道看起來不太相等,則值得記住這一點。 可能的原因是其中一個軌道中的某些內容的min-content大小大於傳遞給它的內容。

使用minmax製作相等的曲目

我們現在知道為什麼fr單元可能會創建比我們想要的更大的軌道。 但是,我們可以通過引入另一種特定於網格的大小調整方法 - minmax()函數來控制其行為方式。 在上面的示例中(一個軌道中的長字強制更大的min-content大小),Grid 的行為就像我們使用以下軌道大小定義一樣。

 .grid { display: grid; grid-template-columns: minmax(auto,1fr) minmax(auto,1fr) minmax(auto,1fr); }

Grid 正在查看解析為content大小的auto大小,並將其用作軌道的基本大小,然後再共享任何剩餘空間。

如果您希望 Grid(在上面的示例中)強制使中間軌道與網格容器中的寬度相等,即使這會導致任何溢出,您可以通過將minmax()中的第一個值設為0來實現。 正如您在下一個示例中看到的,這將導致溢出。

請參閱 CodePen 上 Rachel Andrew (@rachelandrew) 的 Pen The fr unit 和 minmax。

請參閱 CodePen 上 Rachel Andrew (@rachelandrew) 的 Pen The fr unit 和 minmax。

您可以看到為什麼規範默認為它所做的行為。 一般來說,如果有空間顯示內容,我們不希望發生溢出,但是,如果需要,您可以強制執行此操作並導致溢出。

minmax()函數在調整行大小以防止行在空時折疊到零高度時也非常有用,但仍允許它增長到允許添加任何內容的大小。 在下一個示例中,我將grid-auto-rows設置為minmax(50px, auto) 。 隱式網格中的軌道總是 50 像素高,但是您可以看到第二行更高,因為該行的一個單元格中的內容量很大。

請參閱 Rachel Andrew (@rachelandrew) 在 CodePen 上的 Pen minmax with a max of auto。

請參閱 Rachel Andrew (@rachelandrew) 在 CodePen 上的 Pen minmax with a max of auto。

網格佈局中的百分比

雖然我們在網格佈局中有fr單位、基於內容的大小和我們通常的長度單位,但您可能仍希望使用百分比來滿足某些大小要求。 在大多數情況下, fr單位將是更好的選擇,但是,有時您可能希望自己控制確切的百分比大小。 這樣做的一個原因是,如果您在設計中排列使用 Grid 佈局的元素,該設計還使用其他依賴於百分比大小的佈局方法。

大多數情況下,百分比大小將按您的預期工作。 使用百分比調整大小的網格軌道將根據網格容器寬度計算百分比。 您還可以為gap屬性使用百分比,這些也將根據網格容器寬度進行計算。 下面的示例具有三個列軌道,每個軌道為 30%,軌道之間的網格間隙為 5%。

請參閱 CodePen 上 Rachel Andrew (@rachelandrew) 的筆百分比軌跡和間隙。

請參閱 CodePen 上 Rachel Andrew (@rachelandrew) 的筆百分比軌跡和間隙。

需要注意的地方是在使用百分比作為垂直邊距和填充時。 在 Flexbox 和 Grid 中,一個長期存在的問題意味著垂直百分比邊距和填充的計算方式在瀏覽器之間會有所不同。

您可以在我的帖子“我們應該如何解決網格和彈性項目上的百分比邊距和填充”中閱讀有關此問題的更多信息,但是,我的建議和規範的建議是避免使用百分比作為邊距和頂部和底部的填充時間因為結果會不一致。

網格佈局中的對齊和大小調整

在網格佈局中使用框對齊屬性還可以更改網格中區域的大小。 考慮以下具有四個 100 像素列軌道、三個 50 像素行軌道和 20 像素間隙的佈局。 網格軌道不會佔據網格容器的全部區域,因此會自行對齊以在兩個軸上start 。 跨越多個軌道的項目的大小是它們跨越的所有軌道和間隙的總和。

請參閱 Rachel Andrew (@rachelandrew) 在 CodePen 上的 Pen Grid 軌道對齊和證明。

請參閱 Rachel Andrew (@rachelandrew) 在 CodePen 上的 Pen Grid 軌道對齊和證明。

如果我現在使用具有space-between值的 Box Alignment 屬性align-contentjustify-content ,軌道會隨著間隙的增加而展開以吸收額外的空間。 現在,任何跨越多個軌道的項目都變得更大,因為它包含了現在擴大的間隙的空間。

請參閱 Rachel Andrew (@rachelandrew) 在 CodePen 上的 Pen Grid 跟踪 align-content 和 justify-content space-between。

請參閱 Rachel Andrew (@rachelandrew) 在 CodePen 上的 Pen Grid 跟踪 align-content 和 justify-content space-between。

Flexbox 和 Grid 中的空間分佈比較

我認為在處理佈局時理解諸如min-contentmax-content之類的概念非常重要的原因是,它們使您能夠開始深入研究佈局的細節。 我將用一個很好的例子來結束這篇文章,當我們需要將項目放入容器中時,我們通過比較 flexbox 和 Grid 中發生的事情來發現這一點。

該示例顯示了一個包含四個彈性項目的彈性容器; 下面是一個帶有四個網格項的網格容器。 此內容是相同的,但佈局略有不同,儘管這些佈局大致相當。 彈性項目具有autoflex-basis並且允許收縮。 網格定義定義了四個軌道,所有軌道的大小都為auto

請參閱 CodePen 上 Rachel Andrew (@rachelandrew) 的 flexbox 和網格中的 Pen Space 分佈。

請參閱 CodePen 上 Rachel Andrew (@rachelandrew) 的 flexbox 和網格中的 Pen Space 分佈。

在 flexbox 示例中,較短的項目已折疊到其min-content大小,而較大的項目已被給予更多空間。

在 Grid 示例中,較小的項目以其max-content大小顯示,因此較長的項目顯示的空間較小。 當我第一次看到這種行為時,我感到很困惑。 差異的原因歸結為在佈局方法中計算項目大小的算法。 在 Flexbox 中,項目從max-content大小開始; 由於flex-shrink是一個正值,因此開始從每個項目中佔用空間。 一旦較小的項目達到min-content大小,flexbox 就會停止佔用空間以防止它們消失或溢出。

然而,網格從min-content大小的項目開始,然後添加空間。 我們的項目很快達到max-content大小,此時網格停止為它們分配空間,因為我們有一個更大的項目可以填充剩餘空間。 既然您了解了min-contentmax-content ,您將能夠發現曲目或項目何時以這種方式顯示,這將為您提供一個起點來挖掘並弄清楚發生了什麼。

大小事項!

雖然計算百分比大小以排列事物從來都不是一件有趣的事情,但至少我們都理解這一點。 它給了我們很大的控制權,儘管這意味著我們必須完成所有的工作。 開始使用 Flexbox 和 Grid 時可能會感到沮喪,只是發現有時我們沒有得到我們期望的佈局。 回到我們自己做這項工作並使用百分比來衡量我們的flex-basis或軌道大小可能很誘人。

然而,花一些時間調整大小,直到你對各種情況下發生的事情感到滿意,最終會回報你。 您會發現您需要更少的媒體查詢,並且可以依賴佈局方法的固有靈活性。

為了幫助您從自己的探索開始,我嘗試使本文中的示例盡可能簡單,以便您可以對它們進行分叉和試驗。 我在本文中分享的大部分內容都是因為我想知道如果我嘗試不同的東西會發生什麼,即嘗試它並找出它為什麼會這樣工作! 因此,如果您留下的問題多於答案,請發表評論並附上演示鏈接,我將嘗試指出規範中解釋的部分。