CSS Houdini

news2024/12/25 2:47:29

前言

最近看了几篇文章,是关于 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 Houdini
 
const 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>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/356118.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Matlab搭建AlexNet实现手写数字识别

Matlab搭建AlexNet实现手写数字识别 个人博客地址 文章目录Matlab搭建AlexNet实现手写数字识别环境内容步骤准备MNIST数据集数据预处理定义网络模型定义训练超参数网络训练和预测代码下载环境 Matlab 2020aWindows10 内容 使用Matlab对MNIST数据集进行预处理&#xff0c;搭建…

基于Spring Boot框架的人事管理系统的设计与实现(程序+详细文档)

大家好✌&#xff01;我是CZ淡陌。这里为大家分享优质的实战项目&#xff0c;本人在Java毕业设计领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目&#xff0c;希望你能有所收获&#xff0c;少走一些弯路&#xff01; &#x1f345;更多优质项目&#x1f447;&am…

面向六部十层电梯群控算法的研究

面向六部十层电梯群控算法的研究 赵大权&#xff0c;张翔宇 &#xff08;晋中学院 机械学院&#xff0c;山西 晋中 030619&#xff09; 摘 要&#xff1a; 在商业大楼和高层写字楼里&#xff0c;基于可编程逻辑控制器&#xff08;PLC&#xff09;对电梯运行进行控制是当前主流…

【LeetCode】剑指 Offer(4)

目录 写在前面&#xff1a; 题目&#xff1a;剑指 Offer 10- I. 斐波那契数列 - 力扣&#xff08;Leetcode&#xff09; 题目的接口&#xff1a; 解题思路&#xff1a; 代码&#xff1a; 过啦&#xff01;&#xff01;&#xff01; 题目&#xff1a;剑指 Offer 10- II. …

河南工程学院2.17蓝桥杯培训

乘法口诀数列&#xff1a;https://www.acwing.com/problem/content/3466/ 剪绳子&#xff1a;https://www.acwing.com/problem/content/68Sin SinSine之舞&#xff1a;http://lx.lanqiao.cn/problem.page?gpidD5272 数列&#xff1a;https://www.acwing.com/problem/content/…

【郭东白架构课 模块一:生存法则】13|法则六:如何鉴别文化环境是否有利于架构师的生存?

你好&#xff0c;我是郭东白。 架构师通常并不管理团队&#xff0c;而是管理架构活动。更准确地说&#xff0c;是定义和引导架构活动。因为每个参与架构活动的个体&#xff0c;都有各自工作的优先级和汇报关系。因此在没有管理、考核和激励等手段的保障下&#xff0c;唯一能够…

Chrome 又不支持 HTTP/2 网站的原因

导读昨晚偶尔清理 Chrome 插件时发现我的 “HTTP/2 and SPDY indicator”插件好像好久没亮了。这个插件在你访问到一个支持 HTTP/2 &#xff08;或之前的 SPDY 协议&#xff09;的网站时会点亮&#xff0c;而我明明记得之前专门让 https://linux.cn/ 支持了 HTTP/2 。 我的第一…

软考高级-信息系统管理师之整体管理(最新版)

整体管理 1、项目整体管理概述2、制定项目章程(选择,案例,论文)制定项目章程过程制定项目章程的依据1、协议2.项目工作说明书:3、商业论证4、事业环境因素包括,但不限于如下事项。5、组织过程资产:项目选择方法项目启动会议项目目标引导技术3、制订项目管理计划(选择)项目管…

MakeFile编写 使用

目录 1、基本格式如下&#xff1a;2、GCC编译过程3、Makefile具体流程可参考下图&#xff1a;4、Makefile变量解析![在这里插入图片描述](https://img-blog.csdnimg.cn/50fdafadef79400abea65b64a12f8ec8.png)5、实例项目目录5.1 使用g直接编译5.2 Version 15.3 Version 25.4 V…

[oeasy]python0086_ASCII_出现背景_1963年_DEC_PDP系列主机_VT系列终端

编码进化 回忆上次内容 上次 回顾了 字符编码的新陈代谢 ibm 曾经的EBCDIC 由于 字符不连续导致 后续 出现无数问题 随着 网络的发展 数据交换的 需要原来的小隐患现在 产生了 巨大问题 Bemer 联合各方巨头 想要推出 字符连续的编码集 这新编码集 具体长什么样 呢&#xff1…

