本篇依然来自于我们的 《前端周刊》 项目!
由团队成员 田八 翻译,欢迎大家 进群 持续追踪全球最新前端资讯!!
原文地址:csswizardry
Obs.js 通过读取少量的浏览器信号(Navigator 和 Battery API),推断出用户的连接强度、电池状态以及设备性能。它将这些信号以 CSS
类的形式添加到 <html>
元素上,并且以属性的形式暴露在 window.obs
对象中,这样您就可以据此灵活地调整资源交付策略,比如:提供低分辨率的媒体内容、不使用网络字体、禁用自动播放的视频等等,您可以根据需要自由定制。
事实上,如果您的设备电量极低、已开启省电模式,或者网络连接较弱,那么您在上方 <h1>
标题中看到的将不会是那个圆润美观的 Fredoka
字体------而只会显示您系统默认的 system-ui
字体。
javascript
(() => {
// 只有在能够展示富媒体内容时,才加载 Google Fonts。
// 在不支持相关 API 的浏览器中,我们则会直接加载字体文件。
//
// 此外,我们将字体脚本挂载到 body元素的末尾,而不是 head,
// 这样就不会意外阻塞页面渲染。
if (window.obs?.shouldAvoidRichMedia === true) {
return;
} else {
const gf = document.createElement('link');
gf.rel = 'stylesheet';
gf.href = 'https://fonts.googleapis.com/css2?family=Fredoka:wght@300..700&display=swap';
document.body.appendChild(gf);
}
// 有趣的是:由于这个 <script>标签是一个典型的、内联的、同步执行的脚本,
// 所以在这个代码片段中提到的"body元素的末尾",实际上就是您此刻正在阅读的这段文字的紧后面。
// 打开浏览器的开发者工具(DevTools),
// 您会发现 Google Fonts 的样式表并不是位于 </body>标签之前,而是紧接在这个代码块之后。
//
// 还有一个有趣的地方:您此刻正在阅读的这段文字,其实就是浏览器刚刚执行过的 确切代码内容。
// 只不过我们给它加上了 display: block;样式,让它以块级元素的形式显示出来而已。是不是很巧妙!
})();
Obs.js 由 Harry Roberts 开发并维护,遵循 MIT 许可证。
本页面展示了 Obs.js 为 <html>
元素添加的 .has-*
类,以及它用于存储设备和网络信息的当前 window.obs
对象。
您可以尝试切换 省电模式(Data Saver)、插拔电源 或 切换网络(在支持的设备上),观察这些类和对象的实时更新。
html.classList
- .has-bandwidth-high
- .has-battery-charging
- .has-connection-capability-moderate
- .has-conservation-preference-neutral
- .has-cpu-high
- .has-delivery-mode-cautious
- .has-device-capability-strong
- .has-latency-medium
- .has-ram-high
window.obs
json
{
"config": {
"observeChanges": true
},
"dataSaver": false,
"rttBucket": 150,
"rttCategory": "medium",
"downlinkBucket": 10,
"downlinkCategory": "high",
"connectionCapability": "moderate",
"conservationPreference": "neutral",
"deliveryMode": "cautious",
"canShowRichMedia": true,
"shouldAvoidRichMedia": false,
"ramBucket": 8,
"ramCategory": "high",
"cpuBucket": 16,
"cpuCategory": "high",
"deviceCapability": "strong",
"batteryCritical": false,
"batteryLow": false,
"batteryCharging": true
}
请注意:各浏览器对这些 API
的支持情况有所不同,其中 Chromium
内核浏览器提供的支持最为全面。
Demo
如果您的当前网络连接允许,您应该可以看到下方的小视频;如果条件不允许,则会显示一张静态的 <img>
------ 您看到的是什么?

ini
(() => {
// 如果网络连接状况良好,就嵌入视频;否则,只嵌入屏幕截图图片。
const videoWrapper = document.getElementById('jsVideo');
if (window.obs?.shouldAvoidRichMedia === true) {
const img = new Image();
img.src = './assets/poster.png';
img.alt = '';
img.width = '1500';
img.height = '966';
img.classList.add('c-hero');
videoWrapper.appendChild(img);
} else {
const video = document.createElement('video');
video.src = './assets/video.min.mp4';
video.poster = './assets/poster.png';
video.autoplay = true;
video.loop = true;
video.muted = true;
video.controls = true;
video.preload = 'auto';
if (window.obs?.deliveryMode === 'cautious') {
video.preload = 'metadata';
}
if (window.obs?.batteryLow === true) {
video.autoplay = false;
}
videoWrapper.appendChild(video);
}
})();
分析
如果您使用的 RUM
(真实用户监控) 或 分析服务提供商 能够接收类似 window.obs
格式的数据,那您就可以将这些信息发送给他们! 您 并不一定非要用 Obs.js
来调整或改变您的网站------您完全可以将它作为一个 纯粹的观测工具,借此更深入地了解您的用户群体。

我会把所有数据都发送给我在 SpeedCurve 的朋友们。有了这些数据,我就能开始对 RUM
(真实用户监控)数据进行细分,并制定针对不同用户群体的服务策略。
以下是我用来将 Obs.js
数据发送至 SpeedCurve
的具体代码片段:
javascript
/**
* 此前由 Obs.js 捕获的所有数据,现在都会发送至 SpeedCurve 了!
*
* I ❤️ SpeedCurve!
*/
(() => {
// 如果 SpeedCurve 不可用,则直接退出
if (!window.LUX || typeof window.LUX.addData !== 'function') return;
const obs = window.obs || Object.create(null);
// 我们计划发送的键值。请与 Obs.js 保持同步。
const keys = [
'canShowRichMedia',
'connectionCapability',
'conservationPreference',
'cpuBucket',
'cpuCategory',
'dataSaver',
'deliveryMode',
'deviceCapability',
'downlinkBucket',
'downlinkCategory',
'ramBucket',
'ramCategory',
'rttBucket',
'rttCategory',
'shouldAvoidRichMedia'
];
for (const key of keys) {
if (Object.prototype.hasOwnProperty.call(obs, key)) {
window.LUX.addData(key, obs[key]);
}
}
})();
展示
这些优秀的人正在使用Obs.js:

站点:
- csswizardry.com 用法:
- 在受限网络上提供低分辨率的英雄图像;
- 在低电量模式下禁用过渡和动画。