Houdini,CSS 别样助攻,让你的界面效果更酷炫

认识 Houdini:源自一场”邂逅”

吃饭看书刷视频,修身养性三件套。

这天,我正闲心,所以刷了刷 MDN 的网站。点到Web 开发者指南这页下,看到了一个有点陌生的词汇——CSS Houdini

Houdini,CSS 别样助攻,让你的界面效果更酷炫

我顺着自己的”脑机接口”,翻了翻脑袋里的前端知识库,没什么印象。

没印象没关系,可以现学。

Houdini,CSS 别样助攻,让你的界面效果更酷炫

了解 Houdini:全方位扫描中

Houdini 是一组底层 API,它们公开了 CSS 引擎的各个部分,从而使开发人员能够通过加入浏览器渲染引擎的样式和布局过程来扩展 CSS。它们使开发人员可以直接访问CSS 对象模型 (CSSOM),使开发人员可以编写浏览器可以解析为 CSS 的代码,从而创建新的 CSS 功能,而无需等待它们在浏览器中本地实现。

“一组”、”它们”,根据这些关键词不难看出,Houdini 并非 CSS 的某个特定的属性,想要熟悉 Houdini,并确定实际可应用的业务场景,也要采用不同的学习策略:

先来总结这组 API 的共性,再逐个认识每一个的特点,根据各自的特别,联想到不同的展示效果。

Houdini 的特点

我从 MDN 对 Houdini 的大段大段的介绍文档中,提炼了一下 Houdini 的特点:

  • 使用 Houdini,当样式改变时,浏览器可以解析的更快;
  • 可以使用 JavaScript 动态修改 CSS 样式;
  • 可以通过 Worklet 创建模块式的 CSS,也能够访问元素的自定义属性,而非作为函数参数传递。

这么看,Houdini 对 CSS 的操作确实够强。

Houdini 的 APIs

以下为 MDN 中罗列的 APIs:

Houdini,CSS 别样助攻,让你的界面效果更酷炫

我也搜了一下,另外一个有”W3C”标识的网站,APIs的介绍稍微有些出入,感兴趣的可做详细了解

Houdini,CSS 别样助攻,让你的界面效果更酷炫

Houdini VS CSS-in-JS

除了 Houdini 提供的 APIs 的用途,我还关心的一点是,Houdini 与 CSS-in-JS 的差异。换句话说,我挺关心,实际业务场景中具体应该采用哪种方式来操作 CSS。

CSS-in-JS 是一种将 CSS 维护在 JavaScript 中的技术方案。从被提出到现在,CSS-in-JS 已经拥有了众多方案。

两者都支持在 JavaScript 修改 CSS,但是方式不同:

  • Houdini 提供的 Typed OM API 可以在 JavaScript 中直接访问类型化JavaScript对象的 CSS 的值,进行读取和写入;
  • CSS-in-JS 的方案中,是在 JavaScript 文件中定义一系列的CSS属性,然后被引入到页面,解析之后,会把对应的 CSS 样式通过 style 标签的形式插入到该页面的 Head 中。

如何选择开发方案,可以借鉴MDN 备注中的这段话:

在 Houdini 的帮助下你能够在 css 中实现你自己的布局、栅格、或者区域特性,但是这么做并不是最佳实践。CSS 工作组已经做了许多努力来确保 CSS 中的每一项特性都能正常运行,覆盖各种边界情况,同时考虑到了安全、隐私,以及可用性方面的表现。

熟悉 Houdini:代码一上手,就知有没有

代码实验开始前,先讲一个我遇到的阻塞性的问题—— Chrome 浏览器跨域。

在使用”CSS.paintWorklet.addModule”引入本地 JS 文件之后,Chrome 浏览器出现了跨域报错。

因为是 Mac 本,所以我采用的解决方案是:

使用命令打开一个支持设置”–disable-web-security”的浏览器页,命令如下:

open -n /Applications/Google\ Chrome.app/ --args --disable-web-security --user-data-dir=/Users/你电脑的名称/Documents/MyChromeDevUserData

实例1:简历模版同款背景装饰

UI 展示效果

我记得之前下载的简历模版中,有一款的标题装饰像梳子的齿,大致展示效果如下图:

Houdini,CSS 别样助攻,让你的界面效果更酷炫

Painting API 搞定绘制

上面思维导图中有 Painting API 的介绍:

该 API 允许开发者通过 paint() 方法书写 JavaScript 函数,以控制绘制元素的背景、边框或者内容区域。

