使用生成的內容和 CSS 網格佈局為空單元格設置樣式

已發表: 2022-03-10
快速總結↬有沒有想過如何在不添加多餘的空元素的情況下實現空網格單元格的樣式? 好吧,CSS 生成的內容可以幫助您做到這一點。

一個常見的 Grid Layout 問題是佈局方法的新手想知道如何設置不包含任何內容的網格單元格的樣式。 在當前的 1 級規範中,這是不可能的,因為無法定位空的網格單元或網格區域並應用樣式。 這意味著要應用樣式,您需要插入一個元素。

在本文中,我將了解如何使用 CSS 生成的內容來實現空單元格的樣式,而不添加多餘的空元素,並展示一些使用這種技術的用例。

仔細看看 BFC

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

為什麼我們不能為空白區域設計樣式?

網格規範的開頭段落說,

“這個 CSS 模塊定義了一個基於網格的二維佈局系統,針對用戶界面設計進行了優化。 在網格佈局模型中,網格容器的子項可以定位到預定義的靈活或固定大小佈局網格中的任意槽中。”

這裡的關鍵詞是“網格容器的子級”。 該規範定義了在父元素上創建網格,子項可以定位到其中。 它沒有定義該網格的任何樣式,甚至沒有實現像我們在多列佈局中擁有的column-rule屬性之類的東西。 我們為子項設置樣式,而不是網格本身,這使我們需要有某種元素來應用該樣式。

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

使用冗餘元素作為樣式掛鉤

插入樣式的一種方法是在文檔中插入冗餘元素,例如 span 或 div。 開發人員往往不喜歡這個想法,儘管他們多年來一直在添加額外的冗餘“行包裝器”以使用浮動實現網格佈局。 也許那個明顯的空元素比包裝元素的隱藏冗餘更令人反感!

完全空的元素成為網格項,並且可以像包含內容的元素一樣添加背景和邊框,如本示例所示。

請參閱 Rachel Andrew (@rachelandrew) 在 CodePen 上的 Pen Empty 元素成為 Grid Items。

請參閱 Rachel Andrew (@rachelandrew) 在 CodePen 上的 Pen Empty 元素成為 Grid Items。

Eric Meyer 在他的 A List Apart 文章 Faux Grid Tracks 中主張使用b元素作為您選擇的冗餘元素,因為它不賦予任何語義含義,並且在標記中作為鉤子很短而且相當明顯。

插入額外的幾個divb元素不太可能是對你曾經犯過的良好標記的最大犯罪,所以如果需要,我不會因為選擇這種方法而失眠。 Web 開發經常涉及選擇最不次優的方法來完成工作,直到設計出更好的解決方案。 但是,如果可能的話,我更喜歡將我的樣式保存在一個地方,安全地保存在樣式表中。 如果不出意外,它可以更輕鬆地重用樣式,而無需擔心額外的必需標記。 正是出於這個原因,我傾向於查看生成的內容,這是我在使用 CSS 格式化書籍所做的工作中非常熟悉的內容,您大部分時間都在使用此功能。

使用生成的內容作為樣式掛鉤

CSS Generated Content 使用::before::after CSS 偽類以及content屬性將某種內容插入到文檔中。 插入內容的想法可能會讓您認為這是用於插入文本,雖然這是可能的,但出於我們的目的,我們有興趣插入一個空元素作為我們網格容器的直接子元素。 插入元素後,我們可以對其進行樣式設置。

在下面的示例中,我有一個包含元素,它將成為我的網格容器,其中嵌套了另一個元素。 這個單一的直接孩子將成為一個網格項目。 我在容器上定義了一個三列三行網格,然後使用網格線定位單個項目,因此它位於中間的網格單元中。

 <div class="grid"> <div class="item"></div> </div>
 .grid { display: grid; grid-template-columns: 100px 100px 100px; grid-template-rows: 100px 100px 100px; grid-gap: 10px; } .grid > * { border: 2px solid rgb(137,153,175); } .item { grid-column: 2; grid-row: 2; }

如果我們看一下這個例子,使用 Firefox Grid Inspector 覆蓋網格線,我們可以看到網格的其他空單元格是如何存在的,但是,要為它們添加背景或邊框,我們需要添加額外的子元素元素。 這正是生成的內容所支持的。

網格中心單元格中的單個項目
單個網格項目,使用 Firefox Grid Inspector 突出顯示軌道

