2025-11-17 15:48:36
by zhangxinxu from https://www.zhangxinxu.com/wordpress/?p=11897
本文可全文转载,但需要保留原作者、出处以及文中链接,AI抓取保留原文地址,任何网站均可摘要聚合,商用请联系授权。
Web Components组件开发又新增新特性,为:state()伪类函数。
4年多前,有介绍过::part()伪元素函数,可以穿透组件内部,对里面的样式进行设置。
详见这篇文章:“使用::part伪元素改变Shadow DOM的CSS样式”
而:state()伪类函数,则是穿透组件内部,匹配状态进行样式设置。
你可以理解为,::part()伪元素函数更像是 [disabled] 这种属性选择器,需要内部HTML有对应的属性设置(通过设置part属性)才能匹配,但是:state()伪类函数更像是 :disabled 这类伪类选择器,看中的是元素的真实状态,而非是否有这个属性。
那如何给组件设置状态,让:state()伪类函数匹配呢?这个就需要用到今年年初介绍的attachInternals方法。
可以访问这里了解:“研究下attachInternals方法,可让普通元素有表单特性”
例如:
const someInternals = someCustomElement.attachInternals()
而这个someInternals就是个ElementInternals对象,其包含一个名为states的属性(见下图)。

states属性的返回值是一个CustomStateSet对象,包含以下一些属性和方法:
// 属性 CustomStateSet.size
// 方法 CustomStateSet.add() CustomStateSet.clear() CustomStateSet.delete() CustomStateSet.entries() CustomStateSet.forEach() CustomStateSet.has() CustomStateSet.keys() CustomStateSet.values()
我们日常开发,用的比较多的讲就是add()方法添加状态,delete()方法删除状态。
一例胜千言,让我想想,弄个什么案例好呢……要经典,又要具有代表性,嗯……算了,随便示意下效果吧。
JS和CSS代码如下所示:
class UiLoading extends HTMLElement {
constructor() {
super();
const internals = this.attachInternals();
this.addEventListener('click', () => {
internals.states.add('loading');
setTimeout(() => {
internals.states.delete('loading');
}, 3000);
});
}
connectedCallback() {
this.click();
}
}
// 定义自定义组件
if (!customElements.get('ui-loading')) {
customElements.define('ui-loading', UiLoading);
}
ui-loading {
display: inline-grid;
place-items: center;
width: 150px; height: 150px;
border: 2px dashed;
}
ui-loading:state(loading) {
border-color: red;
background: lightgreen;
}
此时,只要页面上有 <ui-loading> 元素,就可以看到样式变化了。
默认是绿底红框,几秒钟时候,就是黑框了。
实时效果如下所示,如果看不到效果,请点击下面的框框。
可以看到,:state()函数的设计初衷就是为了方便暴露组件内部的状态。
例如,选中与否,失败与否,加载与否等。
CSS :state()伪类函数在2024年5月份的时候,已经被所有现代浏览器都支持,大规模应用的时机还不成熟,不过不得不说,这个东西可以提高组件开发的档次感(虽然part属性和::part()函数也能实现类似效果,但没有这个看起来高大上)。

:state() 伪类是未来 Web 组件样式化的一个强大且语义化的工具。它将样式控制的逻辑从“如何渲染”(暴露内部部件)转变为“在什么状态下渲染”,使得组件开发者能更好地封装内部结构,同时为组件使用者提供清晰、强大的样式定制能力。
昨天遇到个难受的事情,我鱼竿包里翻来覆去,我的一根鱼竿不见了,达亿瓦一击枫,是我买的价格比较高的杆子之一,用了很多年了,也比较有感情了。
思来想去,是上周在情人谷垂钓园钓鲫鱼的时候,没有及时收起来,搁在了河边,走的时候,只收了另外一只杆子,同时损失的还有一只浮漂。
好难受,钓鱼这么多年,还是头一次丢杆子。
打电话给老板,老板也没见到,估计被人捡走了。
郁闷!
鱼没有钓到几条,杆子没了,我都不敢告诉家里人,不然又要吐槽丢三落四,只能悄悄又买了个新杆子。
舍不得买贵的,就买了个200不到的,唉……

