MoreRSS

site iconZhangXinXu | 张鑫旭修改

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

Inoreader Feedly Follow Feedbin Local Reader

ZhangXinXu | 张鑫旭的 RSS 预览

JS拖拽交互必用setPointerCapture方法

2026-11-06 17:51:24

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

一、还在mousedown个棒槌

关于拖拽的文章,我之前写过至少两三篇,之前实现逻辑都是这样。

一个拖拽标志量,一个存储数据的变量。

mousedown后标志量开启,存储初始数据,
然后在document文档上绑定mousemove,实时计算位置。
等mouseup后再恢复和处理。

用了很多年,自我感觉也挺好的,眼睛闭着都能手写出来。

实际上,上面这套实现已经过时了,且过时很久了。

现在还在使用mousedown实现拖拽效果,那就是个棒槌了。

应该使用pointerdown、pointerup这类事件(PC、Mobile双通),同时,移动的事件也不需要绑定在document或者<body>元素上了,直接写在触发元素上即可!

有人会问了,要是拖动太快,鼠标从触发元素上移出,岂不是pointermove事件不会触发?

是有这个问题,不过,此事件在设计的时候就考虑到这种场景了,于是设计了setPointerCapture方法,专门针对此问题。

二、setPointerCapture与拖拽

setPointerCapture可以捕获事件的pointerId,在鼠标或手势释放之前,后续所有事件都将以该捕获元素为目标。

所以拖拽的时候,不要担心目标元素会丢失。

眼见为实,直接看案例,假设一个球是ball:

<div class="ball" id="ball"></div>

那么所有拖拽事件都可以绑定在 ball 元素上,通过setPointerCapture捕获,不要担心拖拽行为那么容易丢失。

JS代码参考示意:

let dragging = false;
let offsetX = 0;
let offsetY = 0;

ball.addEventListener("pointerdown", function (event) {
    dragging = true;
    // 最关键代码就是我
    ball.setPointerCapture(event.pointerId);
    ...
});

ball.addEventListener("pointermove", function (event) {
    if (dragging == false) {
        return;
    }
    ...
});

const stopDrag = function (event) {
    dragging = false;
    if (ball.hasPointerCapture(event.pointerId)) {
        ball.releasePointerCapture(event.pointerId);
    }
};

ball.addEventListener("pointerup", stopDrag);
ball.addEventListener("pointercancel", stopDrag);
ball.addEventListener("lostpointercapture", stopDrag);

鼠标或手指按下的时候setPointerCapture,抬起的时候释放releasePointerCapture,就可以完成体验流畅的拖拽效果啦。

眼见为实,您可以狠狠地点击这里:setPointerCapture实现小球拖拽demo

小球拖拽截图

演示效果是AI生成的,虽然不是我的UI美学风格,但是算了,省心啊,嘿嘿😋。

三、在唠叨点什么,水些字数

哎呀,内容有点少了,再水些内容吧。

说到Pointer,我不自觉又联想到了requestPointerLock,这个是用来实现无限滚动的,属于JS Pointer Lock的内容,之前写文章介绍过:鼠标无限移动 JS API Pointer Lock简介

CSS的pointer-events:none可以干掉JS pointer相关的事件,不过却阻止不了focus交互。

还有啥,好有啥,我想想……

哦,还有个touch-action,与触摸有关的,可以阻止滚动啥的,可以防止自怼拖拽和原生滚动冲突。

然后老的setCapture()方法已经废弃了,万不可使用。

噢啦,差不多就这么多了。

感谢大家的阅读,周末愉快,祝我爆护。

这是我上周末钓的,168五小时,钓得都铺出来了,😁😁。

鳊鱼爆护

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

(本篇完)

懒加载图片新支持了sizes=”auto”属性,其作用是?

2026-10-30 19:47:48

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

一、一步到位

一句话:sizes="auto" 是给懒加载图片用的新特性,浏览器不再需要你手写媒体查询,会自动读取图片布局后的实际渲染宽度,去 srcset 里挑选最合适尺寸的图片。

关于srcset属性,我在之前的文章(响应式图片srcset全新释义sizes属性w描述符),以及我写的《HTML并不简单》这本书里面都有过详细的介绍。

