MoreRSS

site iconZhangXinXu | 张鑫旭修改

出版《CSS选择器世界》,喜欢钓鱼、写作。
请复制 RSS 到你的阅读器,或快速订阅到 :

Inoreader Feedly Follow Feedbin Local Reader

ZhangXinXu | 张鑫旭的 RSS 预览

超级Web特性HTML-in-Canvas初体验

2026-08-28 18:14:29

by zhangxinxu from https://www.zhangxinxu.com/wordpress/?p=12309
本文可全文转载,但需要保留原作者、出处以及文中链接,AI抓取保留原文地址,任何网站均可摘要聚合,商用请联系授权。

一、等不及了

Chrome 150+之后,可以通过开启#canvas-draw-element特性体验HTML-in-Canvas的神奇效果。

Chrome地址栏输入下面代码可开启:

chrome://flags/#canvas-draw-element

HTML-in-Canvas开启示意

通常Web新特性都都要等浏览器正式支持才介绍。

但是这次的这个特性,实在是等不及了。

在过去,Canvas里面实现元素动效是麻烦的,啰嗦的,往往需要借助第三方的组件。

而CSS实现动画动效非常方便。

现在,有了HTML-in-Canvas,所有的Web动效,包括SVG动效,都可以无缝接入到Canvas中,Canvas的应用能力直接飙升。

比方说HTML原生的<dialog>弹框使用非常方便,于是,过去,WebGL/Canvas 游戏中的弹窗和提示面板就可以直接使用HTML <dialog>元素,而无需像以前一样重写一套游戏 UI 交互:

  1. 游戏外悬浮 DOM:弹窗跟随游戏视口缩放很麻烦;游戏画布拖动缩放时 DOM 同步成本高。
  2. 手写绘图 API 绘制 UI:成本极高,不能复用现有组件库。

又比如HTML转图片这个功能。

之前我们大多使用 html2canvas 这个项目,简单点的会借助SVG <forginObject>元素实现(详见“SVG foreignObject简介与截图等应用”此文)。

但是html2canvas还有不支持CSS锥形渐变,一些CSS混合模式效果不支持的问题。

现在又了HTML-in-Canvas,等于原生有了HTML转图片的能力,既全面,又高性能,html2canvas直接可以说拜拜了。

二、使用非常简单

将HTML绘制在Canvas上的代码非常简单,几行代码的事情。

最核心的一行代码就是:

canvas.getContext('2d').drawElementImage(htmlElement, 0, 0);

就可以了。

Chrome开发者社区提供了很多HTML-in-Canvas的案例:https://chrome.dev/html-in-canvas/

HTML-in-Canvas案例

可以看到,无论是Video视频、Form表单还是iframe内嵌框架,都可以绘制在Canvas画布上。

而且目前主流的前端3D开发框架,如There.js、Pixi.js都已经加入了对HTML-in-Canvas的支持。

所谓实践出真知,看别人写的Demo,不如自己写个Demo。

脑筋一转,不妨试试看能不能把LuLu UI的表单验证直接搬到Canvas画布上。

案例

您可以狠狠地点击这里:HTML in Canvas 绘制LuLu UI表单组件演示页面

可以看到,表单不仅渲染了,特么的自定义的JS验证UI居然也一起带到Canvas里面去了。

真是牛了个大发了!

表单效果与验证提示

相关的代码如下所示:

<canvas id="canvas" style="width: 100%;" layoutsubtree>
<form id="validateForm" is-validate>
    ...略...
</form>
</canvas>
<script>
    const pixelRatio = window.devicePixelRatio || 1;
    const canvas = document.getElementById('canvas');
    const validateForm = document.getElementById('validateForm');
    canvas.style.width = validateForm.offsetWidth + 'px';
    canvas.style.height = validateForm.offsetHeight + 'px';
    canvas.width = canvas.clientWidth * pixelRatio;
    canvas.height = canvas.clientHeight * pixelRatio;

    const ctx = canvas.getContext('2d');

    canvas.onpaint = () => {
        ctx.reset();
        ctx.drawElementImage(validateForm, 0, 0);
    };
</script>

JS主要做两件事情,其一,设置合适的尺寸;其二,渲染。

然后就没有然后了,就这么Easy!

Nice表情包

补充说明

