茫茫人海中与你相遇
相信未来的你不会很差
作者:阿里巴巴淘系技术
来源:https://juejin.im/post/6886258269137043464
Web性能
contain 和 content-visibility
这两个属性是属于 CSS容器模块 的,其最大的特点应该是可以帮助Web开发者提高Web页面的性能:
当容器的内容发生变化时,浏览器考虑到其他元素可能也会发生变化,于是就会去检查页面中所有的元素。一直以来浏览器都是这么做的,大家都习以为常了。但从另一方面来说,开发者很清楚当前修改的元素是否独立、是否影响其他元素。因此如果开发者能把这个信息通过CSS告诉浏览器,那么浏览器就不需要再去考虑其他元素了,这就是非常完美的事情。而CSS容器模块中的contain属性就为我们提供了这种能力。
们来看@Manuel Rego Casasnovas在《An introduction to CSS Containment》文章中提供的一个示例:
假设一个页面有很多个元素,在这个示例中,我们有10000个这样的元素:
<div class="item"> <div>Lorem ipsum...div>div>
使用JavaScript的textContent这个API来动态更改div.item > div的内容:
const NUM_ITEMS = 10000; const NUM_REPETITIONS = 10; function log(text) { let log = document.getElementById("log"); log.textContent += text; } function changeTargetContent() { log("Change \"targetInner\" content..."); // Force layout. document.body.offsetLeft; let start = window.performance.now(); let targetInner = document.getElementById("targetInner"); targetInner.textContent = targetInner.textContent == "Hello World!" ? "BYE" : "Hello World!"; // Force layout. document.body.offsetLeft; let end = window.performance.now(); let time = window.performance.now() - start; log(" Time (ms): " + time + "\n"); return time; } function setup() { for (let i = 0; i < NUM_ITEMS; i++) { let item = document.createElement("div"); item.classList.add("item"); let inner = document.createElement("div"); inner.style.backgroundColor = "#" + Math.random().toString(16).slice(-6); inner.textContent = "Lorem ipsum..."; item.appendChild(inner); wrapper.appendChild(item); } }
如果不使用contain,即使更改是在单个元素上,浏览器在布局上的渲染也会花费大量的时间,因为它会遍历整个DOM树(在本例中,DOM树很大,因为它有10000个DOM元素):
在本例中,div的大小是固定的,我们在内部div中更改的内容不会溢出它。因此,我们可以将contain: strict应用到项目上,这样当项目内部发生变化时,浏览器就不需要访问其他节点,它可以停止检查该元素上的内容,并避免到外部去。
CSS容器模块中的content-visibility属性会显著影响第一次下载和第一次渲染的速度。此外,你可以立即与新渲染的内容交互,而无需等待内容的其余部分加载。该属性强制用户代理跳过不在屏幕上的标记和绘制元素。实际上,它的工作方式类似于延迟加载,只是不加载资源,而是渲染资源。
简单地说,CSS的content-visibility属性 可跳过不在屏幕上的内容渲染,包括布局(Layout)和渲染(Paint),直到真正需要布局渲染的时候为止。所以利用它可以使用初始用户加载速度更快,还能与屏幕上的内容进行更快的交互。
上图来自于@Una Kravets和@Vladimir Levin的《content-visibility: the new CSS property that boosts your rendering performance(web.dev/content-vis…: auto属性可使分块的内容区域的初始加载性能提高7倍。
数据服务
数据服务指的是 Data Saver。啥意思呢?不做解释,直接用一段代码来描述:
@media (prefers-reduced-data: reduce) { header { background-image: url(/grunge.avif); }}
我想大家对于@media (prefers-reduced-data: reduce)应该不会陌生吧。是的,它就是我们所说的CSS媒体查询。只不过稍有不同的是,这个媒体查询是根据用户在设备上的设置喜好来做条件判断。比如上面示例代码,当用户在设备上开启了“Low Data Mode”(低数据模式),会加载grunge.avif图像,可以帮助iPhone上的应用程序减少网络数据的使用:
到目前为止,CSS媒体查询提供了多个媒体特性,可以以用户在设备上的喜好设置做为判断,比如iOS13+开始,iPhone提供的DarkMode模式(prefers-color-scheme):
比如,使用prefers-reduced-motion媒体查询用于检测用户的系统是否被开启了动画减弱功能:
上面提到的这些媒体查询条件都是在
CSSMediaQueriesLevel 5(www.w3.org/TR/mediaque…) 模块中新增的。
除了上面提到的之外,还有一些我们平时很少见的媒体查询条件,比如:
@media (hover: hoveer) {}@media (hover: none) and (pointer: coarse) {}@media (hover: none) and (pointer: fine) {}@media print and (min-resolution: 300dpi) {}@media (scan: interlace) {}@media (update) {}@media(environment-blending: additive){}@media (color) {}
变量字体
变量字体是一个非常有意思的CSS特性,它也常被称为“可变字体”,先给大家展示一个Demo:
变量字体的目标是让网站性能更好,同时给用户提供了更多选择和扩展。变量字体是类似矢量图形,允许为各种字体轴定义不同的值。变量字体设计中一般有五个注册轴,包括字体、字宽、斜体和光学尺寸。每个注册轴都有一个对应的四个字母的标记,可以映射到现有的CSS属性:
除了注册轴之外,字体设计器还可以包含自定义轴。自定义轴让可变字体变得更具创造性,因为不限制自定义轴的范围、定义或数量。与注册轴类似,自定义轴具有相应的四个字母标记。但是,自定义轴的字母标记必须是大写的。例如,你定义了一个注册轴是grade,其对应的字母标记是 GRAD。
比如上面示例效果对应的代码:
.text { font-weight: 800; font-style: italic; font-variation-settings: "SSTR" 183, "INLN" 648, "TSHR" 460, "TRSB" 312, "TWRM" 638, "SINL" 557, "TOIL" 333, "TINL" 526, "WORM" 523; transition: font-variation-settings .28s ease;} .text:hover { font-weight: 400; font-style: normal; font-variation-settings: "SSTR" 283, "INLN" 248, "TSHR" 160, "TRSB" 112, "TWRM" 338, "SINL" 257, "TOIL" 133, "TINL" 426, "WORM" 223;}
在Firefox浏览器中,我们还可以通过开发者工具中“字体”选项提供的相关可变字体注册轴的值调整:
调整完之后,可以获得新代码:
p { font-size: 60px; line-height: 37px; letter-spacing: 0.113em; font-variation-settings: "SSTR" 450, "INLN" 741, "TSHR" 292, "TRSB" 497, "TWRM" 173, "SINL" 557, "TOIL" 728, "TINL" 526, "WORM" 523, "TFLR" 362, "TRND" 516, "SWRM" 536, "TSLB" 509; font-weight: 491;}
对应效果如下:
Web可访问性
:focus-visible 和 :focus-within
一直以来我很容易把:focus-within和:focus-visible混淆。其实:focus-within和:focus-visible都是CSS选择器 Level 4中用户操作类伪类选择器。早前在《初探CSS 选择器Level 4》中聊过:focus-within,但没有聊过:focus-visible。
另外,在《CSS :focus-within》教程中就提到过, :focus-within能非常方便处理获取焦点状态。当元素本身或其后代元素获得焦点时,:focus-within伪类的元素就会有效 。:focus-within伪类选择器的行为本质上是一种父选择器行为,子元素的状态会影响父元素的样式。由于这种“父选择器”行为需要借助用户的行为触发,属于“后渲染”,不会与现有的渲染机制相互冲突。
如果上面的介绍让你感到困惑的话,可以看下面这个Demo。你会发现,当
的后代元素得到焦点时,会有一个放大的效果:
实现上图的效果代码非常的简单:
form:focus-within { box-shadow: 0px 0.2em 2.5em #c4c4c4; transform: scale(1.025); }
对于:focus-visible伪类来说,当元素匹配:focus伪类并且客户端(UA)的启发式引擎决定焦点应当可见时就会生效。这个选择器可以有效地根据用户的输入方式(鼠标 vs 键盘)展示不同形式的焦点。
简单点说,按键盘tab键和鼠标点击得到的焦点效果不同。比如:
/* 链接得到焦点时的样式 */ a:focus { }/* * 1\. 如果链接有焦点,但是浏览器通常不会显示默认的焦点样式,会覆盖上面的焦点样式 * 2\. 不是按键盘`tab`键让链接得到的焦点,比如说鼠标点击链接*/a:focus:not(:focus-visible) {}/* 按键盘tab键让链接得到焦点的样式 */ a:focus-visible { }
来看一个具体的案例。这个示例中分别用鼠标点击链链和按键盘tab键让链接得到焦点,它的样式是不一样的:
我们在虚拟的空间与你相遇,期待可以碰撞出不一样的火花
公众号ID:前端大联盟扫码关注最新动态