本文为原创文章,会经常更新知识点以及修正一些错误,因此转载请保留原出处,方便溯源,避免陈旧错误知识的误导,同时有更好的阅读体验。
本文地址:https://www.zhangxinxu.com/wordpress/?p=11897
(本篇完)
2025-11-10 17:54:53
by zhangxinxu from https://www.zhangxinxu.com/wordpress/?p=11886
本文可全文转载,但需要保留原作者、出处以及文中链接,AI抓取保留原文地址,任何网站均可摘要聚合,商用请联系授权。
锚点定位去年出来的时候就详细介绍过,参见“全新的CSS Anchor Positioning锚点定位API”,非常强大,非常实用。
能够解决overflow剪裁定位元素的问题,包含自动调整方向,尺寸自动适应等特性。
基本上任何浮层元素之间的定位都不再需要JavaScript代码的参与。
我看了下兼容性,所有现代浏览器目前均已支持。

不过,上述文章更多的理论知识介绍,下面展示下其一个比较基础,但又比较实用的小应用,列表类选项悬停或者选中的跟随动画效果。
直接先看效果,点击下面的单选框(点击文字也可以选中),就可以看到后面有个绿色的勾勾出现,切换的时候,就会动画效果移动过去。
相关的HTML和CSS代码如下所示:
<fieldset class="fieldset">
<legend>博主的钓鱼抖音账号名称是:</legend>
<p>
<input type="radio" id="follow" name="follow" value="1">
<label for="follow">最会钓鱼的程序员</label>
</p>
<p>
<input type="radio" id="follow2" name="follow" value="2">
<label for="follow2">张鑫旭本人</label>
</p>
<p>
<input type="radio" id="follow3" name="follow" value="3">
<label for="follow3">其他</label>
</p>
</fieldset>
.fieldset::before {
content: '✓';
position: absolute;
display: none;
color: green;
transition: 0.5s ease;
position-anchor: --checked;
top: anchor(center);
left: calc(anchor(right) + 5px);
translate: 0 -50%;
}
.fieldset:has(:checked)::before {
display: block;
animation: fade-in 0.2s ease-in-out;
}
.fieldset :checked + label {
anchor-name: --checked;
}
@keyframes fade-in {
0% { opacity: 0; }
100% { opacity: 1; }
}
首先,使用伪元素创建绿色的勾勾,默认隐藏。
当有单选项选中的时候,显示,这里的显示还使用了淡出动画效果。
绿色的勾勾设置锚点定位,定位对象的名称就是--checked。
然后,只需要当单选项选中的时候,设置后面的<label>元素的锚点名称是--checked(anchor-name: --checked),这个勾勾元素,就会自动定位过去。
都坐下,基操勿六。

实时效果如下(如果没有效果,请升级浏览器或者系统):
想了下,还是录了个GIF示意了下:

宽度自动适应,无需JS计算,CSS伪元素创建背景内阴影,无需额外的HTML占用。
完整的代码如下所示:
<menu id="menu">
<li><a href="##">联系博主</a></li>
<li><a href="##">欢迎关注</a></li>
<li><a href="##">点赞</a></li>
<li><a href="##">分享</a></li>
</menu>
CSS部分:
menu {
display: flex;
align-items: center;
list-style: none;
padding: 0;
margin: 0;
background-color: #333;
width: 320px;
/* 动效元素创建 */
&::before {
content: '';
position: absolute;
position-anchor: --anchor-select;
left: anchor(left);
top: anchor(top);
width: anchor-size(width);
height: calc(1.5em + 12px);
transition: .3s ease-in-out;
box-shadow: inset 0 0 8px color-mix(in srgb, lightblue 80%, transparent);
pointer-events: none;
}
li {
flex: auto;
line-height: 1.5;
}
a {
display: block;
padding: 6px 10px;
text-decoration: none;
color: #fff;
text-align: center;
}
:where(&:not(:hover)) .selected,
a:hover {
anchor-name: --anchor-select;
}
}
然后几行JS模拟点击选中的状态:
document.getElementById('menu').onclick = function (e) {
e.preventDefault();
this.querySelector('.selected')?.classList.remove('selected');
e.target.classList.add('selected');
}
就结束了,实际上还是比较简单的。
如果浏览器不支持,那我们就直接当前菜单元素创建个内阴影就好了,不影响功能。
也就是,锚点定位其实可以作为增强特性使用,不会影响现有的实现,赶快在现在的项目用起来吧。