<canvas>元素上设置的layoutsubtree属性是必须的,这个千万不能删除,否则是没有实时渲染效果的。

– 我看到不少案例,包括官方案例,都在表单元素上设置了drawable属性,但是根据自己的实践,此属性不设置似乎不影响效果。但是暂时又没有改属性相关的资料,所以,其最终作用,暂时我也不清楚。

三、好了,暂时就先说这么多

AI编程时代,技术细节没必要深究,加上本身目前兼容性还不太好,我觉得了解这么多就好了。

静待浏览器大规模支持吧!

最后,想问下大家,目前还有哪些前端周刊还在更新的吗❓

发现AI编码来了之后,很多都停更了,难道前端这个行业这是自此不再上进了吗? ​​​

🤔

本文为原创文章,会经常更新知识点以及修正一些错误,因此转载请保留原出处,方便溯源,避免陈旧错误知识的误导,同时有更好的阅读体验。
本文地址:https://www.zhangxinxu.com/wordpress/?p=12309

(本篇完)

卧靠,这是好东西,CSS text-fit属性简介

2026-08-21 18:02:33

by zhangxinxu from https://www.zhangxinxu.com/wordpress/?p=12348
本文可全文转载,但需要保留原作者、出处以及文中链接,AI抓取保留原文地址,任何网站均可摘要聚合,商用请联系授权。

一、从动态font-size标题说起

我博客的每篇文章的标题的font-size都是动态的。

比方说“前端快讯:setHTML()和Element.startViewTransition已支持”这篇文章,可以看到字号明显小(需要PC端查看),如下截图所示:

标题截图

但若是标题文字内容少的文章,那么标题尺寸就会很大!

例如“CSS新单位dvh、lvmin、vi、cqb等初解”这篇文章。

标题字号大示意

为何会有这种区别?

因为我不希望标题换行。

标题字号比较大,一旦换行,排版就很丑陋。

于是,我在PHP输出标题的时候,动态计算了字符数,然后进行了动态设置:

<h2 class="single-h" style="--length:30.533333333333">
  前端快讯:setHTML()和Element.startViewTransition已支持
</h2>
.single-h {
  font-size: clamp(1.25rem, calc(100cqw / var(--length, 20)), 2.4rem);
}

动态尺寸示意

虽然说面前实现了预期的排版效果,但是并不完美。

因为每个英文字符占据的宽度是不一样的,标题使用的并不是等宽字体,导致标题文字并不能充分利用容器宽度。

此需求,一直是我心中的一个刺,扎了自己快10年。

结果,哈哈哈,结果,现在居然有原生了CSS属性可以解决此问题了,哈哈哈!

牛来,哈哈哈

二、text-fit与容器宽度自动适配

如果希望一段长度不固定,但是范围可控的文字,永远一行显示,同时尽可能填满整行,很简单,两行CSS代码的事情,先设置一个足够小的font-size尺寸。

h2 {
  font-size: 12px;
  text-fit: grow;
}

此时,标题正好占满一行容器的宽度,绝赞!

字符充分占据一行

语法

语法如下,支持两种类型的关键字值:

text-fit: <fit-type> <fit-target>

其中:

  • <fit-type>(缩放类型)
    • none:不进行自动适配。
    • grow:放大文本以填满较短的行或空间。
    • shrink:缩小过长的文本防止溢出。
  • <fit-target>(适配目标)
    • per-line:逐行单独计算,让每行各自填满容器。
    • per-line-all:所有行共同参与、强制填满。
    • consistent:整体按统一的缩放比例调整,保持相对一致的字体大小。

案例

<fit-type>类型是很好理解的,毕竟大家都是学过Flex布局的,对flex-growflex-shrink属性肯定有所了解。

比较有挑战的是搞懂<fit-target>类型各个值的区别。

一图胜千言。

如果text-fit的属性值是grow per-line,那么,除了最后一行,前面没一行各自填满容器,如下截图所示:

grow per-line效果

如果是text-fit: grow per-line-all,那么最后一行文案,也会放大到充分利用容器宽度,如下示意图:

pre-line-all效果示意

如果是text-fit: grow consistent,为了确保每一行的字号大小都一样,整个字号的变化其实并不是很明显,不知道下面的对比图大家能否看出区别。

consistent效果对比

