阅读视图

发现新文章,点击刷新页面。

热力图

文章更新热力图

类似的热力图,我最早是在 GitHub 看到的,用来展示开发者的更新频率。现在看到不少博客也做了这种小组件:就是从当前日期向前追溯一年,每一天显示成一个灰色的小方块,如果当天有文章发布,就显示成浅绿色,如果当天发布的文章不止一篇,就显示成深绿色。我想了一下,用 Hugo 的模版系统,加上一点 CSS 做布局和显示优化,应该就能实现,动手试了一下,果然效果还算可以。目前可以在首页看到实际演示。

fin.

有天赋?

当年今日

有时候我也搞不懂自己是不是真的有编程的天赋,还是说不知道为什么我对这方面会特别感兴趣。之所以这样,我觉得一定程度上跟我过往的经历有关。我不讨厌数学,但因为自己的计算能力有问题,经常会因为这样那样的原因出错,所以越往上学,我的成绩就越会出现提不上去。知道那个思路,但是却算不出那个答案。这种情况在某些只需要答案不需要过程的考试里面就很吃亏。即便需要计算过程,但如果我在第一个部分就算错了,后面也就没有什么意义了,因为根本算不下去。

编程好像一定程度上弥补了我的计算失误。因为计算结果是由机器完成的,而我只需要提供思路。在简单的问题上,那种百发百中的感觉真好。不过当问题遇到的越来越多,思路不是一下子就能畅通,我需要碰过很多壁以后才能出结果我会觉得刺激。在考虑很多因素的时候,总是有这样那样的不到位。有些步骤可以做在前面,也可以坐在后面,但是哪个会更优呢?最终都能得到同样的结果,那个时候我就得用机器的方式去考虑,怎么样才能最大程度节省资源,提高运算速度。

如果说写脚本的话,高中的时候我已经在干,那个时候是写网站,现在写CSS,然后是 HTML,再到后来当我接触WordPress以后是PHP。一开始用的CSS 那个时候就完全只是控制网站的部分格式而已。CSS可以控制很多东西,但是核心的部件是没办法修改的,有些控制封装在核心部件里,于是自定义CSS无法到达,那个时候我感觉到有一点点的无力。相对而言,WordPress控制方面可以说只有你想不到没有做不到。哪怕有些部分可能CSS真的无能,但实际上当你得知那个控制手段以后,你还可以配合其它的脚本实现某些格式的自定义。

最终让我觉得自己的编程技术总算是用到了点子上是近几年Python,Power Qurey和Power Pivot以及VBA的使用。这几个东西是从Excel的数据处理开始的。我基础的东西都齐全了,但是我怎么才能快捷获取某个成品的结果呢?我知道那个事情该怎么干。但是天天都干,又或者是在很短的时间内要我干那个事情,首先是觉得很烦,其次是非常容易出错,于是这让我想到为什么我不能用编程的手段把它们高度的结合起来。要用什么编程语言?其实一直我都在摸索。用过了一段时间,大家都尝试过了以后,我觉得大部分情况下,无论哪个语言,都能获得类似的结果,但复杂程度不一样,在不同设备上的运行速度不一样,需要的设备基础也不一样。我要用什么编程实现那个结果,我就得考虑这些东西。我是不是经常要用,是不是我一个人用,是不是我还得给别人用。最终我觉得稳定性首先必须保证,最终那个结果也是,必须得以某个我要求的方式输出的,第三点就是看看我的第一感觉是哪个编程软件。

可能某一天,某些软件用不了了,我只能用其它方法去替代,虽然这很麻烦,但是我也相信,我有能力可以做出替代,但我希望不需要有那么一天。

新标签页助你重新掌控你的收藏夹

在数字时代,我们的浏览器收藏夹,就如同一个宝库,里面藏着我们曾经因兴趣、工作或学习而保留的无数网站链接。小舒同学,一个浏览器新标签页扩展,帮助您高效地管理这些珍贵的在线资源。通过整洁、直观的界面和强大的功能,通过小舒同学这款强大的浏览器扩展,让您的收藏夹焕发新生。

一键展示管理收藏夹

不需要反复整理和搜索您的主页,小舒同学提供了一种轻松的方法来展示和管理您的收藏夹。通过在新标签页中,将书签以清晰的图形方式呈现,帮助您聚焦真正重要的事情。无论是微软的 Edge、Google 的 Chrome,还是 Mozilla 的 Firefox,都可以实现一步直观整洁地展示管理您的网络财富。

一键展示管理收藏夹

随时随地的同步空间

小舒同学的同步空间可以让您轻松同步收藏夹,通过同步空间功能,不管您是在工作场合的电脑还是在家里的设备,都可以轻松连接,访问您全部的收藏内容。您的内容将被安全地存储与同步,确保您可以在任何时间访问。网络世界的一切都将由您连接统一,不仅能启动哔哩哔哩,更能直接访问您关注的具体内容。

同步空间

网页端

直观且舒适的重组织

小舒同学以流畅和直观的用户体验,帮您重新组织您的在线生活。我们专注于舒适的交互设计,将您的收藏夹以一种对您有意义的方式进行组织。

小舒同学提供各式各样的卡片形式和布局,让您可以完全按照自己的喜好进行自定义。您可以创建个性化的卡片组合,以满足您的独特需求。

重组织

严格隐私保护

小舒同学重视用户的隐私保护,拒绝记录和上传用户数据。在不使用同步空间的情况下,您的收藏夹数据也只在浏览器本地数据中,确保隐私数据的私密性。依托于 Manifest V3,小舒同学严格控制所需权限,保证只加载本地代码,保护用户的安全与私密。

定制个性化新标签页

