作者 | Ahmad, Digital
譯者 | 核子可樂
策劃 | 丁曉昀
每當遇上一款新產品,我首先想到的就是研究研究他們是怎么實現 CSS 的。Meta 新近推出的 Threads 當然也不例外,我快速體驗了這款移動應用,發現它的主要功能就是展示網絡上的公共發帖。
瀏覽過程中我也有了其他深入發現,本文將具體為大家一一介紹。
閑言少敘,咱們馬上開始!
在帖子布局中使用 CSS 網格
Threads 當中的 CSS 網格,可以算是我在生產級應用中見到的最值得一聊的案例。Meta 在這里選擇用 CSS 網格構建帖子布局。
咱們簡單看看:
:root { --barcelona-threadline-column-width: 48px;}.post { display: grid; grid-template-columns: var(--barcelona-threadline-column-width) minmax(0, 1fr); grid-template-rows: 21px 19px max-content max-content;}
復制代碼
有趣發現:第一個網格列被命名為–barcelona。我很好奇他們為什么要選這個名字。
帖子布局由 2 列 x 4 行網格組成。這里沒有主容器,帖中的每個條目封鏡 使用 grid-column 和 grid-row 屬性進行手動放置。
再來看用戶頭像:
.post-avatar { padding-top: 4px; grid-row: 1 / span 2; grid-column: 1;}
復制代碼
頭像位于第一列并跨越前兩行。這里的 padding-top 尤其值得注意。雖然我在生產代碼中沒找到確切用途,但猜測它可能是在微調 UI 對齊。
下圖所示,是經過/未經 padding-top 處理的頭像部分前后對比:
在這里采用 padding-top 的另一個理由,可能是要把頭像下推以對齊第二行的下沿。
在網格行數中使用奇數值
為什么行值選擇的是 21px 和 19px?經過進一步檢查,這似乎也是對 UI 的微調措施。行高之和為 40px,即頭像高度再加上 padding-top(36 像素 4 像素)。
大家可能會好奇,為什么不對這些值做標準化設置?畢竟在系統設計中存在這樣一條“鐵律”:設計師必須始終遵循 UI 元素的預定義規則。
但從 Threads 來看,手動調整具體值也是可接受的。在某些情況下,甚至不妨先把嚴格的指導方針放下。
使用固定的行大小限制
由于行大小是固定的,因此無法為其添加填充。但只要意識到存在這個限制,我們也可以借用邊距來繞過這一約束。
請看以下示例:
由于行大小是固定的,所以添加頂部和底部填充不會影響到帖子標題。
各布局列之間的列距顯得有點凌亂
布局列之間的當前列距為零。相反,圖像大小為 36 x 36 像素,而其容器寬度則為 48 像素。
這就用模擬的方式呈現出了列距的效果。我不知道開發團隊為什么不直接設置列距,我個人是比較傾向這種作法。
為什么不用命名 CSS 網格區域?
根據我迄今為止觀察到的情況,網格布局當中存在三種變體,而且使用命名網格區域后這三種變體都能獲得效果提升。
我試著復制了這套網格并根據命名區域進行了構建,新的結果比直接為列和行指定值更加順暢易讀。
為了演示差別,我們先為布局中的各個條目分配一個 grid-area:
.AvatarContainer { grid-area: avatar;}.HeaderContainer { grid-area: header;}.BodyContainer { grid-area: body;}.ThreadlineContainer { grid-area: line;}.FooterContainer { grid-area: footer;}
復制代碼
變體 1:使用默認值
之后,我們再來研究變體。以下為默認布局的效果:
.post { display: grid; grid-template-columns: var(--barcelona-threadline-column-width) minmax(0, 1fr); grid-template-rows: 21px 19px max-content max-content; grid-template-areas: "avatar header" "avatar body" ". body" ". footer";}
復制代碼
請注意,這里使用 . 來表示空白區域。
變體 2:回復
這個變體代表某人回復另一用戶時的情況。
.post--reply { grid-template-rows: 36px 0 max-content max-content; grid-template-areas: "avatar header" "body body" "body body" "footer footer";}
復制代碼
變體 3:默認值加 Thread Line
.post--withLine { grid-template-areas: "avatar header" "avatar body" "line body" "footer footer";}
復制代碼
在這里使用命名網格區域,即可通過編輯一處來變更整個布局。
Thread Lines 中的 SVG
老實說,Threads 應用中最先引起我注意的就是這條螺旋線。從幾周前第一次看到以來,我一直想搞清楚它是怎么實現的。
先來看以下截屏:
Threads Line 這條螺旋線把我的頭像和 Zuck 的頭像連接了起來,而這其實是條 SVG 路徑,具體由三部分組成。
第一部分的長度用 JavaScript 代碼計算得出。
CSS 網格的內聯 CSS 變量
這是個令人振奮的發現:我和其他很多從業者所提倡的設計,終于開始在 Threads 這類大型應用中得到體現。
在用戶個人資料部分,選項卡的網格布局是由包含選項卡計數的內聯 CSS 變量構建而成。
這種設計非常精妙。隨著選項卡數量的增加,我們只需要調整 CSS 變量的值即可。多么簡潔、多么方便!
Overflow Wrapping
我注意到,Threads 在帖子本體中用到了 overflow-wrap: anywhere。有一說一,我之前從來沒用過、甚至沒聽說過這個關鍵字,我一直用的都是 break-word。
根據 MDN 的介紹,它跟 break-word 的作用相同,只有一點區別:在計算最小內容的實際大小時,它會考慮由單詞截斷造成的軟換行情況。
我還是沒發現 break-word 跟 anywhere 到底有什么區別。如果有 Threads 團隊的同學正好看到這篇文章,還望不吝賜教。
使用動態視口單元
我很喜歡用動態視口單元 dvh 作為啟動畫面。
感興趣的朋友也可以參考我之前寫的關于新視口單元的文章:
https://ishadeed.com/article/new-viewport-units/
幾項防御式 CSS 策略
為了確保 Flexbox 的布局不會因最小內容長度而中斷,可以使用 min-width: 0 來重置該行為。
我在討論 Flexbox 中最小內容大小的防御式 CSS 文章中,具體介紹了相關問題。
https://defensivecss.dev/tip/flexbox-min-content-size/
總結
文章就是這些。我很喜歡研究 CSS,以此為切入點思考 Threads 團隊是如何設計和構建這款產品的。相信還有很多細節逃過了我的雙眼,畢竟目前能接觸到的只是 Web 上的預覽版本。隨著后續研究的深入,我也期待給大家帶來更多有趣的發現。
原文鏈接:
https://ishadeed.com/article/threads-app-css/
版權聲明:本文內容由互聯網用戶自發貢獻,該文觀點僅代表作者本人。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如發現本站有涉嫌抄襲侵權/違法違規的內容, 請發送郵件至 舉報,一經查實,本站將立刻刪除。