在我的 CSS 中,我添加了一個空字符串::before::after我的網格容器。 這些將立即成為網格項目並拉伸以填充其容器。 然後我添加我需要的框樣式,在本例中添加背景顏色,並像放置任何常規網格項一樣定位它們。

 .grid::before { content: ""; background-color: rgb(214,232,182); grid-column: 3; grid-row: 1; } .grid::after { content: ""; background-color: rgb(214,232,182); grid-column: 1; grid-row: 3; } 
網格中心單元格中的單個項目,角落中有兩個綠色項目
單個網格項,以及生成內容的兩個項

在文檔中,我們仍然只有一個子元素,多餘的樣式元素包含在 CSS 中,這似乎完全合理,因為它們僅用於樣式目的。

生成內容方法的局限性

如果您決定同時設置右上角和左下角網格單元格的樣式,則這種方法的明顯問題將變得明顯。 您只能將生成的內容應用到容器的頂部和容器的底部,並且不允許使用多個::before::after偽元素。 如果你想自己創建一個 CSS Grid 棋盤格,那麼這個方法是行不通的! 如果你發現你確實需要做很多空單元格樣式,那麼在可預見的未來,上面解釋的“填充 B”方法可能是你最好的選擇。

生成的內容方法也可能使未來從事您項目的開發人員感到困惑。 當我們以容器為目標時,如果您在其他地方重用該類,它將帶來生成的內容,如果這是您想要的,這將很有用。 在下一個示例中,我們在標題的任一側添加了裝飾線, h1的每個實例都有這些線條是合理的。 但是,如果您不知道會發生這種情況,那將是非常令人困惑的! 容器規則上方的註釋行將在這裡有所幫助。 這些天我傾向於在模式庫中工作,這確實有助於將這些組件整齊地放在一個地方,從而更清楚地將類應用於元素時會發生什麼。

花式標題

我最喜歡的生成內容技巧之一是設置標題樣式。 過去,我不得不放棄需要額外包裝器和絕對定位軌道才能實現的標題樣式。 當內容來自 CMS 時,通常不可能添加那些多餘的包裝器。

使用 Grid 和生成的內容,我們可以在標題的任一側添加一行,而無需添加任何額外的標記。 該行將根據可用空間擴大和縮小,當 Grid 在瀏覽器中不可用時,它將優雅地退回到一個普通的居中標題。

兩邊都有行的標題,後跟文本
我們想要實現的標題樣式

我們的標記是一個簡單的h1

 <h1>My heading</h1>

h1的規則中,我創建了一個三列網格。 grid-template-columns的值給出1fr的軌道,然後是auto和最終軌道1fr 。 兩個1fr軌道將在航向佔用了它需要位於auto尺寸軌道內的空間後共享剩餘的可用空間。

我添加了值為centertext-align屬性,以便在沒有網格的瀏覽器中輸入我的標題。

 h1 { text-align: center; display: grid; grid-template-columns: 1fr auto 1fr; grid-gap: 20px; }

我們現在添加我們生成的內容,在標題文本之前和之後添加一行。 我將這些規則包裝在一個特徵查詢中,所以我們不會在沒有網格佈局的瀏覽器中得到任何奇怪的生成內容。

