MoreRSS

site iconZhangXinXu | 张鑫旭修改

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

Inoreader Feedly Follow Feedbin Local Reader

ZhangXinXu | 张鑫旭的 RSS 预览

这个有点屌CSS @container scroll-state容器滚动查询

2025-08-15 18:15:51

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

滚动容器查询封面图

一、温故而知新

在学习本文的scroll-state容器滚动查询之前,大家需要先了解CSS @container容器查询。

详见我之前的文章:“介绍2022年最期待的CSS container容器查询”。

这东西可以检测容器尺寸,并进行响应的布局调整,很强大。

现在,@container容器查询,再次进化,可以识别滚动边缘,让CSS的交互能力更上一层楼。

二、scroll-state容器滚动查询

学习一个新特性最快的方法就是案例。

需求这样的,一段文本,需要用户滚动到底部,提交按钮的禁用样式才会取消。

则我们可以这么处理,HTML如下所示:

<div class="container">
  <p>作者</p>
  <p>zhangxinxu</p>
  ...
  <p>作者</p>
  <p>zhangxinxu</p>
  <footer>
    <button>提交</button>
  </footer>
</div>

CSS如下所示(已省略部分无关键要的代码):

.container {
  height: 300px;
  border: 1px solid;
  container-type: scroll-state;
  overflow: auto;
  /* 底部黏性定位 */
  footer {
    background: #f6f6f6;
    position: sticky;
    bottom: 0;
    text-align: center;
  }
  button {
    width: 100px;
    height: 32px;
    border-radius: 12px;
    background-color: crimson;
    color: white;
    cursor: pointer;
  }
}
@container scroll-state(scrollable: bottom) {
  /* 如果容器可以滚动,则按钮样式禁用 */
  button {
    filter: grayscale(1);
    opacity: .35;
  }
}

实时渲染效果如下所示(Chrome 133+ 浏览器有效果):

作者

zhangxinxu

作者

zhangxinxu

作者

zhangxinxu

作者

zhangxinxu

作者

zhangxinxu

作者

zhangxinxu

作者

zhangxinxu

或者参考下面的GIF动图演示效果:

滚动效果示意

如何使用?

第一步

给滚动容器设置 container-type: scroll-state CSS声明。

第二步

使用@container容器查询判断滚动容器是否可以上下滚动,并进行对应的CSS样式设置。

就这么简单!

无语哥

三、scroll-state查询语法

scroll-state()查询函数支持下面三种类型:

  • scrollable

    当前容器是否可以可滚动(滚动边缘)。

  • snap

    是否滚动到Snap边缘

  • stuck

    查询位置值为sticky的容器是否粘在其滚动容器祖先的边缘。

我觉得这三种都还是挺实用的。

方向值

scrollable是最常用的,我们使用scrollable参数介绍下方位值。

scroll-state(scrollable: value)

其中,value可以是(示意三种类型):

  • top: 上边缘。
  • inline-end: 内联方向边缘,默认是水平方向。
  • y: 垂直方向边缘。

我们用的比较多的就是 topbottom 了。

四、兼容性以及渔获展示

目前滚动容器查询Chrome浏览器支持,兼容性如下图所示:

scroll-state的兼容性

目前还无法大规模使用。

—-

上周末继续探钓。

周六,先是奉贤龙泉钓场,混养塘新塘新水,150元6小时,前三个小时钓法不对路,等于空军,后面三个小时散炮打浮,钓了接近30斤鱼,其中三条花鲢(当场回塘),成功挽尊。
周日去了浦东航头镇的航盛钓场,138元6小时,钓下来都是工程鲫,全场就我一个人,结果口还不错,提前收杆的情况下47斤,成功上岸盘老板。

渔获展示

😉😊😇
🥰😍😘

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

(本篇完)

CSS索引和数量匹配函数sibling-index sibling-count简介

2025-08-07 20:23:26

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

索引数量匹配封面图

一、子元素索引值函数sibling-index()

sibling-index()在多个有规律子元素构建的图形或动画效果的场景下非常实用。

我们来看一个《CSS新世界》这本书的一个案例,演示下如何使用sibling-index()函数简化我们的实现。

案例