比方说下面这段HTML代码:

<img src="128px.jpg"
  srcset="128px.jpg 128w, 256px.jpg 256w, 512px.jpg 512w"
  sizes="(max-width: 480px) 100vw, 480px">

我问你,iPhone6下加载的是哪张图片?渲染的宽度是多少?

有谁回答的上来!

需要知道iPhone6的屏幕密度,需要知道他的尺寸,然后计算使用哪个规格的图片。

麻麻批的,我自己都看不懂,虽然这段代码是我自己写的。

这就是为何,从业十几年,我从来没有在哪个国内的项目见谁用过srcset和sizes属性。

太复杂,太啰嗦,所以,大家都是直接2倍图,3倍图一把梭,反正用的是公司流量。

现在情况有变,在某些条件下,开发者无需去关注sizes的media查询细节了,直接sizes="auto"就可以了,浏览器会自动选择合适尺寸的图片去加载。

那这个条件是什么呢?为什么浏览器可以自动选择尺寸?

二、既然是懒加载?

这个条件就是图片需要设置loading="lazy"。

设置了懒加载的图片默认不是立即加载的,对吧,需要图片元素滚动到视口,或者接近视口的时候(与网速、屏幕尺寸等有关)才开始加载。

此时页面的 CSS 早就解析完毕,图片在布局中的准确宽度浏览器早就知道了。

既然尺寸都知道了,那么不就可以后自动匹配对应的srcset资源了?

这就是为何sizes="auto"需要图片是懒加载的原因。

补充说明

图片除了必须是懒加载的,还需要显式指定 width 和 height(或通过 CSS 限制宽高),或者指定一侧高度,然后使用aspect-ratio属性约束好比例。

三、噢啦,就这么点内容

<img sizes="auto" loading="lazy">还是个新特性,我看了下,Safari居然还没有支持:

size=auto兼容性

唉,无所谓了,不支持就不支持吧,反正不影响图片正常显示,到时候src随便给个两倍图就好了。

至于srcset属性的使用窍门那就简单了,原图宽度是多少像素,后面就写多少w,比方说:

<img loading="lazy" 
  sizes="auto" 
  srcset="img-300.jpg 300w, img-600.jpg 600w, img-1200.jpg 1200w" 
  src="img-600.jpg" 
  width="600" 
  height="400"
/>

当然,省流量还有其他更好的方式,比方说jpg格式换成webp,如果条件允许,最好换成avif格式,这个才是兼顾视觉效果和文件大小的王牌格式,同画质下,比webp小20%~30%的体积,和jpg格式相比,更是减半不止。

目前所有主流浏览器都支持avif格式了,大家有兴趣可以多多关注。

比研究srcset这样细节的知识对产品流量的增益大多了。

当然,本文的内容并不是一无是处,反正现在有AI,回头开发的时候,让AI自动生成多尺寸图片(以前多半要手动处理),使用srcset属性调用,也可以。

毕竟以前实现类似东西要烧脑子,现在只要烧token,开发成本不可同日而语。

好了,就说这么多。

顺便汇报下之前说的在线前端课程,已经写到章节2.5了,阅读约莫20~30%的样子吧。

再写几个小节,就可以找编辑看看能不能签约了,谈分成之类的。

股票跌没了,得找点路子赚点零花钱补贴家用了。

太惨了

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

(本篇完)

算了,还是讲下named-feature() @supports规则检测吧

2026-10-26 15:09:37

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

一、一步到位

今天介绍一个特殊的@supports检测函数,那就是named-feature(),目前就下面两个经典用法:

/* 检测:锚点定位是否感知 transform(transform后锚点位置跟着变) */
@supports named-feature(anchor-position-follows-transforms) {
  /* 支持该行为时,启用高级锚点布局 */
  .tooltip {
    position: anchor(--btn);
  }
}

/* 检测单轴滚动容器能力 */
@supports named-feature(single-axis-scroll-container) {
  .scroll-x {
    overflow-x: auto;
    overflow-y: clip;
  }
}

有别于之前的(property: value)属性检测、selector(:has())选择器检测、at-rule(@container) AT规则检测。

这里的named-feature()检测的函数参数是CSS规范里显式登记的特殊名字。

二、为何需要?