小舒同学的自由度极高,可以按照用户的喜好进行多种个性化设置。您可以更换壁纸、主题、主题色,甚至可以用自定义 CSS 美化您的标签页。拥有如此高度自定义的新标签页,您的浏览器将成为真正属于您的个性空间。

主题 Fluid

主题 Meteor

主题 Hyper

小舒同学不仅仅是一个简单的收藏夹工具,它改变了我们与网络信息的互动方式,提供了一个更高效、更有组织性的网络生活体验。减少了无谓的折腾,让每一次收藏都变得值得,让每一次浏览都充满发现的喜悦。现在,尝试小舒同学,让您的收藏夹变成您的独特网络资产,发挥它们真正的潜力吧。

用 Blender 制作一个可循环沙漠公路绿幕

偶然间看到有人发了个《奔跑的阿塔尼斯.GB》,我瞬间联想到的竟是《GO BROLY GO GO》这个梗。

那为什么不干脆自己做一个呢?

然后就遇到了一大堆大坑。其中的一个大坑就是这个奔跑用的绿幕背景该怎么搞。本文就围绕这个大坑随便嘚吧几千字。

(注1:本文非教程)

(注2:本文本该引用的图片,因为我懒而直接截图贴到 Discord 了,所以本地没有保存,我也懒得去 Discord 往回抠,直接文字描述了。对付看吧)


素材与原梗

《奔跑的阿塔尼斯.GB》

《GO BROLY GO GO》


首次尝试

在网上随便搞了一个绿幕背景,然后就做了一下。

[StarCraft] Go Go 大主教 Go Go !!!「旧版」

非常的不满意。

主要是这个绿幕背景不能循环,背景高度在开头和结尾不一致,所以每次到循环的位置时都咯噔一下子,看起来就非常的粗糙。

当然在现在这种大多数都是垃圾视频的大环境下,每天都产生大量漏洞百出的垃圾视频,平台和用户已经亢奋到巴不得直接脑子上插根安卓充电线接手机上在人脑内播放垃圾视频了,没人会在乎这种小细节,甚至都没人看我做的这种视频。


重新搜寻绿幕素材

在网上随便搜索了一下,发现几乎没有我需要的 「可循环」 的绿幕素材。

screenshot_on_b85m_by_flameshot_at_2024-02-16_22-32-40

大多数都是随便一个奇怪的片段,长度都很短,而且全部都是头尾不相同的,简单点的咯噔一下,复杂点的干脆连方向都变了,完全不知道这种限制性极强的素材在什么地方能用得到。

总之在网上找这种可循环绿幕素材这个途径行不通。


尝试自己做

算是要做个3D动画。掏出 Blender。

「路」,好解决,画个面,然后找个路的纹理贴上去就行,然后根据纹理做个首尾相接,循环就搞定了。

难点在路边,我想整个沙漠,那单纯的平面纹理就不够了。

在网上搜了一下关于 Blender 沙漠 的教程。

screenshot_on_b85m_by_flameshot_at_2024-02-16_22-32-51

screenshot_on_b85m_by_flameshot_at_2024-02-16_22-32-56

第一个,测试渲染完了,细节很好,但是主要用法是展示大沙漠里微观场景的,就和其缩略图一样。在大场景下做大背景效果很好,但是缩放小了之后发现作为沙地的效果却很差。只能说纯当练手了。

第二个,测试渲染完了,作为沙地的效果很好,但是沙地的效果是完全随机生成的,边缘不连续,接不上,没法做循环。

很明显遇到了非科班出身的人常遇到的困难。


寻求帮助

找熟人

我目前能联系的人当中,目前没有任何一个人是会使用 Blender 的。

可以说是真正意义上的 人脉匮乏,找不到 关系

中文社区

至于所谓的中文社区,QQ群,那都是吹逼饭的窝点。当年我3DS变砖时寻求帮助,顺着3ds.hack的路先加了中文区的QQ群,结果和想象中的一样,中文社区无非就是 吹牛逼 晒有钱 互相诋毁,一点帮助没获取到,还浪费了我不少时间。最后是把 3ds.hack 改成英文模式然后进了 Nintendo Homebrew 的 Discord 频道,我提出问题之后立刻就有人一步一步手把手帮忙解决问题,而且解决途中还发现我遇到的并不是很寻常的基础问题(不然怎么能卡住我)。

screenshot_on_b85m_by_flameshot_at_2024-02-16_23-41-58

screenshot_on_b85m_by_flameshot_at_2024-02-16_23-42-59

从提出问题到得到响应,用时1分钟。从提出问题到完全解决,用时43分钟。此时中文QQ群还一个屁都没崩出来。

本身被自己不懂的有一点难度的问题卡住就很难受了,网上却又存在着各种能力远比你低下的人在那不懂装懂,很可能导致你离解决方案反而越来越远。你看像 segmentfault.com 现在都是乌烟瘴气,都臭成什么样子了。

(光是当时3DS变砖后的解决办法,我当时没写博文出来,我都觉得奇怪)

总之,在中文区甭想找到什么求助。

英文社区

也不知道算是走运,还是巧合。

我的 Discord 频道列表里刚好有一个 TF2 相关的 Blender 社群。

screenshot_on_b85m_by_flameshot_at_2024-02-16_23-51-17

我还真就想不起来是为啥加了这个社群了,可能是因为看了 Pootis Engage ?

然而事情并没有像解决 3DS 变砖那样顺利。

我提出问题之后,首先跳出来的一帮人问我「为什么要做这个东西?」

哈?

然后我解释了一遍我需要做一个「可循环的沙漠公路绿幕」:其核心思想是,渲染一段以plane为底面的沙漠;沙漠上面有一个公路样式的几何图形,最好是 Cube 这种有高度的,看起来像是沙子上的路;视频结尾帧与视频开头帧相同,这样我可以无限循环这个视频,其最简单的办法是镜头最后的图形边界与开头的边界相同(其他方法亦可)。

