CSS Houdini
前言
最近看了几篇文章,是关于 CSS Houdini 的。作为一个前端搬砖的还真不知道这玩意,虽然不知道的东西挺多的,但是这玩意有点高大上啊。
Houdini 是一组底层 API,它们公开了 CSS 引擎的各个部分,从而使开发人员能够通过加入浏览器渲染引擎的样式和布局过程来扩展 CSS。Houdini 是一组 API,它们使开发人员可以直接访问CSS 对象模型 (CSSOM),使开发人员可以编写浏览器可以解析为 CSS 的代码,从而创建新的 CSS 功能,而无需等待它们在浏览器中本地实现。
具体解释见:CSS Houdini
推荐文章
用CSS Houdini画一片星空
CSS Houdini 实现磁吸效果
CSS Houdini:用浏览器引擎实现高级CSS效果
官方案例
Houdini Samples,可以看看有些东西还是很有意思的。
给textarea加一个方格背景
文章中的效果图:

文章中提到了渐变,自己尝试了一下没啥思路。但是有一种取巧的方式——背景图,把下面的图片当成背景图不就好了

textarea{width: 300px;height: 100px;background-image: url('./abc.png');background-size: 80px 40px;color: white;font-size: 30px;}
我的效果,这不是差不多吗😃

突然发现自己有点傻叉,自己这个每一行的颜色都是一样的,跟官方的差远了。
Houdini 基本用法
attributeStyleMap 和 computedStyleMap
- attributeStyleMap 用于处理内联样式,可以进行读写操作
- computedStyleMap 用于处理非内联样式,只允许读
// Before Houdiniconst size = 30
target.style.fontSize = size + 'px' // "20px"const imgUrl = 'https://www.exampe.com/sample.png'
target.style.background = 'url(' + imgUrl + ')' // "url(https://www.exampe.com/sample.png)"target.style.cssText = 'font-size:' + size + 'px; background: url('+ imgUrl +')'
// "font-size:30px; background: url(https://www.exampe.com/sample.png)"
上面的代码应该很多人都写过,拿到dom元素直接修改内联样式。简单的样式这样写还是可以的,但是比较复杂的时候就比较容易出错
这时可以使用 attributeStyleMap 和 computedStyleMap
<template><div id="test">111</div>
</template><script>export default {mounted() {let el = document.getElementById('test');// attributeStyleMap 用于处理内联样式,可以进行读写操作el.attributeStyleMap.set('color', 'blue');el.attributeStyleMap.set('font-size', '40px');console.log(el.attributeStyleMap.get('font-size'), el.attributeStyleMap.get('color'), el.attributeStyleMap.get('width'));// computedStyleMap 用于处理非内联样式,只允许读console.log(el.computedStyleMap().get('color').toString(), el.computedStyleMap().get('font-size'));}
};
</script><style lang="scss" scoped>
#test {width: 100px;height: 100px;background: pink;
}
</style>