估计很难看出来,这样吧,直接实操,我直接把Demo嵌入到了博客页面(RSS阅读器会看不到效果),如果您的浏览器版本足够,可以通过选择下面的下拉框,切身感受text-fit的渲染效果。

Pi 是 Mario Zechner(libGDX 作者、OpenClaw 底层 harness)做的极简终端编码代理,87.3k stars,MIT 协议,最新 v0.84.1。核心工具只有 read/write/edit/bash 等六个,没有内置 plan mode、子代理、MCP、权限弹窗——这些全都靠 TypeScript 扩展、skills、提示词模板和包来补齐。它的设计哲学是「适配你的工作流,而不是反过来」。

缩放类型:

缩放目标:

三、为什么你来得这么晚!

虽然近些年CSS更新了很多文本相关的CSS新特性,但让我眼前一亮的,只有这个 text-fit 属性,因为其实现的排版效果具有JS不可替代性。

也就是无法使用JavaScript代码轻松模拟text-fit 属性所能实现的效果。

可惜啊可惜,特么的来的太晚了,目前仅 Chrome 150版本发布,😭😭😭😭

text-fit属性兼容性

再加上现在大家都氛围编程了,哪怕特性再逆天,也无法在社区激起一丝波澜。

捶足顿胸,你怎么不早来10年了,哪怕5年也好啊!

罢了罢了,自己先玩玩吧,我先把自己博客改造下。

大家有兴趣了,不妨打开控制台,看看我的文章标题是如何设置的。

牛啊

本文为原创文章,会经常更新知识点以及修正一些错误,因此转载请保留原出处,方便溯源,避免陈旧错误知识的误导,同时有更好的阅读体验。
本文地址:https://www.zhangxinxu.com/wordpress/?p=12348

(本篇完)

还在reduce求和吗?该使用Math.sumPrecise()方法啦

2026-08-14 19:20:25

by zhangxinxu from https://www.zhangxinxu.com/wordpress/?p=12345
本文可全文转载,但需要保留原作者、出处以及文中链接,AI抓取保留原文地址,任何网站均可摘要聚合,商用请联系授权。

一、数组求和新方法

之前大家数组求和,肯定多半都是使用的数组的reduce方法.

例如:

const sum = [1, 2, 3, 4, 5, 6].reduce((a, b) => a + b, 0);
// 结果 sum: 21

如下截图所示:

reduce求和示意

在大多数时候,上面的求和计算是没问题的。

但是,如果计算的数值超大,超过了JS的整数范围;或者是小数,就可能出问题。

比方说:

const arr = [0.1, 0.2, 0.3];
// reduce求和
const sum = arr.reduce((prev, curr) => prev + curr, 0);

console.log(sum);   
// 预期:0.6
// 实际输出:0.6000000000000001
const values = [1e20, 0.1, -1e20];

const sum = values.reduce((a, b) => a + b, 0);
console.log("sum", sum);
// 预期:sum 0.1
// 实际:sum 0

这怎么弄?

在过去,开发人员会把数组每一项都乘以100,1000这种,然后再计算,例如:

const sum = [0.1, 0.2, 0.3].reduce((prev, curr) => prev + curr * 100, 0) / 100;
console.log(sum);   
// 预期:0.6
// 实际输出:0.6

或者使用Number.toPrecision()方法对输出值进行精度格式化处理。

例如:

const moneyList = [0.1, 0.2, 0.7, 0.3];
const total = moneyList.reduce((s, v) => s + v, 0);

console.log(total); 
// 预期:1.3
// 实际:1.2999999999999998

console.log(Number(total.toPrecision(16))); 
// 预期:1.3
// 实际:1.3

然而,上面这些方法都不是完全之策,例如 toPrecision() 方法在下面这个案例中就是无效的:

[1e20, 0.1, -1e20].reduce((s, v) => s + v, 0).toPrecision(16)
// 结果还是0.000000000000000 ❌

那怎么办呢?

有没有什么一了百了的方法呢?

有!

那就是Math对象新增的sumPrecise()方法。

一键求和,同时保证精度。

二、数组求和利器Math.sumPrecise()

从今往后,数组求和,再也无需使用reduce()方法了,直接Math.sumPrecise()方法一把梭。

使用非常简单,例如:

const sum = Math.sumPrecise([1, 2, 3, 4, 5, 6]);
// 结果 sum: 21

