时间:2024-06-11 作者:剧中人
近来给博客 UI 做了小的局部改版,给博客正文的布局更改为“剧场模式”。其实和原来的布局并没有太大的区别,只是将封面图做了更大面积的展示。
样式的调整不复杂,并没有什么值得分享的。但在改 UI 的时候,却发现小剧客栈曾经很多让小剧“引以为傲”的实现,正慢慢变为陈旧的“顽疾”。
简单来说,就是站在 2024 年,博客里很多借助于 JS 实现的效果,都可以由 CSS 来实现了。
新的“剧场模式”博文截图
之前的博文界面截图
单纯实现上图的效果并不难,但是在实际动手改代码时,却意识到之前的实现比较僵硬。
为了更好的兼容性,早期版本的底图模糊效果是借助于 JS 来实现的。
原理很简单,在模糊逻辑入口,会检测显示区域的尺寸。等待原始图片加载后,构建 canvas,并且设置为和可视区域同等大小,然后将图片居中绘制在 Canvas 上。
覆盖一层 0.4 不透明度的黑色矩形,实现亮度降低的效果。
接下来逐个像素遍历,以像素点周围八像素为半径平均计算执行模糊逻辑。
最后再将 canvas 内容以 base64 的形式读出,设置到 dom 的背景上。
单纯分析这段逻辑,其实并没有太大问题,甚至像前文提的一样“兼容性很好”。
目前主流的浏览器对 Canvas 支持都挺好,并且模糊计算为常规 JS 逻辑,不涉及到特殊的浏览器 API 调用,可以在所有浏览器中正确运行。
问题在于这里的计算是同步的,需要 JS 硬扛,计算量过大或者系统可用资源不足时,页面会变卡。
以 100px * 100px 的显示区域举例,模糊半径为 5 像素。总的像素数为一万个,遍历的步长就是一万。加上 5 像素半径的模糊,以及 R、G、B、A 四通道的叠加,计算量还需要再上两个量级。
别忘了这里的例子只有 100px * 100px,模糊半径只有 5 像素哦~
最近两年一直在写小剧起始页这个个人项目。
在小剧起始页里,大量用到了背景模糊的效果,包括底图模糊、界面模糊。
在现代浏览器下,filter 和 backdrop-filter 可以实现很多诸如:模糊、亮度、对比度之类的图像效果。
虽然借助于 GPU 硬件加速比一般样式更耗费性能,但终究比 JS 死扛要好得多。
上面的例子只是在开发博文“剧场模式”时,遇到的最直观的问题。
可改可不改,但不改心里总是痒痒的。
以小剧钻牛角尖的个性,自然第一件事拿它开刀。在写“剧场模式”之前就急不可耐地删了 JS 模糊逻辑。
顺着博文底图模糊效果的由头,小剧又对 TOC sticky 效果、导航粘滞效果做了实现上的替换。
前面一直提到的例子就是博文背景图片模糊效果了。
CSS 的模糊其实可以对任意 Dom 生效,而非仅仅针对图片。
要实现图片模糊一般有两种方案。
一是使用 filter 属性,直接在图片上应用滤镜。
img {
// 模糊 8px,亮度70%
filter: blur(8px) brightness(0.7);
}
第二种方案是在图片上层设置蒙层,使用 backdrop-filter 对覆盖区域设置模糊。
这种方法更为灵活,并且可以实现部分区域模糊的毛玻璃效果。
.overlay {
// 模糊 8px,亮度70%
backdrop-filter: blur(8px) brightness(0.7);
}
此次博文“剧场模式”的底图模糊效果,使用了 backdrop-filter 来实现。
另外在使用 CSS 替换 JS 实现效果的同时,发现这么做还有另一个优势,就是针对多端的响应式实现特别容易。
之前手机版不模糊效果就很难实现。因为手机在横竖屏间切换时,底图也需要在模糊与不模糊之间切换,使用 JS 实现需要频繁的进行模糊的计算与 Dom 修改。
而换为 CSS 实现模糊,仅仅一句 @media 就可以实现响应式的区分。
sticky 定位布局是一种很灵动的效果。既拥有 static 的稳重,又兼顾 fixed 定位的跳脱,同时又有不脱离父级区域的乖巧。
sticky 布局常应用于侧边栏需要常驻的模块,但是很多无良站长会用它放广告。
如果你在使用电脑端阅读这篇文章,并且是小剧客栈中的原文而非其他平台转载。右侧的 TOC 大纲部分就是 sticky 效果。
或者你可以点击下面链接,预览区域右侧黑色框框,在页面滚动中的效果就是 sticky 效果。
这种效果早在 position: fixed
支持都不是很完全的十几年前,就被大范围使用了。
因为效果很特殊,需要考虑 Dom 在 static 模式下与浏览器视口的关系。同时还要兼顾滚动到可视区域外时,父级与浏览器视口的关系。
一直以来 sticky 效果都是基于 JS 实现的,各类 UI 框架几乎也都会有自己的实现。
小剧在十年前写过一个 tie.js,用来实现 sticky 效果,一直沿用至今。
https://github.com/bh-lay/tie.js
前端有一个经典的面试题,是介绍 position 的属性。一般答到 static、relative、absolute、fixed 以及对应的特性就足够了。如果能再追加后面这句,可能会更完整。
火狐浏览器还支持 sticky 布局。
可能是最近几年没有关注 sticky 属性的发展,直到好友 Mofei 去年分享 《CSS position: sticky》 时才发现,CSS sticky 布局的兼容性已经达到了可以在生产环境使用的条件。
position sticky caniuse 截图
于是在开发博文“剧场模式”的时候,对博文右侧的 TOC 模块做了重构。
删除了 tie.js 的引用,更改为 position: sticky
布局。
当然了,sticky 布局也并不是一行 CSS 就能搞得定,需要每一层父级放行对 overflow 的定义。
具体细节可以参考 Mofei 分享的 《CSS position: sticky》 。
这是小剧客栈使用过很多年的一个效果,如果你是在其他网站看到的转载博文,请回到小剧客栈使用电脑或 Pad 体验效果。
效果很简单,就是当页面在初始位置时,导航条以最小形态展示,并且会和顶部保持一点点距离。这样子设计,在配合页面底图显示的时候会更协调。
当页面开始滚动时,导航条会慢慢的吸附到顶部位置,并且会默默恢复成通栏的宽度。
想要这种效果,最常规的方法一定是监听窗口的滚动事件,再配合滚动位置来实现。似乎也没有更好的方案了,小剧也正是这么实现的。
近期接触到 Scroll-driven Animations,发现 CSS 已经愈发变成小剧不认识的样子了。虽然目前滚动驱动动画的兼容性,还没有广到可以随意使用的程度,但对于这种锦上添花的交互还是值得一试的。
滚动驱动动画兼容性截图
滚动驱动动画(Scroll-driven Animations)的字面含义非常直白,就是使用 CSS 实现页面滚动时的动画效果。
利用这个特性可以实现很多不可思议的效果。感兴趣的话可以查看 https://scroll-driven-animations.style/ 这个站点,收录了很多有趣的滚动动画。
小剧这里只是做了很小的应用,删掉了原本页面滚动的 JS 监听,使用 CSS 实现这个小魔法。
就三点:
feat: develop theater mode for blog article https://github.com/bh-lay/blog/pull/168
feat: remove tie module https://github.com/bh-lay/blog/pull/170
feat: navigation use scroll driven animation https://github.com/bh-lay/blog/pull/172
2024 是小剧工作的的第十二年,前端也由 2012 年 IE6 时代,在经历过浏览器大混战之后慢慢趋于统一。
在 CSS3 一统江湖之后,小剧对 CSS 的关注也越来越弱。
甚至一度觉得 CSS 的发展已经到了“尽头”。近些年一直埋头在做业务,偶尔关注下浏览器的新特性、框架的新功能。直到最近重新关注起 CSS,才发现它也没有停滞不前。
比如前文提到的 CSS 滤镜、sticky 定位、Scroll-driven Animation,还有个在个人项目中用到的:CSS 变量、Grid 布局。
甚至小剧在 N 年前就幻想过的容器查询,已经更方便更丰富地支持了。
这些特性都是一份份草案背后的无数提交者,在经历过无数个日夜努力之后,才形成标准的一部分。
而小剧作为 Web 应用开发者,可以在简单的阅读文档后“坐享其成”。
这次大面积的删掉 JS,可惜么?
能够用更简单的方法,用 CSS 来书写本该属于样式的代码,对小剧来说是极其符合心智的,也是能够刺激到爽点的事情。
虽说被删掉的 JS 代码,在当下来看略显“陈旧”。但在五年前、十年前,甚至更早些时候,却是实现效果必不可少的手段。
CSS 依旧在发展,现如今依旧有些样式需要借助 JS 来实现。将来可能用 JS 辅助样式的代码会越来越少,但至少当下,这部分 JS 仍有意义。
所以这次大面积的删掉 JS,可惜么?
挺可惜的,可惜这些好用的 CSS 特性没能来得更早一些。
写在最后:
这篇记录的小水文发布前夕,刚好大漠叔叔发布了《2024,该放弃框架来实现 Web 布局了》。
文章内容和小剧要表达的主题高度重合,只是小剧这篇小水文,仅限于记录小剧此次的小改动,而大漠这篇文章更系统地介绍了,在 2024 年的现在,CSS 能干的更多的事情,推荐阅读。