自己尝试了一下,有几个需要注意的点:
- attributeStyleMap ,可以进行读写,但是只能读取到内联样式
- computedStyleMap() ,只读,可以读取到dom元素上最终的样式
- 对于有单位的样式,比如
width,会返回一个对象;对于五单位样式,比如color,需要调用toString()方法来进行转换 - 以设置样式来说,不支持链式操作
这里补充一个与computedStyleMap 类似的东西,之前在 css中样式类型及属性值的获取 简单说过,感兴趣的可以看一下
CSS Properties & Values API
可以允许开发者自定义属性和属性值,其实就是css变量。
这个不说了,赶紧用处不大,而且有点习惯使用scss了
Paint API
提供了一组与绘制(Paint)过程相关的API,我们可以通过它自定义的渲染规则,例如调整颜色(color)、边框(border)、背景(background)、形状等绘制规则。
文章最开始介绍的如何实现文本域的背景就是通过这种方式来实现的,通常需要创建一个js来编写绘制逻辑,然后使用registerPaint 进行注册。比如:
/* checkboardWorklet.js */class CheckerboardPainter {paint(ctx, geom, properties) {const colors = ['red', 'green', 'blue'];const size = 32;for(let y = 0; y < geom.height/size; y++) {for(let x = 0; x < geom.width/size; x++) {const color = colors[(x + y) % colors.length];ctx.beginPath();ctx.fillStyle = color;ctx.rect(x * size, y * size, size, size);ctx.fill();}}}
}// 注册checkerboard
registerPaint('checkerboard', CheckerboardPainter);
/* index.html */
<script>CSS.paintWorklet.addModule('path/to/checkboardWorklet.js') // 添加checkboardWorklet到paintWorklet
</script>
/* index.html */
<!doctype html>
<textarea></textarea>
<style>textarea {background-image: paint(checkerboard); // 使用paint()方法调用checkboard绘制背景}
</style>
但是在vue中, CSS.paintWorklet.addModule('path/to/checkboardWorklet.js') 这一步失败了,无法请求的js文件,应该是需要进行设置。
因为不知道如何处理,所以采用第二种方式
示例:绘制一个矩形
// js
let blobURL = URL.createObjectURL(new Blob(['(',function() {class CheckerboardPainter {static get inputProperties() {return ['--rect-color'];}paint(ctx, geom, properties, args) {// ctx 一个 Canvas 的 Context 对象,因此 paint 中的绘制方式跟 canvas 绘制是一样的。// geom 包含节点的尺寸信息,同时也是 canvas 可绘制范围(画板)的尺寸信息。// properties 包含节点的 CSS 属性,需要调用静态方法 inputProperties 声明注入。// CSS 中调用 Paint 类时传入的参数,需要调用静态方法 inputArguments 声明注入const color = properties.get('--rect-color')[0];ctx.fillStyle = color;ctx.fillRect(0, 0, geom.width, geom.height);}}registerPaint('checkerboard', CheckerboardPainter);}.toString(),')()'], { type: 'application/javascript' })
);export default blobURL;// 使用
<template><div><div class="rect"></div></div>
</template><script>import blobURL from './checkerboard.js';
export default {mounted() {CSS.paintWorklet.addModule(blobURL);}
};
</script><style lang="scss" scoped>
.rect {width: 100px;height: 100px;--rect-color: red;background-image: paint(checkerboard);
}
</style>

官方示例文本域
let blobURL = URL.createObjectURL(new Blob(['(',function() {class CheckerboardPainter {paint(ctx, geom, properties, args) {const colors = ['red', 'green', 'blue'];// 方块的尺寸const size = 32;for (let y = 0; y < geom.height / size; y++) {for (let x = 0; x < geom.width / size; x++) {const color = colors[(x + y) % colors.length];ctx.beginPath();ctx.fillStyle = color;ctx.rect(x * size, y * size, size, size);ctx.fill();}}}}registerPaint('checkerboard', CheckerboardPainter);}.toString(),')()'], { type: 'application/javascript' })
);export default blobURL;<template><div><textarea></textarea></div>
</template>
<script>import blobURL from './checkerboard.js';
export default {mounted() {CSS.paintWorklet.addModule(blobURL);}
};
</script><style lang="scss" scoped>
textarea {background-image: paint(checkerboard);
}
</style>

要玩好Paint API,还是需要对canvas非常熟悉才行。
Animation API
提供了一组与合成(composite)渲染相关的API,我们可以通过它调整绘制层级和自定义动画。
略,现在有一些很不错的js动画库,没必要用这个写动画。
Layout API
提供了一组与布局(Layout)过程相关的API,我们可以通过它自定义的布局规则,类似于实现诸如flex、grid等布局,自定义元素或子元素的对齐(alignment)、位置(position)等布局规则。
略,这个一般人玩不了,也没必要看了。
磁吸效果
效果:https://codepen.io/HelKyle/pen/zYWozde
效果图:

let blobURL = URL.createObjectURL(new Blob(['(',function() {class MagnetMatrixPaintWorklet {// 鼠标位置、点的颜色、大小、间隔、影响半径static get inputProperties() { return ['--mouse-x', '--mouse-y', '--magnet-color', '--magnet-size', '--magnet-gap', '--magnet-radius']; }paint(ctx, size, props) {const mouseX = parseInt(props.get('--mouse-x'));const mouseY = parseInt(props.get('--mouse-y'));const color = props.get('--magnet-color');const lineWidth = parseInt(props.get('--magnet-size'));const gap = parseInt(props.get('--magnet-gap'));const radius = parseInt(props.get('--magnet-radius'));ctx.lineCap = 'round';for (let i = 0; i * gap < size.width; i++) {for (let j = 0; j * gap < size.height; j++) {const posX = i * gap;const posY = j * gap;const distance = Math.sqrt(Math.pow(posX - mouseX, 2) + Math.pow(posY - mouseY, 2));const width = distance < radius ? (1 - distance / radius * distance / radius) * gap * 0.4 : 0;const startPosX = posX - width * 0.5;const endPosX = posX + width * 0.5;const rotate = Math.atan2(mouseY - posY, mouseX - posX);ctx.save();ctx.beginPath();ctx.translate(posX, posY);ctx.rotate(rotate);ctx.translate(-posX, -posY);ctx.moveTo(startPosX, posY);ctx.strokeStyle = color;ctx.lineWidth = lineWidth;ctx.lineCap = 'round';ctx.lineTo(endPosX, posY);ctx.stroke();ctx.closePath();ctx.restore();}}}}registerPaint('magnet-matrix', MagnetMatrixPaintWorklet);}.toString(),')()'], { type: 'application/javascript' })
);export default blobURL;
<template><div class="demo"></div>
</template>
<script>import blobURL from './checkerboard.js';
export default {mounted() {if ('paintWorklet' in CSS) {CSS.paintWorklet.addModule(blobURL);}let div = document.getElementsByTagName('div')[0];div.addEventListener('mouseenter', e => {div.style.setProperty('--mouse-x', e.clientX);div.style.setProperty('--mouse-y', e.clientY);});div.addEventListener('mousemove', e => {div.style.setProperty('--mouse-x', e.clientX);div.style.setProperty('--mouse-y', e.clientY);});div.addEventListener('mouseleave', () => {div.style.setProperty('--mouse-x', -999);div.style.setProperty('--mouse-y', -999);});},
};
</script><style lang="scss" scoped>
div {box-sizing: border-box;padding: 0;margin: 0;
}.demo {width: 100vw;height: 100vh;padding: 80px;--magnet-color: rgb(97, 123, 255);--magnet-size: 2;--magnet-gap: 20;--magnet-radius: 150;background: paint(magnet-matrix);
}
</style>
相关文章:
CSS Houdini
前言 最近看了几篇文章,是关于 CSS Houdini 的。作为一个前端搬砖的还真不知道这玩意,虽然不知道的东西挺多的,但是这玩意有点高大上啊。 Houdini 是一组底层 API,它们公开了 CSS 引擎的各个部分,从而使开发人员能够通…...
C++引用
这里写目录标题引用引用的基本使用引用做函数参数引用作为函数返回值引用的本质常量引用引用与指针的区别&的三种作用引用 引用的基本使用 作用: 给变量起别名 语法: 数据类型 &别名 原名 引用的本质是给变量起别名,因此࿰…...
YOLOv6-目标检测论文解读
文章目录摘要问题算法网络设计BackboneNeckHead标签分配SimOTA(YOLOX提出):TAL(Task alignment learning,TOOD提出)损失函数分类损失框回归损失目标损失行业有用改进自蒸馏图像灰度边界填充量化及部署实验消…...
【factoryio】使用SCL编写 <机械手控制> 程序
使用虚拟工厂软件和博图联合仿真来编写【scl】机械手控制程序 文章目录 目录 文章目录 前言 二、程序编写 1.机械手运行部分 2.启动停止部分 3.急停复位部分 三、完整代码 总结 前言 在前面我们一起写过了许多案例控制的编写,在这一章我们一起来编写一下一个…...
QT学习记录散件
fromLocal8Bit() qt中fromLocal8Bit()函数可以设置编码。 因为QT默认的编码是unicode,不能显示中文的 而windows默认使用(GBK/GB2312/GB18030) 所以使用fromLocal8Bit()函数,可以实现从本地字符集GB到Unicode的转换,从…...
[SSD科普之1] PCIE接口详解及应用模式
PCI-Express(peripheral component interconnect express)是一种高速串行计算机扩展总线标准,它原来的名称为“3GIO”,是由英特尔在2001年提出的,旨在替代旧的PCI,PCI-X和AGP总线标准。一、PCI-E x1/x4/x8/x16插槽模式PCI-E有 x1/…...
Linux设备驱动模型与 sysfs实现分析
RTOS和Linux系统上开发驱动的方式非常的不同,在RTOS系统下,驱动和驱动之间并没有实质性的联系,不同的驱动和BSP之间仅仅通过一层很薄很薄的设备管理框架聚合在一起构成RTOS的设备管理子系统。图形化表示如下: 设备驱动&BSP之间互相独立,互不影响,互不依赖,独立实现,…...
软考高级之制定备考计划
制定备考计划 高项准备时间最好是三个月以上,分为三个阶段来复习。 第一个阶段——熟悉知识点 第二个阶段——刷题 第三个阶段——冲刺复习 具体操作 第一个阶段 这个阶段的复习以教材和视频为主,掌握重要知识点。基础知识要打牢。例如࿱…...
[Pytorch] Linear层输出nan
参考链接: https://discuss.pytorch.org/t/well-formed-input-into-a-simple-linear-layer-output-nan/74720/11 总结原因: numpy需要更新 PS. 查看numpy版本号 打开Anaconda Prompt 进入环境 输入命令conda activate envname 然后输入pip show numpy…...
2023-2-19-What is ‘ template<typename E, E V> ‘?
目录C里面template怎么用inline函数模板类模板函数模板特化C里面template怎么用 template是什么? template其实是C的一种语法糖,本意是去简化程序员的工作. void swap(int *a,int *b){int temp *a;*a *b;*b temp; }比如在写一个交换函数的的时候,参数为两个in…...
华为OD机试题 - 字符串加密(JavaScript)
最近更新的博客 华为OD机试题 - 任务总执行时长(JavaScript) 华为OD机试题 - 开放日活动(JavaScript) 华为OD机试 - 最近的点 | 备考思路,刷题要点,答疑 【新解法】 华为OD机试题 - 最小步骤数(JavaScript) 华为OD机试题 - 任务混部(JavaScript) 华为OD机试题 - N 进…...
美团前端一面手写面试题
实现斐波那契数列 // 递归 function fn (n){if(n0) return 0if(n1) return 1return fn(n-2)fn(n-1) } // 优化 function fibonacci2(n) {const arr [1, 1, 2];const arrLen arr.length;if (n < arrLen) {return arr[n];}for (let i arrLen; i < n; i) {arr.push(arr[…...
2D图像处理:缺陷检测--仿照Halcon的Variation Model
文章目录 基于 C++&Opencv 的检测结果(Robust模式-MAD)一、Variation Model1.1 准备和训练模型方法1.2 比较模板方法1.3 过滤(保留符合缺陷特征的区域)二、参考基于 C++&Opencv 的检测结果(Robust模式-MAD) 一、Variation Model Halcon中的Variation Model主要是将待…...
JavaScript 注释
JavaScript 注释可用于提高代码的可读性。JavaScript 注释JavaScript 不会执行注释。我们可以添加注释来对 JavaScript 进行解释,或者提高代码的可读性。单行注释以 // 开头。本例用单行注释来解释代码:实例// 输出标题:document.getElementB…...
浅谈使用CDN加速的OSS
目录引出OSS对象存储服务CDNCDN加速OSS资源总结引出 之前,我在写项目的时候,因为项目中存在音视频的存储,然后我看圈子里面的人都是使用OSS对象存储来处理,然后我也跟风去使用了,然后在之后,我一个朋友问我…...
华为OD机试题 - 服务依赖(JavaScript)
最近更新的博客 华为OD机试题 - 任务总执行时长(JavaScript) 华为OD机试题 - 开放日活动(JavaScript) 华为OD机试 - 最近的点 | 备考思路,刷题要点,答疑 【新解法】 华为OD机试题 - 最小步骤数(JavaScript) 华为OD机试题 - 任务混部(JavaScript) 华为OD机试题 - N 进…...
整合K8s+SpringCloudK8s+SpringBoot+gRpc
本文使用K8s当做服务注册与发现、配置管理,使用gRpc用做服务间的远程通讯一、先准备K8s我在本地有个K8s单机二、准备service-providerpom<?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.…...
Django框架之模型视图--HttpResponse对象
HttpResponse对象 视图在接收请求并处理后,必须返回HttpResponse对象或子对象。HttpRequest对象由Django创建,HttpResponse对象由开发人员创建。 1 HttpResponse 可以使用django.http.HttpResponse来构造响应对象。 HttpResponse(content响应体, con…...
Linux下的Jenkins安装教程
当前环境 CentOS 7.8Java 11(注意当前jenkins支持的Java版本最低为Java11)FinalShell 3.9(操作环境) 安装Jenkins PS:不建议使用Docker安装Jenkins,因为使用Jenkins的时候一般会调用外部程序,…...
[软件工程导论(第六版)]第5章 总体设计(课后习题详解)
文章目录1. 为每种类型的模块耦合举一个具体例子。2. 为每种类型的模块内聚举一个具体例子。3. 用面向数据流的方法设计下列系统的软件结构。4. 美国某大学共有200名教师,校方与教师工会刚刚签订一项协议。按照协议,所有年工资超过$26000(含$…...
墨语灵犀镜像灰度发布:Kubernetes滚动更新无感升级实践
墨语灵犀镜像灰度发布:Kubernetes滚动更新无感升级实践 1. 引言:优雅升级的艺术挑战 在现代应用部署中,如何实现平滑无感的服务升级一直是个技术难题。特别是对于「墨语灵犀」这样注重用户体验的深度翻译工具,任何服务中断或体验…...
Java异常体系全景解析:从Checked与Unchecked的本质区别到最佳实践
Java异常体系全景解析:从Checked与Unchecked的本质区别到最佳实践在Java的浩瀚生态中,异常处理机制无疑是构建健壮、可靠应用程序的基石。它不仅仅是简单的错误捕获,更是一套精密的契约系统,决定了程序在遭遇非预期状态时如何“表…...
基于OFA的智能写作助手:图文内容自动生成与问答
基于OFA的智能写作助手:图文内容自动生成与问答 1. 引言 你有没有遇到过这样的情况:手头有一堆产品图片,却不知道怎么写吸引人的商品描述;或者看到一张复杂的图表,想要快速提取关键信息却无从下手;又或者…...
水墨江南模型Python入门实践:第一个AI国画生成程序
水墨江南模型Python入门实践:第一个AI国画生成程序 你是不是也刷到过那些充满诗意的AI水墨画?烟雨朦胧的江南水乡,寥寥几笔勾勒出的远山,那种独特的意境让人过目不忘。你可能觉得,要做出这样的画,得是懂艺…...
若依框架多数据源实战:如何用@DataSource注解轻松切换MySQL主从库
若依框架多数据源实战:用DataSource注解实现MySQL主从库智能切换 当系统流量逐渐攀升,数据库的读写压力开始显现时,很多开发者都会面临一个关键决策:如何在保证数据一致性的前提下,有效分散数据库负载?若依…...
5分钟快速上手:Rufus免费工具制作Windows启动盘终极指南
5分钟快速上手:Rufus免费工具制作Windows启动盘终极指南 【免费下载链接】rufus The Reliable USB Formatting Utility 项目地址: https://gitcode.com/GitHub_Trending/ru/rufus 还在为系统安装而烦恼吗?Rufus作为一款完全免费的USB格式化工具&a…...
自动驾驶中的路径规划实战:手把手教你用Python复现RRT与RRT*算法(含动态演示)
自动驾驶路径规划实战:Python实现RRT与RRT*算法全解析 从理论到实践的路径规划探索 在自动驾驶技术快速发展的今天,路径规划作为核心算法之一,直接决定了车辆能否安全高效地完成行驶任务。想象一下,当你驾驶车辆进入一个复杂的停车…...
【2026年阿里巴巴春招- 3月28日-算法岗-第二题- 隐式素数计算】(题目+思路+JavaC++Python解析+在线测试)
题目内容 我们称一个正整数为隐式素数,如果它不同的正因子的个数是一个素数。给定一个闭区间$ [l,r]$,请计算该区间内隐式素数的个数 输入描述 每个测试文件均包含多组测试数据。第一行输入一个整数$ T (1 ≤ T ≤ 10^4)$,代表数据组数,每组测试数据描述如下: 在一行上…...
AutoJS与按键精灵实战:微信抢红包脚本开发指南(附完整代码)
1. 微信抢红包脚本开发入门指南 最近几年,手机自动化工具越来越受到开发者欢迎,特别是像AutoJS和按键精灵这样的工具,能够帮助我们完成很多重复性的手机操作。今天我要分享的是如何用这些工具开发一个微信抢红包脚本,这个需求在过…...
爬虫对抗:ZLibrary 反爬机制实战分析(第二版)
摘要: 本文从爬虫工程化角度,详细分析 ZLibrary 站点的常见反爬策略,包括 IP 限流、Cookie 校验、请求头检测、人机验证、接口签名等,并给出对应的 Python 实战对抗思路与代码示例。本文仅用于网络安全技术学习与反爬防护研究&…...
