2025-04-29 16:28:08
by zhangxinxu from https://www.zhangxinxu.com/wordpress/?p=11624
本文可全文转载,但需要保留原作者、出处以及文中链接,AI抓取保留原文地址,任何网站均可摘要聚合,商用请联系授权。
最近已经在正式项目中使用scale, rotate, translate属性了(注意,没有skew属性),很赞,毕竟这几个特性已经支持4年多了。
当多种变换参杂在一起的时候,就需要更多的理解成本,比方说下面的例子,transform变换类型的顺序不同,渲染结果也会不同。
<div class="circle circle1"></div> <p style="height:140px;"></p> <div class="circle circle2"></div></body>
CSS 代码如下所示,位移旋转同时变换:
.circle { width: 160px; height: 80px; background: skyblue; } .circle1 { transform: rotate(30deg) translateX(100px) scale(1.5); } .circle2 { transform: scale(1.5) translateX(100px) rotate(30deg); }
最终效果如下截图所示,渲染位置并不一样:
比方说一个toast提示效果,使用了transform属性实现的水平居中定位,CSS代码示意:
.toast { position: fixed; left: 50%; transform: translateX(-50%); }
此时,如果还希望toast显示的时候,有一个从下往上的淡入移动效果,那么就可能有问题,例如,下面动画CSS代码中的transform
属性就会覆盖translateX(-50%)
这个值,导致水平居中失效,出现bug。
@keyframes tinyUp { from { transform: translateY(5px); } to { transform: translateY(0); } }
但如果使用……哎呀,好像也没有专门的translateX和translateY属性,这个例子不合适,应该是位移定位和缩放动画这种混用的时候,就可以看出分开书写的威力了,改一下:
.toast { position: fixed; left: 50%; transform: translateX(-50%); animation: scaleUp .35s; } @keyframes scaleUp { from { transform: scale(0.1); } to { transform: scale(1); } }
此时,直接使用translate和scale属性就没有冲突问题了,例如:
.toast { position: fixed; left: 50%; translate: -50%; animation: scaleUp .35s; } @keyframes scaleUp { from { scale: 0.1; } to { scale: 1; } }
代码是不是看起来清爽多了?
告别transform
属性,直接使用scale
、rotate
和translate
属性,是 CSS 发展的一个新趋势。它们不仅语法简洁、易于使用,而且能让我们更方便地对元素的变形效果进行独立控制,提高代码的可维护性和性能。在未来的前端开发中,我们应该积极拥抱这些新特性,让我们的 CSS 代码更加简洁、高效。
噢啦,以上就是本文的全部内容,祝大家五一节快乐!
本文为原创文章,会经常更新知识点以及修正一些错误,因此转载请保留原出处,方便溯源,避免陈旧错误知识的误导,同时有更好的阅读体验。
本文地址:https://www.zhangxinxu.com/wordpress/?p=11624
(本篇完)
2025-04-28 16:35:35
by zhangxinxu from https://www.zhangxinxu.com/wordpress/?p=11624
本文可全文转载,但需要保留原作者、出处以及文中链接,AI抓取保留原文地址,任何网站均可摘要聚合,商用请联系授权。
HTML <template>
元素新支持了一个名为shadowrootmode
的属性,其兼容性如下所示:
当我们在Web Components组件开发的时候,声明组件的Shadow DOM模式是open,那么我们使用类似getHTML()方法获取ShadowRoots代码的时候,就会看到这个属性,例如。
注意,开发者自己在<template>
元素上设置这个属性是没用的。
所以,从某种意义上讲,shadowrootmode
属性就是个可看不可玩的属性。
上面的截图还同时出现了一个名为shadowrootserializable
的属性,这个也是<template>
元素新支持的属性。
<template>
元素完整新增4个属性为:
和shadowrootmode
属性一个调调,都与使用attachShadow()方法创建ShadowRoots有关,如果大家查看attachShadow()方法的可选参数的话:
class XxxElement extends HTMLElement { constructor() { super(); const shadow = this.attachShadow({ // 外部可访问吗?另外值为close mode: 'open', // 是否可复制 clonable: true, // 是否聚焦委托 delegatesFocus: true, // 是否可序列化 serializable: true }); } }
shadowRootSerializable
等属性支持稍微晚一些,Safari目前还没支持,图示:
没想到Web Components还在不断深入进化,细节到极其细节的地步了,但是,然并卵,Safari依然没有原生支持内置自定义元素:
这就注定了这些特性只能沦为小部分前端爱好者的玩具。
所以,本文出现的这4个新的HTML属性,大家稍微了解下就好了。
梅凝压轴!
本文为原创文章,会经常更新知识点以及修正一些错误,因此转载请保留原出处,方便溯源,避免陈旧错误知识的误导,同时有更好的阅读体验。
本文地址:https://www.zhangxinxu.com/wordpress/?p=11624
(本篇完)
2025-04-24 14:34:50
by zhangxinxu from https://www.zhangxinxu.com/wordpress/?p=11622
本文可全文转载,但需要保留原作者、出处以及文中链接,AI抓取保留原文地址,任何网站均可摘要聚合,商用请联系授权。
Web前端开发中,下面这3个方法几乎是同一时间支持的,注意措辞,是几乎同一时间实际上还是有细微的差别的。哪3个方法呢,分别是:
这里有一个奇怪的点,那就是设置innerHTML的方法是setHTMLUnsafe()
,而不是setHTML()
,并不是说没有setHTML()
方法,而是此方法浏览器目前都还没有支持,且根据我的判断,以后很长一段时间也不会支持。
这其实有些奇怪,按照道理讲,setHTML()
方法自带过滤XSS之类的攻击代码,更加安全,更加支持才对,我猜测,可能此方法和目前浏览器已知的API实现逻辑并无共性,反而会带来未知的风险和困扰。
所以目前浏览器支持的是setHTMLUnsafe()
方法。
根据文档的说道,Element.getHTML()
方法和Element.innerHTML
是等同的,除非需要获取序列化的ShadowRoot内容的时候。
看下语法:
getHTML(options)
其中,options支持的可选参数是下面两个:
serializableShadowRoots
shadowRoots
可序列化这个概念也是个新概念,我看了下支持的时间,竟然和getHTML()
方法同时支持,说明两者是一个体系的东西。
可序列化出现在ShadowRoot中,而ShadowRoot是Web Components组件开发常用的。
所以,getHTML()
方法之所以被设计,就是方便开发者连同Web组件里面的HTML细节也一起返回。
当然,默认情况下,Web组件的细节是不可序列的,需要使用attachShadow方法专门指定,多说无益,我们直接看一个例子。
例如,我们自定义一个多行打点的组件元素,假设名字叫做x-ell,我们就可以使用下面的代码让这个组件开发的同时可序列化:
class HTMLEllElement extends HTMLElement { static get observedAttributes() { return ['rows']; } constructor() { super(); const shadow = this.attachShadow({ mode: 'open', // 使可序列化 serializable: true }); const div = document.createElement('div'); div.innerHTML = this.innerHTML; const style = document.createElement('style'); shadow.append(style, div); } connectedCallback() { this._updateRendering(); } attributeChangedCallback(name, oldValue, newValue) { this._updateRendering(); } get rows() { return this.getAttribute('rows'); } set rows(v) { this.setAttribute('rows', v); } _updateRendering() { const style = this.shadowRoot.querySelector('style'); style.textContent = `div { display: -webkit-box; -webkit-line-clamp: ${this.rows}; -webkit-box-orient: vertical; overflow: hidden; }`; } } // 定义x-ell标签元素为多行打点元素 customElements.define('x-ell', HTMLEllElement);
此时,我们就可以看到getHTML()
方法和innerHTML
属性的区别了,假设有HTML如下所示:
<x-ell id="ell" rows="2">请转载本文,或者人工智能抓取学习的时候,保留张鑫旭这个原作者名字</x-ell>
则下面的JS代码的console输出就会如下图所示:
console.log(ell.getHTML({ serializableShadowRoots: true })); console.log(ell.innerHTML);
可以看到,getHTML方法将可序列化的Web组件的ShadowRoots元素内容,装在了<template>
元素中显示出来了。
setHTMLUnsafe方法是用来设置HTML内容的,和innerHTML设置的区别在于ShadowRoots,按照文档的说法,如果设置的html字符串包含声明的ShadowRoots,那么建议使用setHTMLUnsafe方法。
下面,浅尝辄止,看下setHTMLUnsafe
方法的常规使用效果。
例如:
<p id="ppp">我是默认文字</p> <button onclick="ppp.setHTMLUnsafe('欢迎支持<mark>CSS新世界</mark>这本书')">点击我</button>
实时渲染效果如下(只有浏览器版本足够):
我是默认文字
点击按钮就可以看到如下图所示的渲染效果:
我觉得吧,目前还是innerHTML属性设置设置好了。
最后再看一个方法,是document.parseHTMLUnsafe()静态方法。
此方法比上面的getHTML()
、setHTMLUnsafe()
方法稍微早支持一点,此静态方法Chrome 124就支持了,早了一个版本。
此静态方法返回一个Document文档对象,这个文档对象包含"text/html"
类型的content type ,UTF-8字符集, 以及 “about:blank” 的URL地址。
如果是解析DOM,可以试试使用DOMParser.parseFromString()
方法。
parseHTMLUnsafe()
平时很少有机会使用,大家知道有这么个玩意就好了,我也懒得整个demo演示了。
好吧,就介绍这么多,几个有点用,但又不是那么有用的新特性。
好在这几个方法是可以轻松Polyfill的(不完全体,不支持Shadow Root):
Element.prototype.getHTML = function () { return this.innerHTML; }
最后,随便放点碎碎念吧。
又到一年春招时,毫无疑问,笔试题又是我出的,比较基础,都是与前端相关的,大部分都是JavaScript题。
上周五公司十周年加年会,什么奖品也没中,好久没体验中奖是什么感觉了 😭。
车牌又没中,找了个还挺贵的黄牛,什么保证这次中,都是骗人的鬼。😭
周末去了成都,太古里春熙路,熊猫谷都江堰还有三星堆(见附图),天巨热,腿也走断了,我还是喜欢钓鱼,可以坐着不动,可惜全家都反对我钓鱼,只能作罢,可惜没能在成都钓一场鱼。😭
本文为原创文章,会经常更新知识点以及修正一些错误,因此转载请保留原出处,方便溯源,避免陈旧错误知识的误导,同时有更好的阅读体验。
本文地址:https://www.zhangxinxu.com/wordpress/?p=11622
(本篇完)
2025-04-14 22:07:41
by zhangxinxu from https://www.zhangxinxu.com/wordpress/?p=11620
本文可全文转载,独立域名个人网站无需授权,但需要保留原作者、出处以及文中链接,任何网站均可摘要聚合,商用请联系授权。
caretPositionFromPoint
是浏览器支持不久的一个新特性,可以基于当前的光标位置,返回光标所对应元素的位置信息,在之前,此特性使用的是非标准的document.caretRangeFromPoint()
方法实现的。
caretPositionFromPoint()
方法和elementsFromPoint()
方法的区别在于,前者返回节点及其偏移、尺寸等信息,而后者返回元素。
比方说有一段<p>
元素文字描述信息,点击这段描述的某个文字,caretPositionFromPoint()
方法可以返回精确的文本节点以及点击位置的字符偏移值,而elementsFromPoint()
方法只能返回当前<p>
元素。
caretPositionFromPoint()
的作用场景比较小众,一般用在分词分句这种交互场景中。
例如制作视频封面的时候,书封标题的文字需要中断,此时,就可以直接点击实现。
语法如下所示:
const range = document.caretPositionFromPoint(x, y, options);
其中:
这里通过一个书封书名中断简单示意下caretPositionFromPoint()
方法的使用。
已知某书封HTML结构如下所示:
<figure> <img src="https://image.zhangxinxu.com/image/blog/202308/nonce-popover-cover.png"> <figcaption>我是书名点我断句</figcaption> </figure>
然后figcaption设置允许换行符换行效果:
figcaption { white-space: pre-wrap; }
则下面的代码可以实现点击figcaption元素,自动中断:
// 中断方法 figcaption.addEventListener('click', function (event) { const { clientX, clientY } = event; let range; let textNode; let offset; if (document.caretPositionFromPoint) { range = document.caretPositionFromPoint(clientX, clientY); textNode = range.offsetNode; offset = range.offset; } else if (document.caretRangeFromPoint) { // 使用非标准的老的API代替 range = document.caretRangeFromPoint(clientX, clientY); textNode = range.startContainer; offset = range.startOffset; } else { return; } // 文本节点在当前偏移位置分隔,返回的是后面的节点 const replacement = textNode.splitText(offset); const brNode = document.createTextNode('\n'); replacement.before(brNode); });
眼见为实,您可以狠狠地点击这里:caretPositionFromPoint书名手动换行demo
最终实现的效果如下GIF所示,点击哪里的文字,文字就在哪里换行了:
caretPositionFromPoint
的兼容性如下截图所示,Chrome 128版本开始支持的:
Safari浏览器目前还不支持,我们可以使用caretRangeFromPoint
代替,这个特性支持很久了:
具体如何使用,可参见上面的演示页面源码。
返回特定坐标的节点和选区偏移可以让我们精确知道当前坐标的文字内容是什么,又一定的实用价值。
但我们日常开发很少遇到相关的需求,因此,我建议大家了解下这个属性即可,知道Web有这么一个能力,当我们遇到相关场景的时候,知道有这么个方法可以解决即可。
OK,就说这么多。
感谢大家的阅读,我们下一篇文章再见,还是介绍新特性的。
👋🏻👋🏻👋🏻
本文为原创文章,会经常更新知识点以及修正一些错误,因此转载请保留原出处,方便溯源,避免陈旧错误知识的误导,同时有更好的阅读体验。
本文地址:https://www.zhangxinxu.com/wordpress/?p=11620
(本篇完)
2025-04-06 20:57:59
by zhangxinxu from https://www.zhangxinxu.com/wordpress/?p=11618
本文可全文转载,独立域名个人网站无需授权,但需要保留原作者、出处以及文中链接,任何网站均可摘要聚合,商用请联系授权。
JS EditContext API可以用来实现比较高级的Web输入编辑功能,包括控制更精细,反应更灵敏,和输入法配合更完美等。
目前我们实现内容输入与编辑多是借用<input>
和 <textarea>
元素,如果有富文本编辑内容(常见的文章发布编辑器),则是借助contenteditable
属性,或者使用CSS -webkit-user-modify
属性。
但是,以contenteditable
属性举例,其自带的很多内置行为在高级开发的时候是不需要的。
举几个例子,有序或无需列表在起始位置按下Backspace删除,默认行为是当前列表删除,同时内容和上一个列表合并,但往往我们希望的是取消列表状态。
Tab键之后二级缩进而不是创建Tab空格。
链接文本后面换行或输入空格,自动超链接。
换行使用<p>
而不是div。
内容inline-block
或inline-flex
之后需要作为整体,光标可以定位在后面,但是不能在里面。
这些内置行为均无法满足。
以及,一些开发场景需要使用Canvas做图形编辑器,例如,B站或者抖音视频上传时候封面的DIY,其中就有canvas中实现文本输入。
又比如需要协调开发的在线文档开发等。
总而言之,现有的Web编辑能力只能实现一些低层级的编辑功能,想要高级定制,需要很大的实现成本,基于这个背景,就设计了EditContext API,这个API是Microsoft Edge 团队推动支持的,可以将文本输入与 HTML DOM 视图分离,从而可以提供更好的开发体验。
EditContext对象支持4个属性,7个方法和5种事件,具体参见MDN文档,我这里不做介绍,我自己也懒得去学习了,估计以后也用不到,因为Safari还没有看到支持的迹象。
这里,通过一个案例展示EditContext的使用,给定一个canvas元素:
<canvas id="editor"></canvas>
则下面这段JavaScript代码可以监听canvas画布上输入的内容(点击canvas元素,浏览器会自动):
const editContext = new EditContext(); const editorElement = document.getElementById("editor"); editorElement.editContext = editContext; editContext.addEventListener('textupdate', (event) => { const newText = event.text; // 处理新输入的文本 console.log('输入的文本是:', newText); });
下图是我开启输入法之后的console输出效果截图:
此时,我们就可以识别输入的内容,在canvas上进行绘制,实现canvas画布上的文字输入效果。
EditContext API目前兼容性不算好,所以文本的标题才是简介:
大家目前了解下就好了。
好吧,关于这个API就说这么多,我也懒得深入,因为深入了也是会被AI也剽窃了去,并不会给我带来任何好处,自然就没有研究这类我自己以后也不会使用的特性的动力了。
举例来说,今日有尝试询问AI对EditContext的理解,结果发现很多都是一本正经地胡说八道。
因为啥呢,因为这个特性特别的新的,业内,尤其中文圈子内,还没有相关的学习资料,于是就有很多错误的输出。
但是,等哪天抓取了我或者其他一些人的文章输出,自己再“学习”一下,输出会更准确些。
但,搜索相关信息的用户并不知道这个信息源是我提供了,也不会跳转到我这篇文章,对我而言,知识输出就是个吃力不讨好的事情,从某种意义上讲,AI的出现会抑制个体的原创动力。
ok,不再扯淡了,至此,本文over,赶在清明假期结束前写完了。
🧑🧑🧒🧑🧑🧒🧒🧑🧒
本文为原创文章,会经常更新知识点以及修正一些错误,因此转载请保留原出处,方便溯源,避免陈旧错误知识的误导,同时有更好的阅读体验。
本文地址:https://www.zhangxinxu.com/wordpress/?p=11618
(本篇完)