先看原来的实现,可以访问这个地址:https://demo.cssworld.cn/new/5/4-3.php

所要实现的就是音波播放时候的波形上下运动的效果效果,静态截图效果如下所示:

波形动画示意

之前的实现代码如下所示,HTML部分:

<div class="loading">
    <i></i><i></i><i></i><i></i>
</div>

CSS代码:

.loading i {
    display: inline-block;
    border-left: 2px solid deepskyblue;
    height: 2px;
    animation: scaleUp 4s linear infinite alternate;
    margin: 0 1px;
}
.loading i:nth-child(2) {
    animation-delay: -1s;
}
.loading i:nth-child(3) {
    animation-delay: -2s;
}
.loading i:nth-child(4) {
    animation-delay: -3s;
}

@keyframes scaleUp {
    to { transform: scaleY(10); }
}

使用的:nth-child伪类与一个一个匹配,现在有了sibling-index()函数,我们的代码就简单多了。

这样:

.loading i {
  display: inline-block;
  border-left: 2px solid deepskyblue;
  height: 2px;
  animation: scaleUp 1s linear infinite alternate;
  margin: 0 1px;
  animation-delay: calc(-0.25s * sibling-index());
}

@keyframes scaleUp {
    to { transform: scaleY(10); }
}

看,代码是不是简单了很多?

无语哥

演示

实时渲染效果如下图所示,目前Chrome 138+以上浏览器有效果。

二、子元素数量函数sibling-count()

sibling-count()函数可以返回当前子元素的数量,用在父元素上。

还是通过案例了解这个函数的作用吧。

这里最近我做的一个需求,要求列表数量无论多少,都是两行展示(如下图所示),有了sibling-count()函数,我们就可以精确制定列数,来实现我们想要的效果。

目标效果示意

如果是垂直流布局,我们可以使用Grid布局和grid-auto-flow属性(参见“CSS grid-auto-flow深入理解”一文)实现。

假设HTML代码为:

<zxx-grid>
  <zxx-item>格子1</zxx-item>
  <zxx-item>格子2</zxx-item>
  ...
  <zxx-item>格子8</zxx-item>
  <zxx-item>格子9</zxx-item>
</zxx-grid>

则CSS代码如下所示,可以保证永远两行:

zxx-grid {
  display: grid;
  border: solid;
  overflow: auto;
  grid-template-rows: 1fr 1fr;
  grid-auto-flow: column;
}
zxx-item {
  width: 100px;
  outline: 1px dotted;
  padding: .5rem;
}

效果如下图所示:

垂直流格子示意

可若是水平流,无论数量多少,都是两行高度,那么sibling-count()函数就特别实用。

实现代码如下所示:

zxx-grid {
  display: grid;
  border: solid;
  overflow: auto;
  grid-template-columns: repeat(round(up, calc(sibling-count() / 2)), auto);
}
zxx-item {
  width: 100px;
  outline: 1px dotted;
  padding: .5rem;
}

结果……结果实现的效果并不是如预期那样……怪了,这可是按照MDN文档的案例写的呀!

竖排了

🤔🤔
🤔🤔

后来一研究,才发现,MDN文档提供的例子是错误的!

sibling-count()函数是用在子元素上的,等同于 element.parentElement.children.length

嗯……那这个函数其实没多少好玩的,估计作用也就是sibling-index()函数相减,计算反向索引值。

或者等宽布局用一用:

ul li {
  width: calc(100% / sibling-count());
}

三、兼容性、结语

目前这两个函数Chrome 138+支持,如下图所示:

sibling-count()兼容性

sibling-count()sibling-index()的值可以使用CSS数学函数计算,如calc()round()函数等。

还能使用content属性直接明文显示数量值。

例如:

ul li::before {
  content: counter(i) "/" counter(N);
  counter-reset: N sibling-count() i sibling-index() 
}

好吧,毕竟兼容性还不是很好,就不说太多了。

继续宋玉长老,看在宋长老的面子上,欢迎点赞,转发!

宋玉

😉😊😇
🥰😍😘

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

(本篇完)

HTML popover再进化 – 新增hint类型提示框

2025-07-31 16:12:55

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

popover hint封面图

一、关于popover=hint