線本身是生成項目的邊框。

 @supports (display: grid) { h1:before, h1:after { content: ""; align-self: center; border-top: 1px solid #999; } }

這就是你需要做的! 您可以使用相同的技術在元素的上方或下方添加任何樣式,甚至添加圖標。 通過將您的項目放置到單獨的軌道中,您知道該項目最終不可能與您的標題文本重疊,這在嘗試使用絕對定位執行此類事情時往往是問題。 您還可以從網格中的項目相互對齊的精確方式中受益。

請參閱 Rachel Andrew (@rachelandrew) 在 CodePen 上的 Pen Generated Content 標題示例。

請參閱 Rachel Andrew (@rachelandrew) 在 CodePen 上的 Pen Generated Content 標題示例。

這是一個很好的例子,可以使用網格佈局進行增強,即使您還沒有準備好直接使用網格進行重大重新設計,您也可以利用它。 它很好地回到了一個簡單的標題,支持瀏覽器的人得到了額外的接觸,每個人都得到了內容。 Eric Meyer 採用了類似的方法,使用生成的內容向塊引用元素添加易於設置樣式和定位的引號。

有了這些小功能,我通常不會一開始就想到要使用網格佈局。 當我開始弄清楚如何實現我的設計時,我意識到這是選擇的佈局方法。 正是出於這個原因,我鼓勵人們不要將 Grid 視為用於組件之上的頁面佈局,如果您這樣做,您可能會錯過很多它可以提供幫助的機會。

為您的設計區域添加背景和邊框

我們還可以使用生成的內容來堆疊物品; 事實上,多個項目可以佔據一個特定的網格單元。 這可以包括與生成的內容一起插入的那些項目。

在下一個示例中,我有一個包含兩個內容部分和一個全角項目的設計。 內容後面是一個背景,它也在全角項目下方。

單列佈局,全寬圖像
我們瞄準的佈局

標記有一個容器,其中部分和全角元素作為直接子元素,我使用基於行的放置將我的項目放置到網格上。

 <article class="grid"> <section class="section1"> <p>…</p> </section> <div class="full-width"> <img src=“placeholder.jpg” alt=“Placeholder”> </div> <section class="section2"> <p>…</p> </section> </article>
 .grid { display: grid; grid-template-columns: 1fr 20px 4fr 20px 1fr; grid-template-rows: auto 300px auto; grid-row-gap: 1em; } .section1 { grid-column: 3; grid-row: 1; } .section2 { grid-column: 3; grid-row: 3; } .full-width { grid-column: 1 / -1; grid-row: 2; background-color: rgba(214,232,182,.5); padding: 20px 0; }

這為我提供了全角圖像和放置兩個內容部分的佈局; 但是,如果我將背景添加到部分,它將停止在section和全寬圖像之間的row-gap上方。

 .section { background-color: rgba(214,232,182,.3); border: 5px solid rgb(214,232,182); } 
單列佈局,全寬圖像,內容區域後面的背景顏色
背景現在位於內容區域的後面

如果我們移除grid-row-gap並使用 padding 來製造空間,它仍然不會啟用在全寬麵板下方運行的背景效果。

這是我們可以使用生成內容的地方。 我在網格容器::before並給它一個背景顏色。 如果我什麼都不做,這會將內容定位在網格的第一個單元格中。

 .grid::before { content: ""; background-color: rgba(214,232,182,.3); border: 5px solid rgb(214,232,182); } 
佈局左上角的一個正方形
生成的內容進入網格的第一個空單元格

然後,我可以使用基於行的定位來定位內容,以覆蓋應顯示背景顏色的區域。

 .grid::before { content: ""; background-color: rgba(214,232,182,.3); border: 5px solid rgb(214,232,182); grid-column: 2 / 5; grid-row: 1 / 4; }

您可以在此 CodePen 中查看完整示例。

請參閱 Rachel Andrew (@rachelandrew) 在 CodePen 上的 Pen Generated Content 背景示例。

請參閱 Rachel Andrew (@rachelandrew) 在 CodePen 上的 Pen Generated Content 背景示例。

使用z-index控制堆棧

在上面的示例中,生成的內容使用::before插入。 這意味著其他元素在它之後,它位於堆棧的底部,因此將顯示在我想要的其餘內容的後面。 您還可以使用z-index來控制堆棧。 嘗試將::before選擇器更改為::after 。 生成的內容背景現在位於所有內容之上,正如您可以從邊框在圖像上運行的方式看到的那樣。 這是因為它現在已成為網格容器中的最後一個東西,它是最後繪製的,因此出現在“頂部”。

要改變這一點,你需要給這個元素一個比其他元素更低的z-index屬性。 如果沒有其他東西具有z-index值,那麼最簡單的做法是為生成的內容提供-1z-index 。 這將使它成為堆棧中的第一件事,作為具有最低z-index的項目。

 .grid::after { z-index: -1; content: ""; background-color: rgba(214,232,182,.3); border: 5px solid rgb(214,232,182); grid-column: 2 / 5; grid-row: 1 / 4; }

以這種方式添加背景不必局限於將背景完全放在內容後面。 能夠在設計的一部分後面彈出色塊可以產生一些有趣的效果。

這是規範將來可能解決的問題嗎?

添加背景和邊框確實感覺像是 CSS Grid 規範中缺少的一個特性,工作組已經與社區的許多成員一起討論過這個特性(討論線程在 GitHub 上)。

如果您的用例無法通過生成的內容輕鬆解決,請將您的想法添加到該線程中。 您的評論和用例有助於證明開發人員對該功能感興趣,並確保任何提案都涵蓋了您需要做的事情。

請提供更多示例!

如果本文鼓勵您嘗試生成的內容,或者如果您已經有示例,請將其添加到評論中。 每個人都是在生產中使用 Grid 的新手,所以有很多,“我從沒想過! ” 當我們將 Grid 與其他佈局方法相結合時,我們將有機會擁有。