然后得到了这么几个答案:

  • 随便渲染一下就好了,循环的时候咯噔一下,没人在意。
  • 渲染一个足够长的道路。
  • 你为什么要做绿幕,你直接在 Blender 你做完你的项目不就好了?

基本上,面对一个 目标极为明确的问题时 ,得到的答案是 不要做?

什么玩意……


继续摸索

阶段1

总之得到的帮助极为有限,多数人都是喷子状态。因为我的电脑配置是 i7-4790K + GTX1080 ,10年前的配置。虽然这个配置称霸了非常多的年份(10系显卡GTX1060霸榜一直到去年年末为止),但是放在 Blender 这种纯正的生产力场景下是很虚的。所以又冒出来一堆开喷硬件配置的,直到有人发现我在 Linux 环境下没有正确启用 Cycles 的硬件加速。

作为个生产力工具,整个社区竟然没几个人用 Linux 这一点也是够搞笑的。不过有了这个场景,我立刻就能分辨出哪些才是真正的有能力的 Blender 用户了。

搞了一宿,最后还是没搞定如何 循环 沙漠纹理。

这个时候终于有人提出新的方案了:不要用随机去渲染沙漠纹理,用内置的 海洋 去渲染。

我试了一下,海洋的渲染是基于一个固定模式的,所以其首尾的形状可以首尾相接。然后用颜色噪音把海洋渲染成土黄色。仔细一想其实海洋和沙漠是一回事,还挺有道理的。

然后这个是阶段成果。

[Blender] 在电脑前坐了一天,干到后半夜3点,就整出来2秒钟这玩意

问题出来了,因为我的目标是公路 正向/反向 的效果,所以「地平线」需要是垂直的,这就要求这个海洋要 足够宽 ,那么这个海洋的纹理就会被拉伸得,没啥效果,看着更像是 泥水 了。

此时已经是后半夜三点了。

然后我决定睡觉!

然后刚准备躺下的时候,脑子里冒出来了一个极其有意思的主意!导致我一晚上没睡好觉!

阶段2

首先,「海洋」的办法不是不行,就是实现起来可能要调教很久,效果也很一般,尤其是为了水平线而拉宽之后,效果肉眼可见的差劲。

毕竟我基础就已经很差了,就算形状搞定了,到纹理的大坑也得摔倒。

screenshot_vlcsnap-2024-01-30-19h05m30s064

screenshot_vlcsnap-2024-01-30-19h05m36s007

但是之前的方法我又搞不定边界连接的问题,无法做到循环。

然后我就想到了,或许改变一下前提。

我目前遇到的问题是,沙漠plane的边缘接不上。那假如,代表沙漠的图形没有边缘呢?

screenshot_on_b85m_by_flameshot_at_2024-02-17_01-10-41

Ta-Da!圆柱!

没错,这个就是兴奋得让我一宿没睡好觉的点子。

放弃平面的设计,做两个圆直径超大的圆柱体,一个代表沙漠,沿用旧的渲染方式;一个代表公路,嵌在沙漠里,只要位置恰当,看起来就像公路一样。

这方法甚至都不需要再移动镜头,只要让俩圆柱体旋转起来就行。

[Blender] 用了新的思路,编辑2小时,渲染1小时。

当然,缺点也是有的。圆柱体的直径必须足够大,不然看起来的确不像是平面,而是圆柱,露馅了。直径太大就导致周长特别大,那么转一圈的时长就特别长,渲染压力立刻就上来了。而且圆柱终究是圆柱,边缘怎么看都会觉得并不是地平面,而周长太大,大过头了 循环 的实用性就没了。

不过目前也就只能这样了。

阶段3

第一个大坑算是过了。

然后是给公路贴纹理。

这 TMD 作为一个 Blender 用户,应该是最简单的一个功能。

我TM不会啊!

screenshot_on_b85m_by_flameshot_at_2024-02-17_01-25-20

screenshot_on_b85m_by_flameshot_at_2024-02-17_01-25-37

我其实是要给一个圆柱的侧面贴纹理,而且还是要重复贴相同的纹理。我哪会这个! 你让我写个 CSS 还差不多!

screenshot_on_b85m_by_flameshot_at_2023-12-29_00-34-18

screenshot_on_b85m_by_flameshot_at_2023-12-29_00-49-32

总之这一块也卡了好久才搞定。

这种最基础的玩意,真的是,最好有个人能手把手教一下,把流程缕清晰了最好。

我这种瞎蒙出来的,完全不知道自己是怎么蒙出来,下次让我做一样的事情,我照旧做不出来,还是得瞎蒙。尤其是我也已经上岁数了,记忆力也差,蒙出来也想不起来过程,非常难受。

阶段4

至此坑就算是填了,把天空改成绿幕,然后速度和其他参数什么的,调整了一下就能出成果了。

然后初次渲染的时候,一遍渲染,一边尝试微调些细节。结果渲染出来的结果一塌糊涂。

我这才意识到 Blender 的渲染不是沙盒模式的,即它渲染的不是我在执行「渲染」瞬间的副本,而是正在编辑的正本。

也就是说 Blender 渲染的时候,最好完全不要动 Blender。切出去干别的,或者最好把电脑放那不要动。

这都2024年了怎么软件行业里还有这种玩意啊!


成果

随便剪了一下,做了两个示例,就发B站了。

[Blender] 可循环沙漠公路绿幕

我甚至懒得发布纯素材。

其实渲染有 Alpha 通道的视频也不是不行,但是指望我这个老电脑渲染 VP8/9 H.265 AV1 实在是太困难了。而且现在所有视频网站依旧以 H.264 为主流。