同时,再也没有小数计算精度不准的问题了。

const sum = Math.sumPrecise([0.1, 0.2, 0.3]);
// 结果 sum: 0.6

超大的整数计算也不会有问题了!

const values = [1e20, 0.1, -1e20];
const sum = Math.sumPrecise(values);
console.log("sum", sum);
// sumTwo 0.1

太棒啦,表情包

三、兼容性、Polyfill与结语

各大浏览器对Math.sumPrecise()方法的支持非常积极,目前领先的几个版本都已经支持。

Math sumPrecise兼容性

对于不兼容的浏览器,可以引入Polyfill代码,参考示意:

if (typeof Math.sumPrecise !== 'function') {
  Object.defineProperty(Math, 'sumPrecise', {
    value: function sumPrecise(items) {
      // 参数校验
      if (items == null) {
        throw new TypeError('Math.sumPrecise requires an iterable argument.');
      }
      if (typeof items[Symbol.iterator] !== 'function') {
        throw new TypeError('Math.sumPrecise: argument is not iterable.');
      }

      var sum = 0;
      var compensation = 0; // Neumaier 补偿值
      var count = 0;
      var hasNegZero = false;
      var hasNonZero = false;

      for (var value of items) {
        var num = Number(value);

        // 任意元素为 NaN,直接返回 NaN
        if (Number.isNaN(num)) {
          return NaN;
        }

        // 任意元素为 ±Infinity,处理无穷大相消问题
        if (!isFinite(num)) {
          if (sum === Infinity && num === -Infinity) return NaN;
          if (sum === -Infinity && num === Infinity) return NaN;
          sum = num;
          hasNonZero = true;
          count++;
          continue;
        }

        // 记录 -0
        if (num === 0) {
          if (!isFinite(sum) || hasNonZero) {
            // 有实际数值时 -0 不影响结果
          } else if (Object.is(num, -0)) {
            hasNegZero = true;
          }
          count++;
          continue;
        }

        hasNonZero = true;

        // Neumaier 补偿求和核心
        var t = sum + num;
        if (Math.abs(sum) >= Math.abs(num)) {
          compensation += (sum - t) + num;
        } else {
          compensation += (num - t) + sum;
        }
        sum = t;

        count++;
        if (count > 2 ** 53) {
          throw new RangeError('Math.sumPrecise: iterable is too large.');
        }
      }

      // 全是零(含 -0)的情况
      if (!hasNonZero) {
        return hasNegZero ? -0 : 0;
      }

      // 有无穷大时,补偿值无意义,直接返回
      if (!isFinite(sum)) {
        return sum;
      }

      return sum + compensation;
    },
    writable: true,
    configurable: true,
  });
}

边界测试用例:

// 精度问题
Math.sumPrecise([0.1, 0.2, 0.3])          // 0.6
Math.sumPrecise([0.1, 0.1, 0.1, 0.1,
                 0.1, 0.1, 0.1, 0.1,
                 0.1, 0.1])                // 1

// 特殊值
Math.sumPrecise([])                        // 0
Math.sumPrecise([-0])                      // -0
Math.sumPrecise([-0, -0])                  // -0
Math.sumPrecise([-0, 0])                   // 0(正零优先)
Math.sumPrecise([Infinity, -Infinity])     // NaN
Math.sumPrecise([NaN, 1])                  // NaN
Math.sumPrecise([Infinity, 1, 2])          // Infinity

// 非数组可迭代
Math.sumPrecise(new Set([1, 2, 3]))        // 6
Math.sumPrecise((function*() {
  yield 0.1; yield 0.2; yield 0.3;
})())                                      // 0.6

补充:与原生规范的差异

原生 Math.sumPrecise(TC39 提案)要求实现完全精确的浮点归约,理论上可以超越 Neumaier 的精度上限(如使用任意精度中间表示)。此 polyfill 在绝大多数实际场景下足够可靠,但对于极端的大数组或数值范围极端悬殊的情况,结果可能与原生实现存在最后一位的差异。

——

好了,就说这么多吧。

大家周末愉快。

周末愉快

本文为原创文章,会经常更新知识点以及修正一些错误,因此转载请保留原出处,方便溯源,避免陈旧错误知识的误导,同时有更好的阅读体验。
本文地址:https://www.zhangxinxu.com/wordpress/?p=12345

(本篇完)