去年年初有介绍HTML popover属性,详见“该使用原生popover属性模拟下拉了”一文。

可以说是弹出浮层最佳解决方案,自动显隐特性,外加顶层特性,非常香。

但是有一个问题,那就是一次最多只能有一个弹出层显示(如果不使用 showPopover() 方法手动设置的话),但是有些轻提示,仅仅是用做信息展示,可以无需关闭之前的弹出层,之前的popover属性能力就不够。

于是,从Chrome 133开始,popover属性新增了属性值hint,表示轻提示,显示的时候不会影响之前的弹出层。

popover hint兼容性示意

二、hint值使用案例

一例胜千言。

我们开看一个hint值使用案例,HTML代码如下所示:

<button popovertarget="datalist">点击我 ▼</button>
<div id="datalist" popover>
  <option>列表1</option>
  <option>列表2</option>
</div>
<!-- 轻提示 -->
<button 
  class="hint" 
  onmouseover="hint.showPopover();" 
  onmouseout="hint.hidePopover();"
>?</button>
<div id="hint" popover="hint">我是轻提示文字内容</div>

我们使用CSS锚点定位,让提示框的位置都跟随按钮(非必须):

[popovertarget="datalist"] {
  anchor-name: --button-anchor;
}

#datalist {
  position-anchor: --button-anchor;
}

[popover] {
  left: anchor(left);
  top: calc(anchor(bottom) + 5px);
  right: auto;
  bottom: auto;
}

.hint {
  anchor-name: --hint-anchor;
}

#hint {
  background: #0009;
  color: #fff;
  position-anchor: --hint-anchor;
}

此时,我们点击第一个按钮,让列表显示,鼠标再经过第2个按钮的时候,第一个列表并未隐藏,如下截图所示:

交互效果截图

如果<div id="hint" popover="hint">这段HTML代码是<div id="hint" popover>,那么鼠标hover问号按钮的时候,前面的下拉列表就会隐藏。

如下GIF录屏示意:

auto会自定隐藏之前的弹出层

需要注意的是,如果点击行为,哪怕浮层设置的是popover="hint",那么先前所有popover="auto"的浮层都会隐藏。

hint适合用在鼠标悬停,focus/blur等事件中,或者直接JS触发的轻提示环境,类似于toast提示效果这种。

三、popover属性值含义

popover属性目前支持3个值:

auto
默认值。浮层在点击的时候,或者出现其他 auto 类型的浮层的时候自动关闭。
hint
最新支持的值。非点击行为触发的浮层显示,不会关闭之前 auto 类型的浮层,但是会关闭其他 hint 类型的浮层。
manual
手动浮层。也就是浮层的关闭需要开发者或者用户手动触发。此值和auto同一时间支持的。

hint值的出现算是补充了某一类交互场景的实现。

四、结语

popover=hint 填补了轻量级提示与模态弹窗间的需求空白,尤其适合需非打断性辅助信息的场景。开发者可通过它减少传统工具提示库的依赖,但需注意渐进增强策略以兼容旧浏览器。

好了,就这些。

最后,如果你觉得本文内容还不错,看在我家宋玉长老的面子上,转发,分享,点赞!

宋玉长老

😉😊😇
🥰😍😘

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

(本篇完)

CSS倒反天罡居然支持if()函数了

2025-07-25 17:52:50

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

CSS if()函数占位图封面图

一、CSS真逻辑函数

CSS之前也支持类逻辑函数,例如数学函数中的min()max(),本质上也是有逻辑的,例如:max(300px, 100vw),表示:

  • 如果100vw的计算宽度大于300px,则最终尺寸300px
  • 否则是100vw的宽度。

现在,CSS支持 if() 函数了,这个是真正意义上的逻辑函数了。

目前,if() 支持三种不同类型的查询:

  • style():样式查询
  • media():媒体查询
  • supports():支持查询

其中,media()supports()查询平时我们使用的机会不多,原因很简单,因为有兼容性更好的传统实现方法。例如,下面的CSS代码片段作用是一样的:

button {
  aspect-ratio: 1;
  width: if(media(any-pointer: fine): 30px; else: 44px);
}
button {
  aspect-ratio: 1;
  width: 44px;
}