(其实主要还是我电脑带不动)

这玩意到这个阶段时,我把片段发到之前的 Discord 频道里,然后一堆人(就是之前那堆帮倒忙的)冒出来问我这这那那都是怎么实现的,尤其是对绿幕这块甚至都不知道怎么实现怎么使用。

好家伙, NLE+VFX 最基础的东西都不知道,竟然还试着在那指教我?

然后看到我在用开源的 Shotcut 作为 NLE 时竟然开喷我用不起高贵的 Adobe,这一看就是小孩没参加过工作啊,我在家用不起 Adobe 我大不了去公司用公司电脑上的 Adobe。

(原来国外社区跟国内也没什么两样,都 Toxic


使用例

除了上面那个视频带的 Senator 和 国际靶场 两个示例,我还用这个素材做了另一个视频。

Funky Town ⧸ Eurobeat Remix (Deamoz Eurobeat)

当然最初为了做这个绿幕素材的目的也没忘。

[星际争霸2] Go 大主教 Go Go !!!


结尾

这事就算了结了。

经验基本上是没累积到。我现在这个年龄,好多新知识,摸了不进脑子,除非天天摸。我现在开始担心自己以后会不会糊涂得像家里大人一样,到了岁数后连手机怎么接打电话都不会,但是刷短视频乱花钱比谁都猛。

国内国外社区都这么 Toxic 这事看来我是可以确定了,国外的月亮不比国内圆,但国外的屎一样臭。

The post 用 Blender 制作一个可循环沙漠公路绿幕 first appeared on 石樱灯笼博客.

新致宋字体反锯齿方法二则

文章目录MacOSWindows在前一篇文章的评论中夜未央提出: 对比了下,感觉你默认字体颜色太浅了,看长文可能比较容易注意力不集中,点T后的备用字体则深很多。...

Flexbox 布局实际用例

上篇文章介绍了 flexbox 的属性与示例,本文再通过几个 flex 布局的案例来体会 flex 布局的特性带来的便利和问题~

格式化上下文

当我们给父容器设置 flex 属性后,flex 容器会在容器内创建一个新的 **flex 格式化上下文(formatting context)**。在这上下文中 floatclear 将失去作用,vertical-align 对于 flex 元素也不再会起作用。

在实际开发中,当我们使用行内元素(inlineinline-block) 时,有时候可能会看到元素之间会有一个奇怪的间隙,并且设置的字体越大间隙就越大。原来这个间隙是我们在编写源代码时标签换行导致,不换行就不会出现这种情况。

多数情况下,我们在编写代码时会习惯用编辑器对代码进行格式化,格式化后会使这些标签换行从而导致间隙。这在要求像素级还原的项目中就有点尴尬了。

以前常见的做法是在父元素设置 font-size: 0 消除间隙,再设置子元素的字体大小。这样做确实有点麻烦,因此在 flex 上下文中,这些间隙默认就会被清除。

圣杯布局

通常我们使用 flex 布局更多的是用于整体的布局设计,如:

在互联网早期,由于用户网路的限制,经常会出现 html 的内容显示出来但页面样式还没加载出来的情况,这会导致用户没能最先看到想看的东西。因此 Matthew Levine 在 2006 年提出了圣杯布局的概念,在 HTML 源代码中将用户想看的内容挪到次要内容的前面。

上例 demo 就是使用 flex 布局实现的圣杯布局,虽然在 HTML 源码里 Main 处于其他两块内容之上,但通过 order 属性可以调整元素间的顺序。

除此之外,还可以通过媒体查询(@media)做响应式页面,当屏幕宽度小于 640px 后仅需修改几项 flex 属性就可以改变布局排列的方式,十分灵活。

如果你使用过 react/vue 主流 UI 库的话,你就会发现他们使用布局容器也是 flex 布局实现的,比如 Element UIAnt Design 等。

栅格布局

栅格布局也可以通过 flex 来实现:在以下的 demo 中,HTML 源码内的各元素都是平级,通过调整 flex 属性实现了跨行或跨列的效果。

justify-content 尾列不整齐

让CSS flex布局最后一行列表左对齐的N种方法 –By 张鑫旭

多数情况下使用 justify-content 是要求子元素们散开,但尾列元素不够的时候,散开就显得很奇怪了,为此我们可以做如下处理:

动画

在 MDN Animatable CSS properties 上列出了可以使用 AnimationsTransitions 进行动画处理的属性,其中就有 flex 属性。因此还可以结合动画进行布局设计:

结束

通过以上几个案例是不是对 flex 布局的灵活有了更深的感受呢?以上 demo 大多借鉴已有的思路,如果你有什么好的想法,也可以自己动手尝试一番或分享出来~

参考资料:

Pixiv 背景图例:

  1. ちょけ | アリスミクと白うさぎ
  2. Azit | Miku
  3. ぽむ | もっと高くまで!
  4. 雨陌 | 8.31
  5. akino | つもりつもるキモチ。

Flexbox 布局入门

互联网早期实现布局是需要通过多种不同属性组合才能实现我们想要的布局。

比如常见的垂直居中,刚接触 css 的朋友看到 vertical-align: middle; 这个属性可能就会认为它就是用于垂直居中的,但实际上并没有那么简单。如果想要通过该属性来实现垂直居中,还需要其他小伙伴配合。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
.container {
width: 200px;
height: 200px;
border-radius: 6px;
text-align: center;
color: #fff;
background: #e44b27;
white-space: nowrap;
}

/* 该伪类是实现垂直居中关键 */
.container:after {
content: '';
display: inline-block;
height: 100%;
vertical-align: middle;
}
.content {
display: inline-block;
white-space: normal;
vertical-align: middle;
text-align: left;
}
1
2
3
<div class="container">
<div class="content">我想居中!</div>
</div>

这样看来,为了实现垂直居中布局,我们还得打一套组合拳才能出来才行,是不是看起来有点麻烦的样子?

W3C 在 2009 年提出的 Fiexbox(flex) 布局草案,就是针对用户界面设计优化的 CSS 盒模型。如果使用 flex 布局来实现上面的垂直居中布局的话,可以简化为:

1
2
3
4
5
6
7
8
9
10
11
12
.container {
width: 200px;
height: 200px;
border-radius: 6px;
color: #fff;
background: #e44b27;

/* 使用 flex 布局 */
display: flex;
justify-content: center;
align-items: center;
}
1
2
3
<div class="container">
<div>我想居中!</div>
</div>

修改后的代码就显得更精简了,也不需要其他小伙伴来搭把手。布局的事情就让 flex 家族自己来解决即可。


概念

应用 flex 布局的容器我们通常称为 **弹性盒子/容器(flex container)**。弹性容器可以由 display: flexdisplay: inline-flex 生成。弹性盒子的子项常称为 **弹性元素/项目(flex items)**,它以 flex 布局模型进行布局。

1
2
3
.container {
display: flex | inline-flex;
}

如果想要学习 flex 布局的工作方式,最先需要学习的是它自身的术语。下面直接引用 flex 草案中术语的介绍图:

别被原版英文术语给吓倒了,咱们翻译一下其实就很好理解了:

在术语示意图中可以看到两根轴,分别是**主轴(main axis)垂直交叉轴(cross axis)。同时标注了主轴起点(main start)终点(main end)交叉轴的起点(cross start)终点(cross end)**。

默认情况下 flex 布局是按主轴的方向进行布局的。flex 元素所占据的 主轴空间(main size) 就是 flex 元素的宽度(width)、所占据的 交叉轴空间(cross size) 就是 flex 元素的高度(height)。


flex 容器属性

flex 容器里可以通过以下几种属性来控制容器的行为:

  • flex-direction
  • flex-wrap
  • flex-flow
  • justify-content
  • align-content
  • align-items

为了更好的观察各属性的行为,笔者在 codepen 上给不同属性都写了 demo 做参考。

目前有个新规范(CSS Box Alignment Module Level 3)正处于工作草案的状态中,对一些属性添加新值,如 [first|last]? baselineself-startself-endstartendleftrightunsafe | safe

这些新值多数浏览器都没实现,为了便于演示,此处仅讲解初始版本的值。Firefox 浏览器对新值实现的比较超前,也建议通过使用 Firefox 浏览器来查看 demo。

flex-direction

flex-direction 指示内部元素如何在 flex 容器中布局。可以简单的理解为 flex 容器的布局方向。其默认值为 row,可选语法如下:

1
2
/* 常用属性 */
flex-direction: row | row-reverse | column | column-reverse;
  • row: 主轴起点和主轴终点与内容方向相同。简而言之就是内容从左到右进行布局。
  • row-reverse: 与 row 行为相同,但主轴起点和主轴终点对调了位置。
  • column: 主轴由水平方向转为垂直方向,布局从上往下排。
  • column-reverse: 主轴由水平方向转为垂直方向,布局从上往下排。

值得注意的是,全局属性 dir 的作用是指示元素的文本的方向性,该属性会受到 rowrow-reverse 的影响。

flex-wrap

flex-wrap 指定 flex 元素单行显示还是多行显示 。如果可以换行,你甚至还可以通过该属性控制行的堆叠方向。它的取值如下所示:

1
flex-wrap: nowrap(默认值) | wrap | wrap-reverse;

可以通过本例 demo 右上角的按钮来修改元素的数量,观察三个值之间的变化:

  • nowrap: flex 容器宁愿压榨元素的空间也不肯换行。甚至压缩到一定地步后还会溢出容器。
  • wrap: 若子项超过容器所容纳的宽度,则允许断行展示。
  • wrap-reverse: 和 wrap 的行为一样,只是交叉轴起点与终点互换

flex-flow

flex-flow 属性是 flex-directionflex-wrap 的简写。这个没啥好说的,也就不额外写 demo 了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/* 语法 */
flex-flow: <flex-direction> || <flex-wrap>;

/* 单独设置 flex-direction 的属性 */
flex-flow: row;
flex-flow: column;

/* 单独设置 flex-wrap 的属性 */
flex-flow: nowrap;
flex-flow: wrap;

/* 同时设置两种属性,建议按照语法顺序进行书写 */
flex-flow: row nowrap;
flex-flow: column wrap;

justify-content

justify-content 属性定义了容器主轴中各 flex 元素之间的对齐方式。这是 flex 布局中常用的属性之一。

1
2
3
justify-content: normal |
space-between | space-around | space-evenly |
center | flex-start | flex-end

在初始版本中,justify-content 的默认值为 flex-start。但在最新版本中的 chrome 浏览器被修改为了 normal

为了对比属性之间的差异,本例 demo 将元素的两侧 margin 清空:

  • normal: 排列效果等同 flex-start
  • flex-start: 默认情况是左对齐,从行首开始排列。每行第一个 flex 元素与行首对齐,同时所有后续的 flex 元素与前一个对齐。
  • flex-end: 默认情况下是右对齐,从行尾开始排列。每行最后一个 flex 元素与行尾对齐,其他元素将与后一个对齐。
  • center: 该值使元素居中对齐。
  • space-between: 首尾两端对齐,内部元素之间的间距相等。
  • space-around: 在每行上均匀分配弹性元素。相邻元素间距离相同,首尾两个元素的距离是相邻元素之间距离的一半
  • space-evenly: 主轴内各元素两侧均匀分配剩余空间。(注意此处与 space-around 的差异)

align-items

align-items 属性除了可以在 flex 布局中有效,还可以在 grid(网格) 布局中应用。在 flex 布局中它的作用是决定交叉轴的对齐方式。这也是 flex

1
2
3
4
5
/* 主流浏览器已经实现的值 */
align-items: normal | flex-start | flex-end | center | baseline | stretch

/* 新草案添加的值 */
align-items: | start | end | [ first | last ]baseline | left | right
  • normal: 在 flex 布局中 normal 的表现效果如同 stretch 一样。
  • stretch: 弹性元素被在交叉轴轴方向被拉伸到与容器相同的高度或宽度。若容器没有设置高度,则取当前行中最高元素的高度,如本例中元素 4 是第一行中最高的元素,那第一行中的高度都被拉伸到与最高元素相同的高度。第二行中最高的元素是元素 2,因此第二行高度都取至元素 2。
  • flex-start: 元素向交叉轴起点对齐。
  • flex-end: 元素向交叉轴终点对齐。
  • center: 元素在交叉轴居中。
  • baseline: 所有元素向基线对齐。侧轴起点到元素基线距离最大的元素将会于侧轴起点对齐以确定基线。在例子中放大元素 6 的 font-size, 与 center 进行对比就能看到差异了。

align-content

justify-content 是作用于主轴上,而 align-content 则是用于定义交叉轴的对齐方式。值得注意的是,若 flex 容器内只有一根轴线,该属性将不起作用

1
2
3
4
5
/* 主流浏览器已经实现的值 */
align-content: normal | space-between | space-around | space-evenly | stretch | center | flex-start | flex-end

/* 主流浏览器多数未实现的值 */
align-content: [first|last]? baseline, start, end, left, right

父容器设置了 flex 布局后,若子元素没有设定 height 属性的话,默认会将容器内的子元素进行拉伸。

为了便于观察两者的差异,笔者在 demo 中新增一列进行对比。左列的 flex 元素使用 height 属性,右列使用 min-height 属性。同时将 flex 容器高度设置为 400px:

  • normal: 像未设置值,元素处于默认位置。
  • stretch: 拉伸所有行来填满剩余空间。剩余空间平均的分配给每一行(若某元素设置了高度,那么该值对这个元素将不会起作用)。
  • flex-start: 交叉轴起点对齐。
  • flex-end: 交叉轴终点对齐。
  • center: 交叉轴居中对齐。
  • space-between: 交叉轴两端对齐,行之间间距相等
  • space-around: 交叉轴均匀对齐,行两端间距相等
  • space-evenly: 交叉轴内各元素两侧均匀分配剩余空间。

Flex Item

Flex Container(弹性容器)的一级子元素就是 Flex item(弹性元素)。以下主要应用于 Flex item 的属性。

  • flex-basis
  • flex-grow
  • flex-shrink
  • flex
  • align-self
  • order

flex-grow

flex-grow 属性用于定义元素所占有的比例,它接受一个正整数,默认值为 0

1
2
3
4
flex-grow: <number>

/* 例子: 仅接受正数的值 */
flex-grow: 1;

flex-shrink

flex-grow 相反,flex-shrink 属性处理元素收缩的问题,默认为 1,意味着元素默认会随着容器缩小而等比例缩小。当值为 0 时则不缩放。

1
2
3
4
5
6
7
flex-shrink: <number>

/* 例子: 默认缩放 */
flex-shrink: 1;

/* 例子: 使元素不缩放 */
flex-shrink: 0;

在以下 demo 中,各 flex 项目的宽高相等。当父容器有足够的空间时,元素不需要紧衣缩食,因此 flex-shrink 也没有机会表现出它的作用。

将 flex 容器尺寸调小后可以发现,flex-shrink 的值越大,元素被压榨的空间越多。

flex-basis

flex-basis 指定了 flex 元素在主轴空间(main size)所占的初始大小。

1
flex-basis:  <'width'>

当一个元素同时被设置了 flex-basis (值为 auto 除外)和 width 属性时,flex-basis 具有更高的优先级。

W3C 鼓励使用 flex 简写属性(下一小节进行秒速)来控制灵活性,而不是直接使用 flex-basis 属性。因为简写属性 flex 可以正确地重置任何未指定的属性以适应常见的用途。

flex

flex 属性是 flex-growflex-shrinkflex-basis 的简写,规定了弹性元素如何伸缩以适应 flex 容器中的可用空间,默认值为 0 1 auto

1
flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]

