#31 MicroLighter 代码高亮库
WebDev CSS 2026-08-24把代码高亮从 DOM 层搬到 CSS 渲染层的 2 KiB 方案
coding in a complicated world
把代码高亮从 DOM 层搬到 CSS 渲染层的 2 KiB 方案
前端圈有一条隐形的墙:DOM 负责结构、文本、无障碍与交互;Canvas / WebGL 负责像素、Shader、粒子与 3D。两边各自很强,却很难融合。
HTML-in-Canvas 是 WICG 正在孵化的提案,试图把这道墙拆掉;
而 Canvas UI 则是基于它(并带降级方案)第一个走红的"GPU 级视觉组件库"。
我用 Golang 开发了一个本地站点,跑在 Caddy 上(动态注册路径),并使用阿里云 DNS 将域名解析到本地 IP。
今天突然发现网页无法打开,浏览器一直处于 Pending 状态,而 curl 访问正常。关闭网络代理和浏览器插件、清理缓存后问题仍然存在。
怀疑是 DNS 解析的问题,使用 curl -vk --resolve d3v.cn:443:192.168.31.31 https://d3v.cn/markjour/ 访问也正常。
更奇怪的是,发现使用访客模式可以打开。
最后还发现,在关闭一些浏览器 Tab 后,普通模式也恢复正常。暂时推测可能与浏览器 HTTP/2 连接复用有关:
以后再次遇到的时候再检查验证。
后续多次遇到这个本地网站访问异常问题,今天抽空继续排查。
发现同一台机器上的 Edge,不同 Profile 对 d3v.cn 的访问结果不同:一个可以正常打开,另一个持续 ERR_TIMED_OUT。
进一步查看 Edge 的网络信息发现(d3v.cn 解析为 ::1 和 192.168.31.31,而正常 Profile 解析为 127.0.0.1。随后检查本机 /etc/hosts,发现配置了:
127.0.0.1 localhost
127.0.0.1 eqr.hosts.d3v.cn eqr eqr6
::1 eqr.hosts.d3v.cn
同时公网 DNS 中 eqr.hosts.d3v.cn 也存在地址记录。因此,同一域名实际上同时存在本地 hosts 和公网 DNS 两套解析结果,Edge 不同 Profile 可能缓存或选择了不同地址。
这次基本确认问题核心在域名解析结果不一致,而不是 Caddy、TLS 或 HTTP/2。后续应避免让同一域名同时依赖 hosts 和公网 DNS 提供不同地址,或者至少确保两者解析结果一致。
初审被拒,原因:
初审通过之后,备案进入 “管局审核中-短信校验中” 状态。
几分钟之后就会收到工信部短信验证码,需要进入指定链接输入验证码、手机号、身份证后六位进行核验。
短信核验之后过一会儿,备案进入 “管局审核中-人工审核中” 状态。
本文不涉及自动签发、自动更换证书,只对 acme.sh 工具的简单用法做一个记录。
mime-type:image/png larger-than:1K
# Edge 官方示例,表示过滤出大于 1K 的 PNG 图片
domain:*.csdn.net method:POST
# 过滤出 CSDN 域的 POST 请求。
has-response-header:Content-Type -domain:*.baidu.com
# 过滤出带 Content-Type 头的请求,排除百度域。
| 属性 | 详情 |
|---|---|
domain |
仅显示来自指定域的资源。您可以使用通配符(*)来包含多个域。例如, *.com 会显示所有以 .com 结尾的域名资源。DevTools 会将所有找到的域名填充到自动完成下拉菜单中。 |
has-response-header |
显示包含指定 HTTP 响应头的资源。 DevTools 会将所有找到的响应头填充到自动完成下拉菜单中。 |
is |
使用 is:running 查找 WebSocket 资源。 |
larger-than |
显示大于指定大小的资源,单位为字节。 设置值为 1000 相当于设置值为 1k。 |
method |
显示通过指定的 HTTP 方法类型检索的资源。 DevTools 会将所有找到的 HTTP 方法填充到下拉菜单中。 |
mime-type |
显示指定 MIME 类型的资源。 DevTools 会将所有找到的 MIME 类型填充到下拉菜单中。 |
mixed-content |
显示所有混合内容资源(mixed-content:all),或仅显示当前显示的资源(mixed-content:displayed)。 |
scheme |
显示通过不安全的 HTTP(scheme:http)或安全的 HTTPS(scheme:https)检索的资源。 |
set-cookie-domain |
显示具有与指定值匹配的 Set-Cookie 标头中的 Domain 属性的资源。DevTools 会将所有找到的 Cookie 域填充到自动完成中。 |
set-cookie-name |
显示具有与指定值匹配的 Set-Cookie 标头中的名称的资源。DevTools 会将所有找到的 Cookie 名称填充到自动完成中。 |
set-cookie-value |
显示具有与指定值匹配的 Set-Cookie 标头中的值的资源。DevTools 会将所有找到的 Cookie 值填充到自动完成中。 |
status-code |
显示与特定 HTTP 状态码匹配的资源。 DevTools 会将所有找到的状态码填充到自动完成下拉菜单中。 |
- 表示取反,小技巧:可以通过输入 - 之后的自动补全查看所有支持的选项。看了 How to split JavaScript strings into sentences, words or graphemes with "Intl.Segmenter" 了解到,现在 Web 已经支持分词了:
const text = `我爱北京天安门,天安门上太阳升。伟大领袖毛主席,指引我们向前进。`;
const granularities = ["sentence", "word", "grapheme"];
granularities.forEach(function (granularity) {
// console.log([granularity, index, self])
let segmenter = new Intl.Segmenter("zh", { granularity: granularity });
let seg = segmenter.segment(text);
// console.log(seg) // Segments{}
let result = Array.from(seg, (s) => s.segment);
console.log(result);
});
// ['我爱北京天安门,天安门上太阳升。', '伟大领袖毛主席,指引我们向前进。']
// ['我', '爱', '北京', '天安门', ',', '天安门', '上', '太阳', '升', '。', '伟大', '领袖', '毛主席', ',', '指引', '我们', '向', '前进', '。']
// ['我', '爱', '北', '京', '天', '安', '门', ',', '天', '安', '门', '上', '太', '阳', '升', '。', '伟', '大', '领', '袖', '毛', '主', '席', ',', '指', '引', '我', '们', '向', '前', '进', '。']
随着浏览器厂商的持续推进,现在 WebApp 也能实现很多底层交互了
Hybird App,在 App 中加入 WebView,实现部分逻辑
根据 Native 和 Web 部分的比例,可以分成:
交替
后端和框架核心通信,实现窗口管理,系统调用,WebView。
在很长一段时间里,浏览器发送 Ajax 请求主要依赖 XMLHttpRequest,也就是大家熟悉的 XHR。
但随着 JavaScript 生态的发展,XHR 的一些问题越来越明显:
于是浏览器推出了更现代、更简洁的网络请求方案 Fetch API。
先看一个传统 Ajax 请求:
var xhr = new XMLHttpRequest();
xhr.open("GET", "/api/user", true);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
console.log(xhr.responseText);
}
}
};
xhr.send();
虽然功能没问题,但存在几个明显缺点:
JSON.parse(xhr.responseText)
主要是基于 Promise 实现,可以链式调用,不用一层又一层地回调,更符合现代 JavaScript 风格。
注意:这是较新的语法,在某些老版本浏览器上可能支持程度不好,如果需要兼容,可以使用 XHR 或者 Axios、jQuery Ajax 等库。
fetch("/api/user")
.then(function (response) { // Response 对象
return response.json();
})
.then(function (data) {
console.log(data);
})
.catch(function (error) { // 异常处理
console.log(error);
});
相比 XMLHttpRequest:
Fetch 也支持提交数据:
fetch("/api/user", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
name: "Tom",
age: 18
})
})
.then(function (response) {
return response.json();
})
.then(function (data) {
console.log(data);
});