使用 Painting API 可以创建复杂、有趣的图像。

注:该展示效果在 MDN 上有同款

paint()

介绍 它是一个CSS函数,用于定义了使用PaintWorklet生成的<image>值。
语法 paint(workletName, …parameters)
属性 workletName:注册的worklet的名称parameters:要传递到paintWorklet的可选附加参数

paint worklet

registerPaint(
  'headerHighlight',
  class {
    static get inputProperties() {
      return ['--highColor'];
    }
    static get contextOptions() {
      return { alpha: true };
    }

    paint(ctx, size, props) {
      /* set where to start the highlight & dimensions */
      const x = 0;
      const y = size.height * 0.3;
      const blockWidth = size.width * 0.33;
      const highlightHeight = size.height * 0.85;
      const color = props.get('--highColor');

      ctx.fillStyle = color;

      ctx.beginPath();
      ctx.moveTo(x, y);
      ctx.lineTo(blockWidth, y);
      ctx.lineTo(blockWidth + highlightHeight, highlightHeight);
      ctx.lineTo(x, highlightHeight);
      ctx.lineTo(x, y);
      ctx.closePath();
      ctx.fill();

      /* create the dashes */
      for (let start = 0; start < 8; start += 2) {
        ctx.beginPath();
        ctx.moveTo(blockWidth + start * 10 + 10, y);
        ctx.lineTo(blockWidth + start * 10 + 20, y);
        ctx.lineTo(blockWidth + start * 10 + 20 + highlightHeight, highlightHeight);
        ctx.lineTo(blockWidth + start * 10 + 10 + highlightHeight, highlightHeight);
        ctx.lineTo(blockWidth + start * 10 + 10, y);
        ctx.closePath();
        ctx.fill();
      }
    } // paint
  },
);

HTML

<h2 class="fancy">教育背景</h2>
<h2 class="fancy">工作经历</h2>
<h2 class="fancy">自我评价</h2>

设置CSS

.fancy {
  background-image: paint(headerHighlight);
  --highColor: hsl(155 90% 60% / 0.7);
}
.fancy:nth-child(2) {
  --highColor: hsl(255 90% 60% / 0.5);
}
.fancy:nth-child(3) {
  --highColor: hsl(355 90% 60% / 0.3);
}

注册 worklet

<script>
  CSS.paintWorklet.addModule('header-highlight.js');
</script>

实例2:渐变的渐变背景

UI 展示效果

Houdini,CSS 别样助攻,让你的界面效果更酷炫

properties and values API 搞定绘制

HTML

<button class="registered">Background Registered</button>
<button class="unregistered">Background Not Registered</button>

CSS

.registered {
  --registered: #c0ffee;
  background-image: linear-gradient(to right, #fff, var(--registered));
  transition: --registered 1s ease-in-out;
}

.registered:hover,
.registered:focus {
  --registered: #b4d455;
}

.unregistered {
  --unregistered: #c0ffee;
  background-image: linear-gradient(to right, #fff, var(--unregistered));
  transition: --unregistered 1s ease-in-out;
}

.unregistered:hover,
.unregistered:focus {
  --unregistered: #b4d455;
}

button {
  height: 40px;
  display: block;
  width: 300px;
  font-size: 16px;
  margin-bottom: 10px;
}

JavaScript

<script>
  if (CSS.registerProperty) {
    CSS.registerProperty({
      name: '--registered',
      syntax: '<color>',
      inherits: false,
      initialValue: 'red',
    });
  }
</script>

小结

1、使用 Painting API 绘制图形,最后有些 Canvas 的基础。实现时,会用到 Canvas 的 API。

2、有些过渡效果无法直接实现,比如背景渐变动画,这个时候自定义属性就派上用场了。properties and values API 便支持自定义 CSS 属性。

总结

Houdini 的功能确实强大,让界面效果更加炫酷,但是有一定的学习成本和兼容性问题,所以需要根据实际情况确定采用何种方案。


作者介绍

非职业「传道授业解惑」的开发者叶一一。

《趣学前端》、《CSS畅想》等系列作者。华夏美食、国漫、古风重度爱好者,刑侦、无限流小说初级玩家。

如果看完文章有所收获,欢迎点赞👍 | 收藏⭐️ | 留言📝。

原文链接:https://juejin.cn/post/7242333187250569275 作者:叶一一

(1)
上一篇 2023年6月9日 上午10:05
下一篇 2023年6月9日 上午10:17

相关推荐

发表回复

登录后才能评论