flex 属性可以指定 1 个,2 个或 3 个值。

单值语法: 值必须为以下其中之一:

  • 一个无单位数(<number>): 它会被当作 <flex-grow> 的值。
  • 一个有效的宽度(width)值: 它会被当作 <flex-basis>的值。
  • 关键字 noneautoinitial

双值语法: 第一个值必须为一个无单位数,并且它会被当作 <flex-grow> 的值。第二个值必须为以下之一:

  • 一个无单位数:它会被当作 <flex-shrink> 的值。
  • 一个有效的宽度值: 它会被当作 <flex-basis> 的值。

三值语法:

  • 第一个值必须为一个无单位数,并且它会被当作 <flex-grow> 的值。
  • 第二个值必须为一个无单位数,并且它会被当作 <flex-shrink> 的值。
  • 第三个值必须为一个有效的宽度值, 并且它会被当作 <flex-basis> 的值。

这个属性没啥好演示的,其实就是之前介绍的三个属性的组合:

align-self

align-self 属性在 flex 布局中作用于单个 flex 元素上,它将控制指定元素在交叉轴上的位置。

1
2
3
4
align-self: auto | normal | stretch | center | flex-start | flex-end;

/* 多数浏览器未实现的功能 */
align-self: start | end | self-start | self-end | [first | last]? baseline;
  • auto: 设置为父元素的 align-items 值,如果该元素没有父元素的话,就设置为 stretch
  • normal: 在 flex 布局中,相当于 stretch 的效果。
  • stretch: flex 元素将会基于容器的宽和高,按照自身 margin box 的 cross-size 拉伸。
  • center: 使项目在交叉轴中居中。
  • flex-start: flex 元素会对齐到 cross-axis 的首端。
  • flex-end: flex 元素会对齐到 cross-axis 的尾端。