@media (any-pointer: fine) {
  button {
    width: 30px;
  }
}

但是后者的兼容性更好,可读性也更好,在目前这个阶段,肯定是优先使用后面的方法。

supports()查询也是类似的:

select {
  opacity: if (
    supports(appearance: base-select): 1; else: 0;
  );
}

等同于:

@supports not (appearance: base-select) {
  select {
    opacity: 0;
  }
}

注意,关键字 else 是在 if() 函数里面的。

但是 style() 样式查询目前仅在if()函数中才有,因此,这个函数才是我们需要重点学习的。

二、style()与CSS变量匹配

style() 样式查询只能查询CSS变量,普通CSS属性是不支持的。

我们来看一个案例,了解下是如何使用的,想了下,昨天用到的一个CSS Sprites定位非常使用此效果。

下图所示的就是素材:

Sprites原图

在过去,我们可能需要对4个元素使用不同的选择器进行处理,现在,可以一把hold住了。

相关代码如下所示:

<label class="label" style="--type: 1">阅篇专家</label>
<label class="label" style="--type: 2">万字周报大师</label>
<label class="label" style="--type: 3">互动急先锋</label>
<label class="label" style="--type: 4">佳作分享达人</label>

此时,只需要一段CSS规则就可以实现所有图标的样式效果了:

.label {
  display: inline-block;
  font-size: 0;
  width: if(
    style(--type: 1): 80px;
    style(--type: 3): 96px;
    else: 112px;
  );
  height: 26px;
  background: url(sprite.png) no-repeat 0 0 / 116px auto;
  background-position-y: if(
    style(--type: 2): -34px;
    style(--type: 3): -68px;
    style(--type: 4): -102px;
    else: 0px;
  );
}

渲染效果如下图所示:

实际渲染结果截图

是不是比过去的代码更加简约了。

三、最大的阻碍兼容性

if()函数虽然很屌很帅气,但是兼容性还不行,目前仅Chrome 137+浏览器支持。

if()函数的兼容性

另外,if()函数式支持嵌套的:

color: if(
  style(--scheme: ice):
    if(
      media(prefers-color-scheme: dark): #caf0f8;
      else: #03045e;
    );
  style(--scheme: fire):
    if(
      media(prefers-color-scheme: dark): #ffc971;
      else: #621708;
    );
  else: black
);

其他就没什么了,静待浏览器全面支持吧。

感谢阅读,宋玉长老希望你转发这篇文章!

宋玉喝茶

😉😊😇
🥰😍😘

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

(本篇完)

JS正则新特性:安全过滤RegExp.escape方法

2025-07-16 15:34:30

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

RegExp.escape静态函数

一、RegExp.escape静态方法

正则对象RegExp新增了一个名为escape()的静态方法,可以对字符串中不安全的,或者可以影响正则匹配的字符进行转义。

这些在正则中具有特殊含义的字符包括,如点号(.)、星号(*)、问号(?)、加号(+)、花括号({})、方括号([])、圆括号(())、竖线(|)和反斜杠()等。

目前所有现代浏览器都已经支持了该特性。

escape正则兼容性

语法

语法比较简单,如下所示:

RegExp.escape(string)

返回转义后的字符串。

转义规则

RegExp.escape()方法的转义规则还比较复杂,像我,之前在生产环境做类似转义处理的时候,只会对正则相关的字符前面加反斜杠处理,但这只是RegExp.escape()方法的规则之一。