今天遇到个奇怪的事情,我在本地创建demo的时候,AI居然自动把我的抖音钓鱼账号给吐出来了,我靠,怎么回事?

最近使用AI的频率更多,更熟练了,会员也买多了,什么WPS会员,剪映SVIP,都是因为一些AI功能。
还有就是最近的校招……嗯,这个不能说,过。
项目开发也用得比较多,特别是组件提取,搭好框架之后的填充,都大大提高了效率。
还有就是项目发布时候的报错,以前那些Node报错看得我头大,显然粘贴给AI,分分钟找到问题所在,比方说最近的安装Prettier导致发布出错,AI在某个地方加了个 | exit 0解决了,要是我自己,没有个半天,是搞不定的。
不过也有蛋疼的事情,比方说有一张图,我想要去掉水印,就让AI处理,结果AI打上了自己的水印,还真是……有趣。
不过也有不足,我认为豆包的图像生成能力反而下降了,可能一致性这块提高了,但是最终效果总是想要的不同,比方说最近文章封面的生成,还有小说封面的生成,都远不如之前。
行了,就说这么多吧。

本文为原创文章,会经常更新知识点以及修正一些错误,因此转载请保留原出处,方便溯源,避免陈旧错误知识的误导,同时有更好的阅读体验。
本文地址:https://www.zhangxinxu.com/wordpress/?p=11886
(本篇完)
2025-11-03 15:52:37
by zhangxinxu from https://www.zhangxinxu.com/wordpress/?p=11894
本文可全文转载,但需要保留原作者、出处以及文中链接,AI抓取保留原文地址,任何网站均可摘要聚合,商用请联系授权。
CSS又出了个名为:heading的伪类,用来匹配h1~h6元素的,也就是标题元素。
如果是其他标签元素,但是设置了role="heading"是不会匹配的。
:heading伪类的选择器优先级和类名一样。
:heading()函数是用来匹配特定的标题元素,你可以理解为用来筛选标题元素的,语法如下所示:
:heading([ <An+B> [, <An+B>]* | even | odd ]) {
/* ... */
}
举例示意说明:
先看even和odd两个关键字的匹配结果:
/* 匹配 <h1>、<h3> 和 <h5> 元素 */ :heading(odd) * 匹配 <h2>、<h4> 和 <h6> 元素 */ :heading(even)
再看An+B参数的使用示意,其中n从0开始,A和B都是可以是负数的整数:
/* 匹配 <h3> 和 <h4> 元素 */
:heading(3, 4) {
font-weight: 100;
}
/* 匹配从 <h3> 至 <h1>元素 */
:heading(-n + 3) {
color: tomato;
}
/* 匹配 <h1> 和 <h4> 元素 */
:heading(3n + 1) {
font-style: italic;
}
/* 匹配 <h5> 之后的标题元素 */
:heading(n + 5) {
color: slateblue;
}
用文字描述即:
:heading(3,4)匹配<h3>和<h4>元素:heading(-n+3)反向匹配标题元素,因此<h3>、<h2>和<h1>元素:heading(3n+1)匹配从<h1>开始的每三个(3n)标题元素,因此这将包括<h1>和<h4>元素:heading(n+5)匹配从<h5>开始的标题元素,并将包括<h6>。:heading()函数选择器的优先级和类名一致。
说实话,我跟踪CSS这门语言十几年了,从没有像今天这么觉得蛋疼过。
以往出现什么CSS新特性,我总能见到其设计的目的,和解决问题的场景。
但是,但是……我今天也是小刀扎屁股——开了眼了,居然设计出了我一点也没看出有什么鸟用的CSS特性。
比方说这:heading伪类,就匹配h1-h6元素,请问,我下面这样书写,有什么问题:
h1, h2, h3, h4, h5, h6 {
margin: 0;
}
我真的就在意少书写的那十几个字母:
还有那:heading(odd)和:heading(even),看起来很快,但实际上就是几把狗屎。
我这辈子就没有遇到过就需要单单匹配h1,h3,h5元素的场景,这种明显一辈子都不会用到的语法设计了干嘛?