order

order 属性用于设置指定 flex 元素在容器中的顺序。容器中的 flex 元素按升序值排序,若值相同则按其源代码出现的顺序进行排序,默认值为 0。它接受一个整数值(integer),如 -203 等。

1
order: <integer>

我们可以操作下面的 demo 来控制元素的顺序,比如将第三项元素通过 order 在移动到第一位。


兼容性

要将学到的新东西应用到实际项目中就不得不考虑其兼容性了。通过 caniuse 我们可以看到:flex 布局经过多年的发展,主流浏览器都已经对 flex 布局基本模块都实现完毕了。

PC 端需要考虑的是要不要兼容 IE,移动端最低兼容为 ios 3.2+Android 2.1+。如果你需要开发微信小程序,那么小程序官方就推荐使用 flex 布局。

早期 flex 布局是通过 display: box; 来申明,这是使用了旧的规范,后来该值被 flex 给替换掉了。还有一些很低版本的浏览器或许还需要添加浏览器前缀才能使用 flex 布局。因此你在某处看到如下代码也不用感到奇怪,这是开发者在给布局做兼容呢:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
.flex-center {
display: -webkit-box;
display: -webkit-flex;
display: -moz-box;
display: -ms-flexbox;
display: flex;
-webkit-box-pack: center;
-webkit-justify-content: center;
-moz-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
-webkit-box-align: center;
-webkit-align-items: center;
-moz-box-align: center;
-ms-flex-align: center;
align-items: center;
}