先说anchor-position-follows-transforms。

锚点定位 anchor() 有一个大坑,那就是部分旧版实现,元素做 transform 之后,锚点是坐标不会跟着更新的。

锚点定位是非常强悍的CSS特性,很好用,好用的不得了,有兴趣可以访问我之前的文章:全新的CSS Anchor Positioning锚点定位API

如果使用传统语法检测,比方说@supports (position: anchor()),结果只能检测浏览器认识 anchor 语法与否,并不能检测transform定位bug浏览器是否修复。

所以,就必须用 named-feature(anchor-position-follows-transforms) 判断行为是否符合预期,以此区分两套实现逻辑,避免 UI 错位。

那single-axis-scroll-container呢?

说起单轴滚动,就不得不提我上个月写的这篇文章:一个视频彻底看懂CSS scroll-axis-lock none的作用

虽然都是轴滚动相关的特性,但这里的检测背景和作用与之还有所不同,这个值得展开说说。

三、单轴溢出的问题

比方说设置一个表格可以水平和垂直滚动,结构如下:

<div class="table-wrapper" style="overflow-x: auto;">
  <table>
    …
  </table>
</div>

然后希望表头和第一列粘性定位:

.table-wrapper thead {
  position: sticky;
  top: 0;
}

/* 第一列也粘性定位*/
.table-wrapper td:first-child {
  position: sticky;
  left: 0;
}

结果怎么着,水平滚动是有粘性定位效果的,但是垂直滚动就没有。

为何?

这是一个“次轴无法被彻底裁剪”历史遗留问题。

长期以来,CSS overflow 的组合存在限制。

如果你设置了 overflow-x: auto,哪怕将 overflow-y 显式设为 clip 或 hidden,浏览器在底层计算滚动上下文时,仍然会将该容器视为两个轴向都能滚动的容器(或者说,计算逻辑仍会将其视为 overflow-y 产生了滚动边界)。

插播一下,如果不知道overflow:clip的作用,可以看我很多年前写的这篇文章:CSS overflow-clip-margin属性简介

于是乎,大表格的粘性定位就成了受害者。

浏览器会误认为该外层容器在 Y 轴也是滚动容器,从而导致表头被困在外层容器中,无法跟随页面垂直滚动条实现粘性固定(这句话不理解也没关系,AI时代了,细节原理不重要了)。

效果见下面录屏示意(不动点击播放),左侧是有问题的,右侧是目标效果,左侧可以看到本该粘性定位的表格头直接被滚走了。

停顿了片刻……

算了,还是有不少好学的小伙伴的,上面这句话再通俗解释下吧。

就是我特么的只设置了水平滚动,垂直方向我压根没有任何滚动,你不能傻乎乎的看到我是个滚动容器,就不让我垂直方向的表头无法粘性定位吧!

PS:粘性定位的启动点计算是根据第一个滚动容器来的,详见此文:深入理解position sticky粘性定位的计算规则

为了解决该问题,CSS 规范进行了修订,允许 overflow-x: auto 与 overflow-y: clip(或通过简写 overflow: auto clip)配对时,容器仅充当单轴(X轴)滚动容器。

此时,Y 轴的 position: sticky 就可以绕过该容器,正确地去跟踪文档(页面)的垂直滚动条。

根据我从chrome开发者官方页面看到的数据,貌似是Chrome 154开始支持的。

而为了检测浏览器是否开始了单轴滚动的支持,就需要用到这里的named-feature(single-axis-scroll-container)检测。

为什么不能直接用 @supports (overflow: auto clip)?

  • 如果仅用 @supports (overflow: auto clip),浏览器只会检查自己能不能解析这个语法。
  • 很多旧版本浏览器虽然能解析这个语法,但其底层的滚动上下文计算机制仍然是旧的,并不会正确处理修订后的单轴滚动逻辑。

所以这里才需要@supports named-feature(single-axis-scroll-container)检测浏览器是否已经支持了overflow:clip与浏览器单轴滚动。

如果不支持,我们可以使用JS打个补丁,或使用其他策略修复。

演示页面

对了,演示页面差点忘记了,如果你的浏览器Chrome版本154及其以上,可以狠狠地点击这里:CSS单轴滚动容器的怪异行为以及修复demo