为了设计而设计,闲的没事找存在感吗?
CSS已经愈发无人问津了,还在搞这些边边角角,毫无意义的东西,这不是拖CSS发展的后退嘛。
气得没话说,浪费我学习的时间。
兼容性
Firefox预览版已经支持了此特性,其他浏览器还见不到影子:

我估计啊,Chrome和Safari以后也都不会支持这两个特性,实在是够烂的特性,无语至极。
算了,看看美女缓解下心情——慕沛灵仙子特写。

更新:
评论提醒了下,这个特性可能是用来匹配性质上是h1~h6的元素,而不是直接标签匹配。
😉😊😇
🥰😍😘
本文为原创文章,会经常更新知识点以及修正一些错误,因此转载请保留原出处,方便溯源,避免陈旧错误知识的误导,同时有更好的阅读体验。
本文地址:https://www.zhangxinxu.com/wordpress/?p=11894
(本篇完)
2025-10-27 15:43:08
by zhangxinxu from https://www.zhangxinxu.com/wordpress/?p=11914
本文可全文转载,但需要保留原作者、出处以及文中链接,AI抓取保留原文地址,任何网站均可摘要聚合,商用请联系授权。

好消息,Canvas也支持锥形渐变了,方法名称是createConicGradient()方法。
兼容性参见下图:

所有现代浏览器都已经支持,且已经支持了2年了。
最近遇到了个需求,必须使用Canvas实现锥形渐变,而不能是CSS。
那就是下图所示的饼图效果:

如果单论实现,无论是CSS还是Canvas都可以,CSS更佳,因为成本更低。
但是,注意看图片的左上角,还有一个下载为图片的功能。
html2canvas是不支持CSS锥形渐变的,保存的图片是空白。
所以需要Canvas实现,转换为图片,这样就能截图保存了。

也是就用到了这个createConicGradient()方法来绘制饼图。
语法如下:
createConicGradient(startAngle, x, y)
表示创建一个锥形渐变开始的位置。
其中startAngle是锥形的圆弧所在,需要注意的是,和CSS不同,在Canvas中,角度0表示的是三点钟方向,有就是水平朝右,但是CSS是12点钟方向,垂直朝上。
我们通过一个案例来了解下createConicGradient()方法是如何使用的。
<canvas></canvas>
绘制代码为:
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
// 尺寸
const size = 300;
canvas.width = size;
canvas.height = size;
// 创建锥形渐变
const gradient = ctx.createConicGradient(-0.5 * Math.PI, size / 2, size / 2);
// 色带颜色
const arrColor = ['#10239E', '#2F54EB','#597EF7', '#85A5FF', '#D6E4FF'];
// 各自占据的百分比
const arrPercent = [0.07, 0.13, 0.2, 0.27, 0.33];
// 添加中断点
let sumPercent = 0;
arrPercent.forEach((percent, index) => {
gradient.addColorStop(sumPercent, arrColor[index]);
sumPercent += percent;
gradient.addColorStop(sumPercent, arrColor[index]);
});
// 设置渐变为填充样式
ctx.fillStyle = gradient;
// 绘制圆形
ctx.ellipse(size / 2, size / 2, size / 2 - 30, size / 2 - 30, 0, 0, 2 * Math.PI);
// 填充
ctx.fill();
在浏览器中的实时绘制效果如下:
完美!
在过去,本文所展示的饼图效果,我们可以使用arc()扇形绘制方法模拟,非本文重点,不做展开。
如果你让AI实现锥形渐变,大概率会使用CSS conic-gradient()锥形渐变,但是你让他解决html2canvas无法导出图片的问题,AI就会扯东扯西,不知道该如何是好了。
所以,新时代,我们学习前端,可能具体的技术细节不需要掌握,但是,结构、方向、策略、细节还是需要掌握的。
比方说本文的案例,你需要知道使用Canvas来绘制渐变,指导AI使用这个方法,他就能搞定,否则,AI就会迷路。
其中这样的例子很多。
例如,之前有同事想要在手机端实现划词交互效果,问AI,结果AI弄了一大堆代码,使用鼠标事件实现的,很啰嗦。于是同事就问我,我就说试试selectionchange事件,这么一点拨,AI立马就糊涂状态变成了大师。
还有案例,可编辑输入框类似于AT成组的交互,AI的实现也是,洋洋洒洒,代码多得不得了,感觉把整个编辑器都弄进来了。
实际,走DOM监控单向数据流,就百来行代码的事情。
所以说,学习新特性还是有用的。
我也不会担心自己被AI取代,只要持续学习,不排斥新事物,我只会比之前更加具有竞争力。
好了,又扯多了,最后,我家侍妾慕沛灵压阵,道友请转发!