但如果要我们在开发时手动写这种兼容好像不是很靠谱,兼容又冗余。所幸现在的前端开发都会使用脚手架,这些脚手架一般都会内置 postcssautoprefix 之类的插件来帮助我们完成这些事。

还有一些朋友可能会说,我们老项目还是得要兼容 IE 8+ 呀,是不是意味着跟 flex 布局无缘了?其实不是的,github 上有一个叫 flexibilitypolyfill 可以让 IE8 + 也实现 flex 布局效果.


结束

本篇介绍了 flex 布局该如何使用、各属性的作用与效果,下一篇再详细讲讲 flex 布局在实际工作中的妙用~

参考资料:

  1. CSS Flexible Box Layout Module Level 1
  2. CSS Box Alignment Module Level 3
  3. Flex Item

累积布局偏移优化 CLS 完全指南

什么是布局偏移

一个十几秒的短视频解释清楚。

更详细的解释是:布局偏移指的是在网页上发生突然变化时,页面中的内容位置发生意外移动的现象。这种情况常常让人感到困扰,因为它会导致阅读中断或误操作。布局偏移通常是由于资源异步加载或动态添加到页面上的 DOM 元素导致的。可能的原因包括具有未知尺寸的图像或视频、字体与其备用字体渲染大小不同,或者第三方广告或小部件动态调整大小。

难受的是,网站在开发过程中的功能通常与用户体验有很大不同。个性化或第三方内容在开发中的行为通常与生产环境中不同,测试图像通常已经存在于开发者的浏览器缓存中,本地运行的 API 调用通常非常快,延迟几乎不可察觉。

什么是 CLS

累积布局偏移 CLS(Cumulative Layout Shift)是一个指标。

是对页面整个生命周期中发生的每个意外布局变化的最大布局变化分数的度量。

CLS 通过测量实际用户遇到布局偏移的频率来帮助解决布局偏移问题。它可以帮助开发者了解布局偏移在真实用户中发生的情况,从而采取相应的措施进行修复。

为什么要优化 CLS

布局偏移是一个非常影响用户体验的问题,通过上面那一个简短的视频也能理解。

布局偏移通常会导致意外点击、页面方向的迷失,最终导致用户受挫。用户往往不会逗留太久。有时也会使用户不按照预计的产品流程走。

通常优化好布局偏移能够很好的提高用户粘性、用户停留时间等指标。

Yahoo! JAPAN News 通过降低 CLS 0.2 分,得到如下成果。

如何降低 CLS

图片等媒体元素占位

在图像、视频等媒体资源元素中始终包含宽度和高度大小属性。或用 CSS 中的 min-heightaspect-ratio 或类似的方式保留所需的空间。

aspect-ratio

可以用来直接指定当前元素的比例。

https://developer.mozilla.org/zh-CN/docs/Web/CSS/aspect-ratio

对浏览器的支持:

padding-bottom

如果考虑浏览器支持问题仍然可以考虑使用目前一个被广泛接受的基解决方案 “Padding-Top Hack”。这个解决方案需要一个父元素和一个绝对型的子元素。然后计算出长宽比的百分比来设置为 padding-top。例如:

1
2
3
<div class="container">  <img class="media" src="..." alt="..."></div>
1
2
3
4
5
6
7
8
9
10
.container {  position: relative;  width: 100%;  padding-top: 56.25%; /* 16:9 Aspect Ratio */}.media {  position: absolute;  top: 0;}

使用不易产生偏移的 CSS

其中 transfrom 表现很好,以下举几个例子。
用例可以在这里找到:https://play.tailwindcss.com/26PxFA6UVI

zoom VS transform: scale

zoom 会撑大页面并向右偏移时,transform: scale 只是在原地放大。

margin VS transform: translate

margin 造成父元素变大,transform: translate 只是让当前元素移动。

border VS box-shadow