background-clip升级,支持边框或文字应用背景

2026-08-06 20:24:54

by zhangxinxu from https://www.zhangxinxu.com/wordpress/?p=12341
本文可全文转载,但需要保留原作者、出处以及文中链接,AI抓取保留原文地址,任何网站均可摘要聚合,商用请联系授权。

一、渐变边框的实现

在过去,渐变边框的主要实现方法,一是嵌套或伪元素模拟嵌套,二是使用border-image属性,相关实现在“被低估的border-image属性”一文中有介绍。

但是border-image属性实现渐变边框有个知名的弱点,那就是不支持圆角!

渐变边框

如果支持圆角,哪怕border-image属性的语法再难以理解,也还是与应用场景的。

本以为这件事情就到此为止了,没想到峰回路转,background-clip属性升级了,居然可以用来实现边框背景效果了,那自然将边框背景设置成渐变不再话下,需要用到全新的属性值 border-area.

border-area与渐变边框

例如:

<style>
canvas {
  border: 1em solid #0000;
  background: linear-gradient(deepskyblue, deeppink);
  background-origin: border-box;
  background-clip: border-area;
  border-radius: 20px;
}
</style>
<canvas></canvas>

就可以得到如下图所示的圆角渐变边框效果了:

渐变边框效果示意

效果很赞!

这里有一些细节需要说明。

当值border-area值合写的时候,background-origin属性是可以省略的,也就是:

canvas {
  border: 1em solid #0000;
  background: linear-gradient(deepskyblue, deeppink) border-area;
  border-radius: 20px;
}

但是如果分开书写,就必须设置background-origin:border-box,否则按照默认的padding-box渲染,渐变边框的效果会比较奇怪,会像下面这样。

奇怪渐变边框效果示意

兼容性

目前Chrome和Safari都已经支持边框背景图了。

border-area的兼容性示意

二、和border-shape属性配合使用

上上个月介绍了全新的CSS border-shape属性,可以轻松实现不规则边框效果,于是可以强强联合,实现不规则图形的特殊边框效果。

例如:

<style>
.star {
    width: 150px;
    aspect-ratio: 1;
    border: 10px dotted #0000;
    border-shape: polygon(
  50% 5%,
  61.8% 34.5%,
  95% 34.5%,
  68.9% 57.3%,
  79.4% 90.45%,
  50% 69.1%,
  20.6% 90.45%,
  31.1% 57.3%,
  5% 34.5%,
  38.2% 34.5%
);
  box-shadow: 2px 2px 4px #0008;
  background: conic-gradient(from -36deg, 
    deepskyblue 72deg, 
    deeppink 0 144deg, 
    rebeccapurple 0 216deg,
    orange 0 288deg,
    green 0
  ) border-area;
}
</style>
<canvas class="star"></canvas>

此时,就可以得到如下图所示的五角色值都不一样的图像效果了:

五色五角星边框效果示意

三、文本背景也规范化了

除了边框支持背景,文本也支持背景了。

实际上,在Chrome浏览器诞生之初,其就支持background-clip:text了,不过那时候还是私有特性,非Web标准。

现在迎来了好消息,自Chrome 120之后,background-clip:text无需私有前缀了,已经晋升为CSS标准属性了。

文字背景兼容性

于是乎,我们就可以将边框背景和文字背景结合起来使用,实现更加炫酷的按钮效果。

例如:

<style>
.button {
  font-size: 14px;
  padding: 6px 12px;
  border: 1px solid #0000;
  border-radius: 4px;
  color: transparent;
  background: linear-gradient(deepskyblue, deeppink) border-area text, 
    linear-gradient(#fff, #fe000005);
  &:active {
    filter: brightness(0.95);
  }
}
</style>
<button class="button">我是按钮</button>

实时渲染效果如下(需要Chrome 150+):

Nice表情包

四、结语说明

没啥好说的,是个相当实用的特性,要是10年前出现,肯定会有很多讨论,朋友圈也可以看到相关文章的转发。

现在么,就像是路边的石头,无人问津。

最后,炫一下周末的渔获吧。

周六老鬼垂钓农家乐,特价108元8小时,钓了32斤;周日天天渔场,188元6小时,钓了七八十斤,两个鱼护。

渔获展示

本文为原创文章,会经常更新知识点以及修正一些错误,因此转载请保留原出处,方便溯源,避免陈旧错误知识的误导,同时有更好的阅读体验。
本文地址:https://www.zhangxinxu.com/wordpress/?p=12341

(本篇完)

来了来了,Flex/Grid布局的间隙装饰线它来了

2026-08-03 21:20:14

by zhangxinxu from https://www.zhangxinxu.com/wordpress/?p=12316
本文可全文转载,但需要保留原作者、出处以及文中链接,AI抓取保留原文地址,任何网站均可摘要聚合,商用请联系授权。

一、先讲下历史

间隙装饰线其实由来已久,在大多数前端从业人员还未入行的时候就已经支持了,大家如果查看 column-rule 属性的兼容性,会发现极佳。

column-rule兼容性

但是,请注意,column-rule 属性生效是有前提的,那就是只能在Columns布局中有效。

而Columns布局我已经快10年没有在实际项目中使用了。

同时,之前的column-rule 属性所设置的装饰线某种程度上和border属性类似,不能设置缩进,不支持多属性,算不得强大。

所以,column-rule 属性可谓名存实亡。

只有抱紧Flex布局和Grid布局的大腿,column-rule 属性才可以真正迎来春天。

等啊等,等啊等,在2026年的某天,终于,全新的装饰线效果可以在Flex/Grid布局中生效了。

比方说这个演示页面:使用 Gap 装饰实现分屏布局demo

核心CSS代码:

.flex-split {
  gap: 1px;
  column-rule-width: 2px;
  column-rule-style: dashed, solid;
  column-rule-color: #d4d0c8;
  row-rule-width: 2px;
  row-rule-style: dashed, solid;
  row-rule-color: #d4d0c8;
}
@media (width 

于是,在宽屏下,垂直装饰线效果生效:

水平布局下的gap装饰线

手机设备下,则是水平方向的装饰线效果:

水平方向装饰线效果示意

比之前使用伪元素,或者插入分隔线元素实现简单多了。

除了基本的分隔线装饰效果,还顺便带来了众多其他强大的特性,例如支持多属性值、交点处如何中断、间距边缘距离控制、repeat()函数语法、动画支持等。

我们一个一个来看下。

二、多属性值和 repeat() 语法

如今,无论是column-rule属性,row-rule属性,亦或是他们的子属性,都支持同时设置多个值,分别表示从开始到结束各自的分隔线样式效果。

且看一个极为简单的案例,HTML和CSS代码如下:

<ul>
  <li>《CSS世界》</li>
  <li>《CSS选择器世界》</li>
  <li>《CSS新世界》</li>
  <li>《HTML并不简单》</li>
</ul>
ul {
  display: flex;
  flex-direction: column;
  gap: .5em;
  row-rule: 2px dashed, dotted;
  row-rule-color: red, blue, green;
}

此时,可见如下图所示的分隔线效果:

水平分割线示意

我们来看下属性值是如何生效的。

先看row-rule属性。

列表共有四项,所有会有3道分隔线。

  1. 2px dashed显然对应第一条线;
  2. dotted则对应第二条,然后这里的宽度规则和border属性一致,默认都是medium尺寸,也就是3px,因此,这里实际渲染等同于 3px dotter
  3. row-rule/column-rule的多值属性走的是平铺规则。也就是:
    • 如果仅一个值,那所有的gap线都使用该值;
    • 如果是2个值,则两两循环匹配;
    • 更多数量的值一样不断循环平铺渲染。

    所以,这里,第三条线的样式也是2px dashed

再看row-rule-color属性,这个很好理解,三条线分别三个颜色,一次是红蓝绿。

那么问题来了,如果我设置4个颜色值,会怎么样呢?

答案是:不会怎么样,超出数量的属性值会被忽略。

repeat()函数

如果分隔线的数量很多,我们一个一个值去设置,会累死人的,代码也啰嗦,此时可以使用repeat()函数简化我们的属性设置。

比方说下面这个案例:row-rule应用repeat()函数demo

核心CSS代码参见下方:

.flex-settings {
  row-gap: 1px;
  row-rule: 1px solid #243352;
  row-rule-width: repeat(2, 1px), 4px;
  rule-inset-start: 16px;
}

可得到如下图所示的效果,可以看到,风格线的宽度有着 1px 1px 4px 不断循环渲染的效果。

分隔线平铺repeat()函数示意

三、rule-break与交叉中断控制

在一个二维布局中,例如Grid布局,或者设置了flex-wrap:wrap出现换行的Flex布局,同时出现纵向分隔线和横向分隔线是再正常不过的事情。

于是就会出现纵线和横线互相交叉相遇的场景。

默认情况下,两线是相交的,但很多时候,纵横相交的效果并不好快,最好希望互相保留安全距离。

则可以使用CSS rule-break属性,设置rule-break:intersection声明就好了。

请看案例:

<section>
  <canvas></canvas>
  <canvas></canvas>
  <canvas></canvas>
  <canvas></canvas>
  <canvas></canvas>
  <canvas></canvas>
</section>
section {
  display: grid;
  width: 300px;
  grid: 1fr 1fr / 1fr 1fr 1fr;
  gap: 1rem;
  
  canvas {
    aspect-ratio: 1;
    background: deepskyblue;
    width: 100%;
  }
  
  column-rule: solid red;
  row-rule: solid green;
  /* rule-break: intersection */
}

此时可以看到水平方向和垂直方向的分隔线相交了。

分隔线相交示意

此时,我们给section元素设置rule-break:intersection,原本交叉的地方互相留白了,如下截图所示:

交叉避让后的效果

四、分隔线的扩展与收缩

column-rule-insetrow-rule-inset 属性用于控制装饰在间距内的扩展距离。

如果无需区分水平和垂直距离,或者水平和垂直距离一致,也可以直接使用 rule-inset 属性。

默认情况下,rule-inset 属性设置的缩进距离是对称的,如果开发者希望变化的距离是不对称的,那么可以使用以下两个CSS属性。

  • rule-inset-cap:适用于没有交叉间距的端点的距离设置;
  • rule-inset-junction:适用于与其他间距相交的端点的距离设置。

一例胜千言,还是上面的案例,我们分别设置rule-inset-caprule-inset-junction的值,来看看最终的渲染效果。

关键CSS代码如下:

section {
  column-rule: solid red;
  row-rule: solid green;
  rule-break: intersection;
  rule-inset-cap: 5px;
  rule-inset-junction: 20px;
}

可以看到,交叉点位置的缩进极大,而四边的端点缩进为5px,明显小一圈,即所谓的不对称缩进。

不对称缩进示意

无论是rule-inset-cap还是rule-inset-junction属性都支持负值,此时装饰线就不是缩进,而是扩张效果。

另外,如果只是希望调整某一个方向的装饰线的缩放效果,可以加上 column- 或者 row- 前缀,例如 column-rule-inset-capcolumn-rule-inset-junction 属性。

五、分隔线的显示范围控制

还是上面的案例,区别在于Grid布局的子元素只有4项,此时,间隙装饰线的效果就会让人感到困惑。

明明没有元素项,结果却凭空出现了分隔装饰线。

多余的分隔线效果示意

此时就轮到 column-rule-visibility-itemsrow-rule-visibility-items 属性出马了。

如果无需区分方向,则可以使用合写属性 rule-visibility-items,其语法如下:

  • normal(默认):取决于容器类型。根据我的测试,大多数场景下效果和 all 一致。
  • all:规则显示在每个间距中,即使是没有元素的间距也是如此。
  • around:只要存有一个或多个相邻项,间隙线就会显示。
  • between:间隙线仅会出现在两个相邻项之间。

下图示意了 aroundbetween 这两个属性值的区别。

between和around区别

相信还是很好理解的。

六、动画、兼容性与结语

间隙分隔线的宽度、颜色和交叉缩进都是可添加动画效果的,具体不展示,这个懂的都懂,设置transition过渡,自然可以看到效果。

下面说下兼容性,Gap装饰是相当新的一个特性,目前只有Chrome 149+ 浏览器才支持,如下截图所示:

row-rule兼容性

唉,东西虽好,但现在还没命享用啊,等过几年兼容性跟上了,前端圈子还不知道变成什么样子呢!

好了,就说这么多吧。

参考文章:

竹知了

本文为原创文章,会经常更新知识点以及修正一些错误,因此转载请保留原出处,方便溯源,避免陈旧错误知识的误导,同时有更好的阅读体验。
本文地址:https://www.zhangxinxu.com/wordpress/?p=12316

(本篇完)