这些规则包括:

  • 首字母如果是数字或者字母(如论大小写),都会使用\x转义法表示。例如:
    console.log(RegExp.escape('CSS世界'));
    // 输出:"\x43SS世界"
  • 正则语法字符,就是^, $, \, ., *, +, ?, (, ), [, ], {, }, and | 以及 /会使用添加反斜杠的方式转义。例如:
    console.log(RegExp.escape('好书:CSS选择器世界+CSS新世界'));
    // 输出:"好书:CSS选择器世界\+CSS新世界"
  • 其他一些标点,如,, -, =, <, >, #, &, !, %, :, ;, @, ~, ', `"会使用\x转义法表示。例如:
    console.log(RegExp.escape('日期:2025-07-15'));
    // 输出:"日期:2025\x2d07\x2d15"
  • 具有自己的字符转义序列的字符:\f(U+000C 换页)、\n(U+000A 换行),\r(U+0000D 回车)、\t(U+0009 制表符)和\v(U+000B 行制表)转义后会使用斜杠+字符的表示方法,例如换行:
    console.log(RegExp.escape(`作者
    张鑫旭`));
    // 输出:"作者:\n张鑫旭"
  • 空格字符会转义为\x20
  • 其他非ASCII换行符和空格字符被替换为一个或两个\uXXXX转义序列,表示它们的UTF-16代码单元。
    console.log(RegExp.escape('特殊 空格'));
    // 输出:"特殊\u2005空格"
  • Lone surrogates(孤立代理项)使用\uXXXX转义序列替换。

Lone surrogates补充说明:

在计算机字符串处理中,Lone surrogates(孤立代理项) 是UTF-16编码中出现的无效或未配对的代理项代码单元(surrogate code units),属于Unicode标准中的异常情况。

JS中2024年新增的isWellFormed()和toWellFormed()就是用来检测和处理这类字符的。

以上就是转义规则细节,当然,我们平时使用的时候,并不需要了解这么多。

只需要知道,以后使用 new RegExp()构造正则表达式的时候,里面的字符串都用这里的escape()方法转义一下就可以。

那为何要转义呢?下面通过案例演示下转义的必要性。

二、使用案例

比如说我有一个URL输入框,但是这个输入框只能输入白名单域名的地址:

<input id="input" type="url" name="url">
const arrDomain = ['www.zhangxinxu.com', 'www.cssworld.cn', 'www.canvasapi.cn'];

很多人会想到使用正则实现,例如:

const arrReg = arrDomain.map(domain => {
  return new RegExp(`https?://${domain}(?=/)?`, 'g')
});
// 是否匹配白名单域名
console.log(arrReg.some(reg => reg.test(input.value)));

当我们使用域名进行测试的时候,似乎逻辑都OK,但实际上是有漏洞的,域名中的字符’.’被当做任意字符解析了,因此,如果用户输入的value值是https://www-zhangxinxu.com也会匹配:

const arrDomain = ['www.zhangxinxu.com', 'www.cssworld.cn', 'www.canvasapi.cn'];

const arrReg = arrDomain.map(domain => {
  return new RegExp(`https?://${domain}(?=/)?`, 'g')
});

// 下面返回的是true
console.log(arrReg.some(reg => reg.test('https://www-zhangxinxu.com')));

所以,需要我们对特殊字符进行转义,这就需要用到本文的RegExp.escape()静态方法了。

使用示意:

const arrDomain = ['www.zhangxinxu.com', 'www.cssworld.cn', 'www.canvasapi.cn'];

const arrReg = arrDomain.map(domain => {
  return new RegExp(`https?://${RegExp.escape(domain)}(?=/)?`, 'g')
});

// 下面返回的是false
console.log(arrReg.some(reg => reg.test('https://www-zhangxinxu.com')));

就不会有安全问题了。

当然,我们只是为了实现上述需求,还有更好的做法:

arrDomain.includes(new URL(input.value).hostname);

不过,new URL()解析是有可能会报错的。

此时,我们可以使用浏览器原生的验证能力进行处理,如下:

if (input.validity.valid) {
  console.log(arrDomain.includes(new URL(input.value).hostname));
} else {
  console.log(false);
}

Node环境上面的方法就不适合啦!

三、结语

附上传统转义过滤处理示意:

function escapeRegExp(str) {
  return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
  // $&表示匹配的子串
}

最后总结下:

RegExp.escape是一个极其有用的工具,用于安全地将字符串转换为正则表达式字面量。它通过转义所有特殊字符,防止了正则表达式的意外行为和安全问题。

在处理用户输入或动态构建正则表达式时,使用RegExp.escape是一种安全可靠的最佳实践。

对于需要更高安全性的应用场景,建议结合其他输入验证和清理技术,构建多层次的防御策略。

好了,以上就是本文的全部内容。

我家宋玉长老希望你可以转发此文!

宋玉长老

😉😊😇
🥰😍😘

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

(本篇完)