border 会撑起父元素,而 box-shadow 并不会。

小心你的懒加载

懒加载会引起布局的偏移,如果你在有懒加载长列表的里进行跳转,请小心!
无动画进行跳转,能够一定程度上避免该问题。

小心使用 transition: all

在页面首次加载或者跳转页面时,transition: all 可能会导致元素的 padding 等从参数为 0 开始渲染,照成页面的抖动。

这都是痛:
Commit:表格以及友情链接图标抖动
Commit:修复导航栏抖动问题

标签顺序导致的偏移问题

由于在移动端上优先展示主要内容,因此侧边栏的 markup 位于主要内容的后面;而在更大的屏幕上,则通过设置 CSS order 的方式进行排序,将主要内容移到中间(即第二列),伪代码如下:

1
2
3
4
5
6
7
8
9
export default function MainLayout(props) {  return (    <Container>      <Main className={css`@media screen and (min-width: breakpoint) { order: 0 }`} />      <Left className={css`@media screen and (min-width: breakpoint) { order: -1 }`} />      <Right className={css`@media screen and (min-width: breakpoint) { order: 1 }`} />    </Container>  )}

浏览器在首次绘制时并没有完整解析 DOM、只知道 <Main /> 的存在、但不知道 <Left /> 或者 <Right /> 的存在,才因此将 <Main /> 渲染进第一列而不是第二列;直到第二次绘制时,浏览器才将 <Main /> 渲染进第二列、将 <Left /> 渲染进第一列。

Chrome 并不是一次完整解析 HTML 的,在以下两种情况下,Chrome 会暂停解析、开始渲染和绘制:

  1. Chrome 解析器在读取了 65535 字节的 HTML 后暂停
  2. Chrome 在遇到 <script> 标签后,会继续读取约 50 个「Token」之后暂停

详细了解请看:优化博客的累计布局偏移(CLS)问题

网页跳转与前进后退缓存

默认情况下,所有浏览器都使用 bfcache,但由于各种原因,有些站点不适合使用 bfcache。有关如何测试和识别阻止 bfcache 使用的任何问题的更多详细信息,请阅读 bfcache 文章

在你离开后,bfcache 将页面保存在浏览器内存中很短的一段时间,所以如果你返回它们,那么它们将完全恢复为你离开时的样子。这意味着完全加载的页面立即可用,而不会出现任何变化。

现在的 SPA 应用也能很轻易的保证路由跳转页面布局的一致性。记住始终保持你的目录和导航栏在页面的固定位置。

字体

在下载和渲染网络字体之前,通常有两种处理方式:

  1. 使用网络字体替代备用字体(FOUT——未样式化文本的闪烁)。
  2. 使用备用字体显示“不可见”文本,直到网络字体可用并且文本可见(FOIT——不可见文本的闪烁)。

着两种方式都可能导致布局变化。即使文本是不可见的,它仍然使用备用字体进行布局。这意味着使用该字体的文本块以及周围的内容在网络字体加载时会发生布局变化,与 FOUT 的可见字体完全相同。

以下方法可以帮助你最小化这种问题:

  1. 使用 font-display: optional 可以避免重新布局,因为只有在初始布局时网络字体可用时才会使用它。
  2. 使用匹配度高的备用字体。例如,使用 font-family: "Google Sans", sans-serif; 将确保在加载"Google Sans"字体时使用浏览器的无衬线备用字体。如果只使用 font-family: "Google Sans" 而不指定备用字体,将使用默认字体,而在 Chrome 上默认字体是"Times",它是比默认无衬线字体的匹配度更差。
  3. 使用新的 size-adjustascent-overridedescent-overrideline-gap-override API 来尽量减小备用字体和网络字体之间的大小差异,详细信息请参阅“Improved font fallbacks”文章。
  4. 使用 Font Loading API 可以减少获取所需字体的时间。
  5. 使用 <link rel=preload> 尽早加载关键的网络字体。预加载的字体有更高的机会达到首次绘制,这样就不会发生布局变化。
  6. 阅读有关字体最佳实践的“Best practices for fonts”文章。

使用真正的骨架屏

骨架屏好坏示例

测量 CLS 分数

生产阶段

实验阶段

Lighthouse in DevTools

能够针对移动设备和桌面设备生成网页的实际性能报告,并能够提供关于如何改进相应网页的建议。

在本地开发期间从 DevTools 运行 Lighthouse 非常方便。

PageSpeed Insights

应该就是在线版的 Lighthouse。

Performance in DevTools

性能选项卡在 Chrome 的 DevTools 配置文件的所有页面行为在一段时间内记录。时间轴上会出现一个标记为“Experience”的图层,突出显示布局的变化和发生变化的元素。

Web Vitals extension

最好将 Web vital 扩展视为查找性能问题的抽查工具,而不是全面的调试工具——这是 Chrome 的 DevTools 中的性能选项卡的工作。

结语

作为一个对自己项目有较高要求的人,平常几乎都会接触到布局偏移优化或者 Lighthouse,只不过之前自己瞎折腾的时候还没有 CLS 这个概念,现在算是对 CLS 有了较为清晰的概念了。
CLS 作为一个非常基础的优化指标,在用户体验上非常重要,任何项目都应该针对 CLS 做优化。

如有勘误,请及时指出,感谢!

参考

  1. https://web.dev/cls/
  2. https://web.dev/optimize-cls
  3. https://developers.google.com/publisher-tag/guides/minimize-layout-shift
  4. https://web.dev/yahoo-japan-news/
  5. https://addyosmani.com/blog/infinite-scroll-without-layout-shifts/
  6. https://blog.skk.moe/post/fix-blog-cls/
  7. https://developer.mozilla.org/en-US/docs/Web/CSS/aspect-ratio
❌