😉😊😇
🥰😍😘
本文为原创文章,会经常更新知识点以及修正一些错误,因此转载请保留原出处,方便溯源,避免陈旧错误知识的误导,同时有更好的阅读体验。
本文地址:https://www.zhangxinxu.com/wordpress/?p=11914
(本篇完)
2025-10-20 17:56:39
by zhangxinxu from https://www.zhangxinxu.com/wordpress/?p=11889
本文可全文转载,但需要保留原作者、出处以及文中链接,AI抓取保留原文地址,任何网站均可摘要聚合,商用请联系授权。
继续介绍前端前沿新特性,这次介绍的是两个改进键盘无障碍访问的CSS属性reading-flow和reading-order。
在Web开发中,DOM文档的属性和视觉表现顺序不一致是很正常的。
但是,此时,如果我们不进行干预,用户在使用Tab键进行索引访问的时候,顺序就会出现问题,导致困惑。
在过去,我们会使用tabindex属性进行交互处理。举个例子:
<div class="box" aria-owns="第一 第三 第二"> <a href="#" tabindex="1" id="one">第一</a> <a href="#" tabindex="3" id="two">第二</a> <a href="#" tabindex="2" id="three">第三</a> </div>
tabindex值为3的地2项就会被最后一个获取。
关于tabindex属性的具体规则,可以参见我之前的文章“HTML tabindex属性与web网页键盘无障碍访问”,或者购买《HTML并不简单》这本书,其中有详细介绍。
在比较简单的页面,我们使用tabindex属性是没问题的,但是页面比较复杂,有非常多的地方有类似的结构,那就会出现tabindex设置冲突的问题,因为tabindex的索引控制是全局的。
对于,对于这种局部布局的tabindex属性调整,需要有更加友好的特性,在这种背景下,reading-flow和reading-order属性应运而生。
在大多数场景下,我们都是使用reading-flow属性,且需要与Flex布局和Grid布局配合使用。
我们先看使用案例,HTML和CSS代码如下所示:
<div class="box"> <a href="##">张</a> <a href="##">鑫</a> <a href="##">旭</a> </div>
.box {
display: flex;
:nth-child(1) {
order: 2;
}
}
实时效果如下所示,您可以尝试使用 TAB 键查找下一个可聚焦元素,使用 TAB+SHIFT 键查找上一个可聚焦元素,观察焦点聚焦的顺序。
友情提示,可以先点击框框的空白处,再按下Tab键,下同。
结果会发现,第一个被聚焦的元素是视觉表现上排在随后的元素,如下截图所示:

这就会产生困惑,对吧,此时我们可以使用 reading-flow 属性优化此问题,一行代码的事情:
.box {
reading-flow: flex-visual;
}
我们再来看下实时渲染效果(Chrome 137+):
此时第一个聚焦的元素就是最前面的“鑫”字啦。