springmvc绿植培养交流平台java的ssm设计与实现

本绿植培养交流平台设计与实现以SSM作为框架&#xff0c;B/S模式以及MySql作为后台运行的数据库。本系统主要包括以下功能模块&#xff1a;个人中心、用户管理、品种类型管理、绿植信息管理、视频分类管理、视频信息管理、经验交流、系统管理等模块&#xff0c;通过这些模块的实…

Java之动态规划之机器人移动

目录 0.动态规划问题 一.不同路径 1.题目描述 2.问题分析 3.代码实现 二.不同路径 II 1.题目描述 2.问题分析 3.代码实现 三.机器人双向走路 1.题目描述 2.问题分析 3.代码实现 0.动态规划问题 动态规划(Dynamic Programming)算法的核心思想是:将大问题划分为小问…

九龙证券|连续七周获加仓,四大行业成“香饽饽”!

本周17个申万职业北上资金持股量环比增加。 北上资金抢筹铝业龙头 本周A股商场全体冲高回落&#xff0c;沪指收跌1.12%&#xff0c;深成指跌2.18%&#xff0c;创业板指跌3.76%。北上资金周内小幅净流入。在大盘体现较差的周四周五&#xff0c;北上资金别离逆市回流67.94亿元、…

Vue项目创建首页发送axios请求

这是个全新的Vue项目,引入了ElementUI 将App.vue里的内容干掉,剩如下 然后下面的三个文件也可以删掉了 在views文件下新建Login.vue组件 到router目录下的index.js 那么现在的流程大概是这样子的 启动 写登陆页面 <template><div><el-form :ref"form"…

blackduck issue fix

文章目录场景依赖包风险扫描插件——synopsys codesight安装其他工具snyk公司提供/允许的工具指定依赖版本场景 你在一个前端nodejs项目中使用到了好多个依赖包&#xff0c;其中某几个依赖包的某些版本是有风险的。 在项目上线前&#xff0c;你最好修复这些安全风险。这时&…

SVN 获取多版本间的更新内容

文章目录背景介绍操作步骤 - 获取某段时间内的代码更新内容背景介绍 公司有个项目期初明确要做微信小程序&#xff0c;没有做其他端的意向&#xff0c;并且当时团队人数有限&#xff0c;没有项目实践过 uniapp&#xff0c;项目时间周期紧&#xff0c;就没有用 uniapp 去实现 然…

Linux架设魔兽争霸3战网Battle.net私服

文章目录 用到的工具pvpgnpvpgn-support-1.2Warcraft 3 Loader for PvPGNBNetEditor.exe搭建服务端魔兽争霸3登录战网私服添加战网服务器地址使用Warcraft 3 Loader启动魔兽争霸3工具下载用到的工具 pvpgn PvPGN是一款免费开源的跨平台服务器软件,支持Battle.net和Westwood …

SpringSecurity源码分析(一) SpringBoot集成SpringSecurity即Spring安全框架的加载过程

Spring Security是一个强大的并且高度可定制化的访问控制框架。 它基于spring应用。 Spring Security是聚焦于为java应用提供授权和验证的框架。像所有的spring项目一样,Spring Security真正的强大在于可以非常简单的拓展功能来实现自定义的需求。 在分析SpringBoot集成的Spri…

张晨光-JAVA零基础保姆式技术教程之-事务

事务 课程目标 1、什么是事务 2、jdbc如何控制事务 3、设置事务的回滚点 4、事务的特性ACID 5、数据库事务的隔高级别事务理解 什么是事务&#xff1a; 指逻辑上一组操作&#xff0c;要么同时成功&#xff0c;要么同时失败。 举例&#xff1a; 转账 a 给b 转账 100 a原来有…

React Native Cannot run program “node“问题

概述 前几天mac重装系统了&#xff0c;用Android studio重新构建React native项目时&#xff0c;报Cannot run program "node"错误。 电脑系统为macOS 12.6.3 (Monterey)&#xff0c;M1 Pro芯片。设备信息如下图所示&#xff1a; 完整错误信息如下图所示&#xff…