四、结语碎碎念

named-feature()特征检测其实没什么好讲的,因为太小众了,我估计全中国,99.9%的前端都没有机会在实际项目中使用此特性。

那为什么还专门写一篇文章呢?

主要是这两个特征检测背后的故事很有意思,值得念叨。

一般named-feature()特征检测都是检测浏览器之前有某某渲染问题,在之后的版本中修改了策略,或者修复了bug,然后针对这个现象,专门弄个白名单机制一个的特殊名称。

方便开发者更好地对新老特性做兼容。

很好的设计想法。

但是太小众,AI时代的前端开发者普遍没什么学习热情,怎么可能学这种东西,狗都不学。

接下来看下此特性的兼容性,看图:

named-feature()兼容性

哇,好新的特性啊。

星星眼

得,更是没什么学习价值了。

😮‍💨😮‍💨😮‍💨

好,就说这多,我们下周再见!

飞吻再见

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

(本篇完)

Nice!继text-wrap之后,Flex布局也支持balance排版了

2026-10-14 18:24:41

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

一、内联balance排版

3年前有介绍过内联元素的balance排版,就是使用text-wrap:balance声明,很好用,我已经在真实项目中使用了。

可以让居中排版的多行元素每一行的数量尽可能均衡,使视觉效果更好。

balance排版效果示意

眼见为实,您可以狠狠地点击这里:text-wrap:balance实现头像均衡布局demo

目前所有主流浏览器都已经支持,可以放心大胆使用,就算浏览器不支持,也仅仅是传统排版效果而已。

兼容性

更多信息可以访问这里:快速了解text-wrap:balance的作用

好消息!

现在不仅内联元素,块级元素也支持balance排版了,那就是flex-wrap: balance。

二、flex布局balance排版

Flex布局实现balance排版很简单,只需要将传统的flex-wrap:wrap声明替换为flex-wrap:balance就可以了。

来看下效果对比,默认wrap排版会优先前排的宽度,直到宽度放不小,才会换行显示,比方说这般:

默认 wrap 排版示意

如何选择balance排版,则每一行的标签数量会尽可能的均等,于是排版布局效果就会是这样的:

balance排版效果示意

眼见为实,您可以狠狠地点击这里:flex-wrap:balance与Flex布局均衡排版demo

三、flex-line-count指定均衡行数

默认情况下的均衡排版会充分利用容器宽度。

实际上,Flex布局提供了能力,可以指定均衡排版的行数,就是使用flex-line-count属性。

例如:

.container {
  display: flex;
  flex-wrap: balance;
  flex-line-count: 3;
}

那么书籍标签就会三行显示,每行均分两个标签,效果如下图所示:

三行均衡排版效果示意

衍生作用

指定flex-line-count的数量后,我们其实可以很方便的在Flex布局中实现瀑布流布局效果。

指定Flex容器为垂直排版,设置flex-line-count为固定的列表值,此时,无论Flex子项的数量多少,都会瀑布一样的方式往下排版。

大家不妨想想一下上面三行均衡排版图旋转90°之后的效果,如果列表项足够多,是不是就是瀑布流排版呢?

具体示例我就不放出来了,AI时代,大家知道有这么回事就好了。

或者看下面的示意脑补下吧,

瀑布流布局示意

四、兼容性以及若干碎碎念

Flex布局的balance排版的兼容性如下:

balance Flex布局中兼容性

虽然看起来Chrome 150才支持,但并不影响我们的使用,因为某种意义上,此特性是渐进增强特性。

.container {
  display: flex;
  flex-wrap: wrap;
  flex-wrap: balance;
}

如果浏览器支持,那就是balance排版,如果不支持,还保持现在的wrap排版,并不会造成显著的影响。

碎碎念时间

最近突然冒出了个step-5的模型,最近CodeBuddy和WorkBuddy中限免,试用了下,除了思考慢了点,最终效果还可以。

是一家名叫阶跃星辰 – stepFun的公司开发的,以前听都没听过,突然冒出来的,还真是有趣。

说不定什么时候,某个会自学习的AI模型是从其他模型公司突然涌现。

木卫二

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

(本篇完)

Document Picture-in-Picture API与任意元素画中画实现