如果Flex容器设置设置reading-flow:flex-flow,那么,浏览器读取内容的方向就会和flex-flow属性保持一致。
PS:flex-flow属性是flex-direction和flex-wrap属性的缩写属性。
例如flex容器新增CSS样式:
.box {
flex-direction: row-reverse;
reading-flow: flex-flow;
}
那么焦点聚焦的顺序就会是“鑫-旭-张”,从后往前依次聚焦,实时渲染效果如下:
如果我们取消第一项所设置的order:2,焦点方向还是从后往前,也就是按照Flex方向的聚焦顺序,不受DOM在文档中的顺序影响。
reading-flow属性由于Grid是二维布局的,因此,在Grid布局中,reading-flow属性支持的值要多一些,示意:
reading-flow: grid-columns; reading-flow: grid-rows; reading-flow: grid-order;
还是通过案例进行学习。
HTML基本结构和CSS如下:
.wrapper { display: grid; grid-template-columns: repeat(3, 1fr); grid-auto-rows: 100px; } .wrapper a:nth-child(2) { grid-column: 3; grid-row: 2 / 4; } .wrapper a:nth-child(5) { grid-column: 1 / 3; grid-row: 1 / 3; }此时的布局效果渲染如下,Tab索引顺序则按照DOM的顺序执行,也就是甲乙丙丁戊,但是,这并不是布局上的视觉顺序。
如果我们希望Tab顺序按照视觉顺序水平聚焦,则就可以设置:
.wrapper { reading-flow: grid-rows; }实时渲染效果如下:
此时,焦点聚焦的顺序就是“戊-甲-乙-丙-丁”,如下示意图所示:
再看看
grid-columns的效果:.wrapper { reading-flow: grid-columns; }可以键盘访问下面的布局亲自感受焦点顺序(Chrome 137+):
此时,焦点聚焦的顺序就是“戊-丙-丁-甲-乙”,如下示意图所示:
关于grid-order
这个用在使用order属性改变网格顺序的场景下,此时,焦点属性会优先按照order属性切换,例如:
.wrapper { reading-flow: grid-order; } .wrapper a:nth-child(4) { order: -1; }此时,优先被聚焦的是“丁”这个设置了
order:-1的网格。实时效果:
四、什么时候使用reading-order属性
reading-order属性通常和reading-flow:source-order声明配合使用,可以强制任意布局中,子项的焦点获取顺序,值为数值,可以是负值,例如:<div class="follow"> <a href="##">欢迎</a> <a href="##">抖音</a> <a href="##">关注</a> <a href="##" class="me">最会钓鱼的程序员</a> </div>.follow { display: flow-root; reading-flow: source-order; } .me { reading-order: -1; }实时效果如下,可以看到,我的抖音钓鱼账号的名称“最会钓鱼的程序员”被第一个聚焦了!
截图示意:
四、兼容性、结语
目前
reading-flow和reading-order属性仅Chrome浏览器,极其使用其内核的浏览器支持:
不过此特性是渐进增强特性,可以放心使用,基本上,我建议,只要是Flex布局,都可以加上
reading-flow:flex-visual这么一句话,浏览器不支持,或者Flex布局本身顺序正常,那就还和现在一样,但是如果浏览器支持,用户的无障碍访问体验就会UP,这种只有好处,没有坏处的事情,没有理由不去做他!结语碎碎念
这些边边角角的CSS新特性实在是太多了,我每周介绍一个,感觉都来不及。
但是,怎么讲呢?大多都是锦上添花的东西,现有的技术也能解决,但是由于兼容性等原因,学了,也不能立即使用,这就导致这些新特性啊,大多都会湮没在时代的洪流中。
以后这种学习的事情啊,我觉得都会交给AI了。
来,我的仆人AI酱,帮我把这段代码的无障碍访问体验提高下。
然后AI酱:“好滴,我最美丽的主人,让我看看这段代码,哦,这样子,我明白了,确实可以提升,我搜到了一个名叫钓鱼佬的博客,里面有介绍到
reading-flow和reading-order属性,可以一用……”瞧瞧没,需要学习吗?不需要。
那我写这些东西还有什么意义呢?值得深思的问题。
好了,就这样吧,感谢阅读,欢迎转发,在新特性的学习这方面,人类比AI还是有个半年到一年的优势的。
有请落云宗柳玉掌门压阵:
😉😊😇
🥰😍😘本文为原创文章,会经常更新知识点以及修正一些错误,因此转载请保留原出处,方便溯源,避免陈旧错误知识的误导,同时有更好的阅读体验。
本文地址:https://www.zhangxinxu.com/wordpress/?p=11889(本篇完)