【AICon】AI 基础设施、LLM运维、大模型训练与推理,一场会议,全方位涵盖! >>> 了解详情
写点什么

Threads 横空出世,通过解析 App,我发现了这些 CSS 小秘密

作者 | Ahmad, Digital

  • 2023-08-11
    北京
  • 本文字数:2563 字

    阅读完需:约 8 分钟

Threads 横空出世,通过解析App,我发现了这些CSS小秘密

每当遇上一款新产品,我首先想到的就是研究研究他们是怎么实现 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/

 

相关阅读:


5 天内用户数破亿、增速碾压 ChatGPT,Twitter 劲敌 Threads 是如何构建的?

nodejs 中使用 worker_threads 来创建新的线程

48 小时注册用户达 7000 万,马斯克:Threads 是 Twitter 前员工做出来的!

我眼中的 CSS 革命:新特性潜力无限

2023-08-11 16:534225

评论

发布
暂无评论
发现更多内容

为什么说企业需要具备企业知识管理的能力?

Baklib

http请求redirect的问题

飞翔

golang

【Docker 那些事儿】关于容器底层技术的奥秘

Albert Edison

7月月更

LP单双币质押流动性挖矿系统开发

开发微hkkf5566

Windows下Tomcat内存占用过高问题跟踪(jmap 的使用)

源字节1号

软件开发 小程序开发

太奇葩了!Keepalived突发高可用事故

Java全栈架构师

Java 程序员 面试 程序人生 Keepalived

对象的内存分配一定都是在堆空间吗?

领创集团Advance Intelligence Group

代码优化 内存分配

系统首页 DIY,你的个性化需求 Pro 系统来满足!

CRMEB

一道2016年nice的笔试题引发的思考

芒果酱

7月月更

Ceph集群详细部署配置图文讲解(二)

Lansonli

云原生 私有云 Ceph 云存储 7月月更

leetcode 135. Candy 分发糖果(困难)

okokabcd

LeetCode 贪心算法 算法与数据结构

开源仓库贡献 —— 提交 PR

攻城狮杰森

git GitHub PR 开源贡献 7月月更

亚信科技发布“电信级”核心交易数据库AntDB7.0,助力政企“信”创未来!

亚信AntDB数据库

AntDB 国产数据库 产品发布会

nacos注册中心之客户端服务注册

急需上岸的小谢

7月月更

数据分析引擎百花齐放,为什么要大力投入ClickHouse?

字节跳动数据平台

无声的AI:昇腾AI如何用大模型破解手语学习的难题?

脑极体

【C语言】进阶指针six

謓泽

7月月更

《看完就懂系列》答应我,看完就开始用Symbol好吗?

南极一块修炼千年的大冰块

7月月更

跟着官方文档学 Python 之:函数

甜甜的白桃

Python 递归 函数 参数 7月月更

Ceph Swift Api 配置与使用(三)

Lansonli

云原生 Ceph 云存储 7月月更

大数据培训Hive的数据存储与压缩

@零度

hive 大数据开发

【都 Java17 了,还不了解 Java 8 ? 】一文带你深入了解 Java 8 新特性

猫的树

java8

【Java 基础你一定要掌握的知识点】Java异常处理和设计

猫的树

Java 异常处理

【Java 实战】实现大转盘抽奖

猫的树

Java 大转盘抽奖

web前端培训nodejs异步IO

@零度

node.js 前端开发

全国首创!洞见科技联合山东数据制定的「数据产品登记」两项标准正式发布

洞见科技

数据 联邦学习 隐私计算

NFT数字藏品交易平台APP开发搭建

开发微hkkf5566

答应我忘掉Postman吧,Apifox才是yyds!

程序员小毕

Java 程序员 程序人生 后端 开发工具

Github发布6天,Star55K+,这套笔记足够你拿下90%的Java面试

冉然学Java

java面试 #Github

Go 原生插件使用问题全解析

SOFAStack

Go 语言 开源软件 MOSN 问题解析 开源学习

龙蜥下游发行版 Alinux 和 UOS 成为 OpenSCAP 官方首批支持的国内 OS

OpenAnolis小助手

国产 龙蜥操作系统 UOS v20 OpenSCAP Alinux 2/3

Threads 横空出世,通过解析App,我发现了这些CSS小秘密_大前端_InfoQ精选文章