2026-10-08 18:38:55

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

一、温故而知新

画中画的实现这个2018年的时候就有介绍,乖乖,已经是8年前了,不过那个时候只支持视频元素,可以访问这里了解:video视频播放Picture-in-Picture画中画技术

现在,不仅是视频元素,其他普通元素现在也支持画中画的能力了,就是使用documentPictureInPicture.requestWindow()方法。

在AI时代,我们无需关心具体的API细节。

因此,我不打算介绍各种方法参数,直接上案例。

您可以狠狠地点击这里:普通元素画中画呈现效果demo

点击如下图所示的按钮,就可以看到图片元素的小窗口在显示器的右下方了,即使浏览器最小化,此窗口依然存在。

demo点击画中画按钮示意

进入画中画状态后

之所以进入画中画状态后,背景色从深色变成浅色,是因为加入了@media (display-mode: picture-in-picture)的测试代码。

如下所示:

figure {
    background-color: #333;
    color: #fff;
}
@media (display-mode: picture-in-picture) {
    figure {
        background-color: #f5f5f5;
        color: #333;
    }
}

二、完整代码示意

先看下HTML结构,一个提示元素,一个主体展示元素:

<p id="inPicMsg" hidden>图片信息元素处于画中画状态。</p>
<figure>
    <img src="hanyun.jpg" alt="张含韵">
    <figcaption>画面中这人是谁?</figcaption>
</figure>

<button id="inPicBtn" type="primary" class="ui-button">进入画中画</button>

关键还是交互部分,如下所示:

const figure = document.querySelector("figure");
// 进入按钮和进入提示元素
const inPicBtn = document.getElementById("inPicBtn");
const inPicMsg = document.getElementById("inPicMsg");

inPicBtn.addEventListener("click", function () {
    window.documentPictureInPicture.requestWindow({
        width: figure.clientWidth + 32,
        height: figure.clientHeight + 72,
    }).then(pipWindow => {
        // 添加关闭处理
        pipWindow.addEventListener("pagehide", (event) => {
            inPicMsg.hidden = true;
            inPicMsg.after(figure);
        });
        // 显示提示
        inPicMsg.hidden = false;
        // 创建渲染样式
        const style = pipWindow.document.createElement("style");
        fetch(document.querySelector("link[href^='http']").href)
          .then(response => response.text())
          .then(text => {
            style.textContent = text;
          });
        pipWindow.document.head.append(style, document.querySelector("style").cloneNode(true));
        // 添加目标元素
        pipWindow.document.body.appendChild(figure);
    });
}, false);

// 创建退出按钮
documentPictureInPicture.addEventListener("enter", (event) => {
  const pipWindow = event.window;

  const pipExitButton = pipWindow.document.createElement("button");
  pipExitButton.className = "ui-button";
  pipExitButton.type = "primary";
  pipExitButton.textContent = "退出画中画";
  pipExitButton.addEventListener("click", () => {
    window.documentPictureInPicture.window.close();
  });

  pipWindow.document.body.append(pipExitButton);
});

这段代码处理示意了画中画模式的进入退出,还演示了如何在画中画窗口创建额外的元素以及构建样式。

需要注意的是,我原本打算插入<link>元素,直接链接一个CSS文件,结果发现无效,于是改为fetch CSS数据,使用<style>元素内联实现的。

以及,实际开发的时候,可以使用 async/await 语法减少Promise的嵌套使用。

三、就这些,没什么好说的

画中画的实现其实就那几行代码,然后,画中画小窗口的关闭按钮这些都是可以自定义的,如何自定义使用,到时候让AI模型帮你处理就好了,我就不告诉大家是disallowReturnToOpener这个可选参数了。

接下来,看下兼容性:

画中画API兼容性

Safari浏览器拖了后腿,不过桌面端本身就是Chrome的天下,因此,此特性还是可以大胆使用的,毕竟,就算浏览器不支持,也支持保持现状而已。

好了,就说这么多,博闻强识。

对了,今年开春到现在,都是博客和B站的碎片化输出,打算国庆后到春节前,弄一个前端在线学习的系列课,当然,要与时俱进,不然狗都不看。

拭目以待吧~

拭目以待

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

(本篇完)