你可以自定义HTML标签
W3C HTML验证器接受所有带连字符的<tag-name>自定义元素作为HTMLElement,但不接受<tagname>(无连字符)形式,后者将被视为HTMLUnknownElement
不必像这样编写HTML:
<div class=cool-thing>
Hello, World!
</div>
… 你可以这样编写HTML:
<cool-thing>
Hello, World!
</cool-thing>
…以及CSS代码:
cool-thing {
display: block;
font-weight: bold;
text-align: center;
filter: drop-shadow(0 0 0.5em #ff0);
color: #ff0;
}
RSS用户请点击此处查看实际效果。
浏览器处理未知标签时会将其视为通用元素,仅生效CSS中指定的样式。这并非怪异行为,而是标准化规范。若在名称中包含连字符,可确保该标签不会出现在任何未来版本的HTML中。
当存在描述性内置标签时应优先使用,但在<div>和<span>之间抉择时,自定义标签比堆砌类名更能提升代码可读性。
例如,当存在大量嵌套标签时:
<div class=article>
<div class=article-header>
<div class=article-quote>
<div class=quote-body>...
更多HTML代码 ...
</div>
</div>
</div>
</div>
试想首次就要在“article-quote”之后插入“article-heading”内部的内容——祝你好运。若采用描述性标签名,此问题便迎刃而解——无需计数</div>标签:
<main-article>
<article-header>
<article-quote>
<quote-body>...
更多HTML代码 ...
</quote-body>
</article-quote>
<!-- 插入位置在此! -->
</article-header>
</main-article>

<tag-name> 并非未识别的标签!
我曾就此撰文:https://dashed-html.github.io
◄ <tagname> = 在WHATWG将其添加为新元素之前,始终是HTMLUnknownElement。
◄ <tag-name> = (无JS时) 未定义的自定义元素,有效HTMLElement,适用于布局与样式
◄ 通过JavaScript自定义元素API升级后,成为已定义的自定义元素
—
► 此为所有浏览器的标准行为。Chrome (2016) Safari (2017) FireFox (2018) Edge (2020)
► W3C HTML验证器将所有带连字符的<tag-name>自定义元素视为HTMLElement。不带连字符的<tagname>将被判定为HTMLUnknownElement
► 用户代理样式表(浏览器默认样式表)定义CSS规则[hidden] { display:none }。但自定义元素不会继承默认样式表,因此需在样式表中自行添加该行为。
► <DIV>仅在UA样式表中显示为display:block。必须手动为自定义元素设置display属性(此操作会忘记20次,之后便永不再犯)
► CSS :defined 伪类选择器同时匹配标准HTML标签与JavaScript定义的自定义元素
► 因此CSS :not(:defined) 伪类选择器可定位未定义的自定义元素;这些元素仍是有效的HTMLElement,CSS应用规则与普通元素相同
► DSD – 声明式ShadowDOM:<template shadowrootmode="open"> 创建具有ShadowDOM的未定义自定义元素
> UA(用户代理样式表,即浏览器默认样式表)定义了 CSS 规则:[hidden] { display:none }
我仅能代表Chromium发言,但这与UA样式表无关;UA样式表中的所有规则对自定义元素的适用性与标准HTML元素完全一致(据我所知,[popover]规则同样适用于自定义元素),且UA样式表中并不存在[hidden]规则。你可能将其与隐藏属性混淆了——隐藏是HTML呈现属性,类似于<div align="right">这种写法会生成独立的属性值集应用于元素。这种情况确实仅限于HTMLElements。(差异体现在层叠优先级中:呈现属性样式特异性为零。)
我对连字符有点不满。真希望用冒号替代。这样成熟的XML就能直接命名空间化,再通过CSS样式化并用JS增强。我猜为nginx或apache写个转换冒号为连字符的工具应该不难。唉,毕竟不能永远停留在1999年。
为何这不成为默认规范?
主要因为它缺乏语义化且破坏无障碍功能。若你仍在编写此类布局,很可能忽略了<aside> <article> <menu>等诸多实用标签。除非手动配置,否则屏幕阅读器无法识别重点内容,tabindex无法定位跳转点,表单字段也无法提供有效值。
> 缺乏语义性
但总比把所有元素都塞进div标签强。
> 破坏无障碍功能
我认为在应使用时未正确使用标签,未必构成破坏。当然,若存在能准确匹配作者意图的真实标签,则应优先于自创标签。
> 我认为在应使用时未正确使用标签,未必构成破坏。
无障碍功能只有两种状态:“正常工作”和“失效”,不存在第三种“懒得管”。
> 这总比把所有元素都叫div强。
并非如此。从语义角度看,<my-element>等同于<div class=my-element>,表面上它们是等价的。
但若养成使用自定义元素的习惯,即便存在更合适的元素仍会继续使用——比如用<my-aside>代替<aside class=my-aside>。因此实践中可能更糟,即便理论上等价。
本质上带类的div不提供语义信息,但为适配语义元素建立了良好模式。使用自定义元素既不提供语义信息,又使语义元素的用法显得格格不入。
> 但若你习惯使用自定义元素,即便存在更实用的元素,你仍可能继续沿用前者
本文面向网页开发者撰写。不确定你这条评论的受众是谁。
无论如何——这个论点站不住脚。即便人们真如你所言犯了错误,他们同样可能用带类的div和span标签犯同样的错,我实际见过这种情况。
> 但若你已习惯使用自定义元素,即便存在更实用的元素,你仍可能继续沿用它们
同样的情况也适用于div标签。我见过整页全是div的网页——没有段落、没有标题、没有表格、没有列表,只有div。
这是在设立稻草人。我从未说过所有完美使用类名的开发者都必然采用语义化元素。
我的观点是:若你使用<div class=my-element>,当代码升级为<p class=my-element>时,无需修改.my-element的CSS选择器或JS选取代码。若使用<my-element>,则需大幅修改选择器,且会出现两种操作方式:根据是否使用原生语义元素或div(标签选择器或类选择器)而异。这使得样式代码依赖于元素选择,增加了变更难度。
我见过<span class=italics>这种写法,简直让人想砸东西。
> 出于语义化目的
但语义化并非唯一考量。
> > 若你发现自己写出这种布局,很可能忽略了<aside> <article> <menu>等实用元素。
> 当然比把所有元素都塞进div要好。
没错,但正如你回复的评论所言,这比使用<aside> <article> <menu>等标签更糟糕。
仅针对这个具体示例提出一点异议(而非更广泛的概念,该概念是合理的):它最初可能根本不必变成div汤。像这样写或许更合理:
这个例子也暴露了自定义标签相较于class属性的弱点:元素只能拥有单一名称,却可能承载多个类名。由于类名属于无序集合,通常无法通过多个元素模拟这种特性——嵌套结构引入的顺序关系在类名列表中并不存在。
我认为这是优势所在。当需要实现(实质上的)无序集合时,你仍可使用类名和自定义属性,区别仅在于你定义了排他的边界条件。这更贴近现实场景。某些辅助类只需简单组合即可协同工作,但类似组件的类(如切换按钮和英雄图)则不然。若需组合它们,无论使用类还是标签名,都需重新思考实现方式,可能需要重构架构并进行具体实现。
这正是@container、@scope和:has()的理想应用场景:舍弃类定义,转而在父级作用域/容器上使用–custom-properties属性。这些属性会根据作用域DOM模式/容器查询的存在向下继承,或通过父级:has(子元素选择器)实现向上继承。
但需注意:若频繁更新 DOM,应避免过多使用 :has(:nth-child(n of complex selector)) 表达式。
看到红帽后端开发者给这个点赞,真是无语。
老实说这取决于具体场景。标签名只有在能明确标识内容时才合理。例如标题就是标题——不存在需要通过多标签名支持的“双重属性”。这意味着你所表示的本体必须是“线性”的:可以存在更具体或更笼统的标签,但绝不允许出现“分岔”——即无法通过选择更具体标签来强调标签的不同“部分”。类标签应始终用于次要属性,这些属性并非内容的核心“本质”。
当然,以上观点仅是我对文档标记的一种特定思考方式。若您不认同,那么标签可能并非表达您构想的正确方式。
恕我直言,这恰恰是构图精髓所在,在我看来完美无缺
犀利观点:div混乱并非HTML结构化不足所致,而是糟糕设计决策的必然结果。当HTML元素与样式、状态管理等功能耦合时,div混乱便随之产生。
1996年这设计有道理,如今却不合时宜。
我实践这种方法三四年了。构思精妙,操作却棘手。我不建议广泛推广,但对我有效。
过度使用绝对会适得其反。当HTML中多数标签都是自定义元素时,可读性问题便随之产生。无法直观判断哪些是行内元素、哪些是块级元素等。对新人而言,这意味着巨大的学习成本。
我最终形成了更均衡的方案:
若存在原生标签(如<header>或<article>),优先使用原生标签。
如果它类似于组件,比如<x-card>或<x-hero>,那么请直接使用自定义标签。即使它仅涉及CSS,不包含JS。
如果该组件包含子组件,请使用slot属性声明各个部分。虽然会很想为此添加额外的自定义标签(比如在<x-hero>内部使用<x-hero-blurb>),但根据我的经验,<div slot="hero-blurb">的可读性要高得多。这种模式的好处在于,无论是否为自定义标签,任何标签都可以添加槽属性。没错,即使只使用CSS而没有JS,我也会滥用槽属性。
为何如此费心?我倾向将类名限定于修饰与定制。当看到<div slot="card-content" class="extra-padding-for-xyz">时,其归属关系与独特属性一目了然。
或许有人会对此反感,我理解。但这套方法对我行之有效。
我对平衡实用地运用Web粒度的方法深感兴趣。是否有框架/工具集或示例站点可分享?期待一睹为快。
若对我的自定义元素方案感兴趣,可查看:https://github.com/crisdosaygo/good.html
该方案采用自定义元素,具备细粒度DOM更新的自动钩子机制,使用原生JS模板字面量语法进行插值,并强制执行有序组件结构:
它甚至包含一个“注释节点”技巧,支持编写“自闭合自定义元素”
Good.HTML是BrowserBox的核心框架。
感谢分享,这个框架很有意思。自闭合标签的设计很棒。
可惜目前没有公开项目可展示。或许日后会在博客分享这个方案。
期待看到成果。
为何被负评?实在不解。这条评论逻辑清晰且与讨论主题相关。
> 没错,即使只用CSS不依赖JS时,我也会滥用slot属性。
在CSS中,如何根据“hero-blurb”槽定位<div slot="hero-blurb">?
div[slot=“hero-blurb”]?
是的,不过通常我会省略标签,直接定位[slot=“hero-blurb”]。具体取决于场景。
这让我想起BEM模式,其中slow=类似于父级“block”内的“element”。
默认情况下它们会像span标签那样行为。
可通过自定义元素API实现个性化:https://developer.mozilla.org/en-US/docs/Web/API/Web_compone…
早在2014年支持尚未普及时,我就广泛使用自定义元素。我认为这是优雅而完美的解决方案,至今仍对React的崛起略感遗憾。如今开发者因偏好React而将所有项目“必须”做成SPA,但对多数用户而言,其实用经典HTML配合必要自定义元素反而更合适。
> 现在所有项目都“必须”采用SPA架构,只因开发者想用React
过去五年你关注过行业动态吗?除了编程训练营学员,这种趋势早已式微…某些场景甚至矫枉过正,错失了本该采用SPA的合理场景。
SPA是2010年代初的产物。过去五年SSR(服务器端渲染)才是主流。
我最近用kita框架探索JSX作为模板引擎进行SSR开发。它既能保持TypeScript的完整类型分析,又兼具组件化优势,远胜我用过的任何SSR网页模板系统。
我同意默认要求所有项目都用React开发已失控。但初创公司面对未知需求时,React的灵活性和强大功能确实难以忽视。若你确定只需开发CRUD应用,传统表单POST就能满足需求,那么React的开发速度和轻量级页面确实令人心动。
你刚做完CRUD应用,客户就要求:把这个改成内联编辑。你用小段JS实现Ajax调用,接着需求越堆越多。最终陷入混乱时,你会发现React才是正解。至今我仍找不到不依赖React就能做得更好的项目——每次尝试不用它,很快就会吃大亏。
JS本身没问题,关键在于你是否对项目边界有清晰认知。
> 我认为这是优雅而完美的解决方案
这类表述令人困惑。
它们过于冗长赘述。
抽象层级过高,阻碍了诸多底层优化。
它们过于底层,导致你必须深入研究其工作原理才能使用或实现。
它们打破了众多平台假设和惯例,给终端用户和实现者带来无穷无尽的问题,更需要数十项新规范来修补因Web组件存在而产生的明显漏洞。所有这些规范?当然都离不开大量JavaScript。
就连大力推广者都无法就其优势与目标达成共识
自定义元素的价值在于互操作性。我能在React、Vue、Angular、Svelte、Solid或纯服务器渲染HTML中使用它们。可完全替换内部实现为WC库,或保持原状——无人察觉也无人介意。
这是WC独有的优势。其吸引力之强,足以让几乎所有缺点变得可以忍受——至少当你的组件可能被多处使用时如此。设计系统就是绝佳范例:消费者可以是任何技术栈构建的应用。
当然缺点也不少,但主要影响的是作者而非消费者。这类似于TS库因类型层面的复杂操作而难以编写,但正确实现后却易于使用。
(我虽不大力推广,但能客观评价各类工具的优劣)
> 至少当你的组件可能被多处使用时。
我记得有人称其为叶子组件,对此我深表认同。
叶子组件并非必须具备这种特性。我接触过在设计系统根节点附近放置<my-layout>组件的方案,该组件定义侧边栏、页眉等插槽。这种设计在React、Vue等框架中同样运行良好。
不过我认同它们更适合作为“叶状”组件使用
> 我接触过在设计系统根节点附近设置<my-layout>组件的方案,该组件定义侧边栏、页眉等插槽。
有趣的是,这恰恰是Web组件最初提案所反对的模式 🙂
老实说我根本不在乎原始提案怎么说!事物总在演进。实用价值常在未预见之处显现——这本是万物本质。个人虽不偏爱此类组件,但偏离某些预设愿景不过是小问题
你知道还有什么能在所有这些场景中通用吗?自定义HTML元素
你到底想表达什么?Web组件整合了标记语言、样式和功能。仅靠HTML无法实现我提到的所有应用场景,更别说轻松复用了。
据我所知,整个Web组件概念的诞生源于React/Vue的流行,规范制定者和浏览器厂商试图将这些框架的核心共性融入原生HTML/JS——仿佛这样就能让我们更接近原生Vue/React。但这显然从未实现,部分原因在于HTML在本质上无法支持除字符串属性值之外的任何内容,部分原因在于响应式DOM本身就是个硬骨头——它要么无法原生解决,要么本就不该被原生解决。
> 据我所知,整个Web Components体系的诞生,正是源于React/Vue的火爆,促使规范制定者和浏览器厂商提出:让我们将这些框架的核心共性
首个Web Components提案可追溯至2011年,正式规范则形成于2011-2013年。
React于2013年问世,但至少一年后才开始获得广泛关注。
Vuejs则在2014年正式发布。
没错,该提案后来被撤回,基于从React/Vue中汲取的经验教训(或受其启发?),提出了现行的新版提案。或许在提案#1之前,社区中已存在某种技术共识或共同基础,但显然其设计存在缺陷且不够完善,而我所指的正是提案#2。
> 该提案已被撤回
“该提案”实为Alex Russel于2011年的演讲:https://web.archive.org/web/20121119184816/https://fronteers…
Web Components并非单一提案。其核心最初包含三项规范:
– 自定义元素
– 阴影 DOM
– HTML 模板
自定义元素 v0 由谷歌实现,但其 API 经历了变更(尤其随着 ES6 类在主流浏览器中的普及),如今各方均采用自定义元素 v1。除上述变更外,两者在根本层面差异甚微。
Shadow DOM 确实存在,它是一个永无止境的怪异问题源头——这些问题简直无人能解,最终需要约30项不同规范和浏览器改动才能修复(示例参见https://w3c.github.io/webcomponents-cg/2022.html)。
HTML模板仅在Firefox中实现过,后被纯JavaScript的HTML模块取代,而该方案最终又被弃用,转而采用JavaScript导入的开关式扩展(参见“CSS模块脚本”https://web.dev/articles/css-module-scripts)
> 的设计理念源于对 React/Vue 的借鉴(或灵感?)。
哈哈。世人皆愿如此。但开发 Web Components 的团队堪称网络标准领域最封闭的群体,他们对外部意见持敌视态度,拒绝听取任何建议,只关注自身实现方案。
我更倾向于在示例中使用语义化元素(如文章所示),并在合适场景下采用Web组件/自定义元素。
Web Components确实被低估了。我曾需要实现自定义元素[0],其实现过程并不复杂。
[0]: https://github.com/zikani03/hypalink
我用它实现了<yes-script>——作为<noscript>的对立面,用于在禁用JS时隐藏页面特定区域。当然也能用类名实现相同效果,但自定义标签更有趣。
https://github.com/aaviator42/yes-script
顺便一提,通过脚本媒体特性也能纯CSS实现:https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/A…
我不知道有这种特性。感谢分享!非常实用的API
多年前,我决定重新发明
blink标签,因为那些浏览器制造商取消了对它的支持。我原以为标签类型是固定的,没想到竟能随意创造。尝试后发现只需借助jQuery粘合技术和可见性设置,就能修复浏览器并复活辉煌的闪烁效果。
曾考虑开源这个方案,但代码不过十行左右,而且我怀疑已有成百上千种实现相同功能的方案。
> 因为那些浏览器制造商的怪物们取消了对它的支持
大多数浏览器从一开始就没实现过这个功能。Safari、Chrome、IE和Edge从未支持过。就当前浏览器而言,直到2013年之前,只有Firefox和Opera支持过。
咦,我本以为Internet Explorer曾经支持blink标签,但父母很早就用Netscape和Mozilla了,可能是我记混了。
无论如何,我坚持原来的观点。怪物们!我就是要浏览器这么惹人厌。
别在意,微软用<marquee>标签赢了你。
理论上,1996年网景和微软曾同意淘汰<blink>和<marquee>标签<https://www.w3.org/People/Raggett/book4/ch02.html>,但尽管它们被排除在规范之外, 但两家都未移除其实现。随后IE垄断浏览器市场,<marquee>流行度飙升,迫使其他厂商也加入支持(网景2002年跟进,Presto引擎2003年跟进,KHTML/WebKit时间线不详),最终该标签被纳入HTML标准。
KHTML于2003年10月添加<marquee>支持(Chromium代码库提交记录7bcdd98aa)。
不得不说,这真是精妙的侦探工作。
我记得读过关于如何用IE行为特性实现闪烁效果的文章,那是IE专属但未普及的技术(?),大概是IE5时代的事。
早在Chrome和Safari出现前,IE就已阻碍技术进步。
> IE拖累了技术进步
啊,那段岁月。IE接受<table><tr><td><tr></table>结构,而Netscape却强制要求<table><tr><td></td></tr></table>格式,否则就只显示一片空白灰色区域。
当时人们反而喜欢手动输入这些标签,因为漏写/td标签不会导致页面崩溃。
包容性最终胜出。
我还记得JavaScript登陆网络的那天。
那些靠<meta refresh>伪装实时更新的“聊天室”瞬间失去防御能力
<script>document.write(‘http://twistys.com/folder/porn.jpg’)</script>
或是警报弹窗轰炸
啊,那些日子。<script>document.createElement(“table”).appendChild(document.createElement(“table”))</script>会让IE崩溃,而类似的蠢操作甚至在Windows 98时代都可能导致蓝屏。
(我记得这段代码就是其中一例,就算不是完全相同也差不多了。)
如今完全可以用CSS实现!https://www.w3docs.com/tools/code-editor/13719
我把
.blink改成blink,这样就能定位标签而不是类了,看起来挺管用这不奇怪,我见过很多用CSS实现的酷炫效果。
我向来不是前端专家,在彻底告别网页开发前,用JQuery拼凑功能基本是我的惯用手段。
说到这个,Flash从网页消失至今仍让我惋惜。
据我所知至今没有替代方案。
严格来说,通过基于WebAssembly的模拟器Ruffle仍可使用Flash:
https://ruffle.rs/
Kongregate和albinoblacksheep等网站正借助它复活旧版游戏库。
Flash确实有趣,但它从不追求响应式设计,更无法在单一应用中兼顾桌面端和移动端。所有内容基本都是固定布局。若要加入响应式设计,恐怕会丧失“简单易用”的特性。
尽管Flash作为技术确实糟糕,但它确实激发了网络上大量视觉艺术创作。你在StumbleUpon上看到的酷炫内容有一半是用Flash制作的——那些不精通JS/CSS的人,反正用这些技术也无法实现同样的效果。
我坚持认为Flash是编写软件最有趣的方式,尤其在游戏开发领域。
能够即时将动画转化为代码的过程令人无比满足。
至今我尚未找到能替代它的平台,尽管GameMaker提供了一种近似的解决方案。
继续用Flash不就行了?现在叫Animate了。https://www.adobe.com/products/animate.html
我知道,但缺乏完善的部署共享方案,体验终究不同。
我知道Ruffle,但我不想做针对模拟器的复古游戏,想要持续更新的作品。
而且Animate的定价模式简直荒谬。
你可以导出为HTML/CSS/JS文件上传到任何平台。
好走不送。我曾有幸与众多艺术家共同登上惠普官网专题。但当时采用的是Flash技术——作品被压缩成网站中央的小矩形区域,点击才能逐件浏览展览。这意味着浏览路径与浏览器地址栏脱节,每件展品都没有独立URL。当你想引导他人观看作品时,唯一方法是提供“日本式访客地址”——就像这样:“先到知名地标(域名)处,向西行至高耸黑楼,右转后左转第三条巷子,我住巷内第五栋”。
据我所知,替代方案多得是。
真的吗?Flash多年来简直是我的噩梦,当银行停止使用它时我欣喜若狂,终于能彻底卸载这个东西了。
我个人很庆幸闪烁效果消失了,这种行为本就需要比简单HTML元素更深层的设计考量。
我总觉得移除它会让互联网失去乐趣。90年代的网络本质上是极客们的游乐场,人们纯粹为乐趣而创作,几乎不考虑盈利;大家都会托管自己糟糕的网页。我九岁时从学校买来《自己动手做网页:儿童指南》,这才是我真正接触“编程”的起点(除了让乌龟在屏幕上爬行)。当时九岁小孩就能做到这些,因为网页编程简单又有趣。那时没有数以亿计的JavaScript框架,CSS还是新生事物(甚至不一定被支持),一切都靠标签实现——我对此着迷不已。
没错,那些网站丑陋又惹人厌,但用个不太恰当的词形容——它们带着某种“纯粹”。那时的创作毫无世故算计,网站并非像如今这般为迎合企业而生。那时流行低分辨率的背景贴图,无数网站循环播放着《X档案》主题曲的劣质MIDI音效,还有那些炫耀“用记事本编写”的网站图标,以及铺天盖地的动画GIF。
我觉得Blink浏览器的消失只是网络变得越来越乏味的表象。过去人人都能创建自己的网站并自由定制,如今却只剩下十来个千篇一律的网站,活像都是由大公司为取悦股东而设计的模板。
是啊。
在博客被称为“博客”之前,人们只是随心所欲地写自己想写的内容,用任何方式创作(vi?pico?记事本?网景通讯器的HTML编辑器?MS FrontPage?当然可以!),然后上传到ISP的~/public_html/index.html目录下(或类似位置),[甚至直接托管在拨号调制解调器背后的个人电脑上]——仅此而已。
网站的曝光主要依靠:- 网站环链(越专业越好——通常如此)- 原始搜索引擎偶尔的关键词匹配- (只需些许运气)被雅虎人工收录的索引
这已足够。无需追逐广告收益,也不指望网站会爆红。没有自定义域名,没有Wordpress托管,没有资金投入,更不期待回报。没有CSS,没有框架,没有JS这类客户端繁琐操作,甚至没有图像地图。
只有段落文本、闪烁的标题、点击后变紫的蓝色链接,偶尔点缀几张图片或表格。简单的标记,简单的呈现。
最后加上一张颗粒感十足的低分辨率静态猫咪GIF(朋友用扫描仪从4×6照片制作而成),几个指向他人简易页面的链接,底部嵌着某个互联网角落找来的亮绿色访问计数器,再点缀个Netscape Now按钮——就这样放任它存在吧。
那确实是个更纯粹的年代。
你让我笑出眼泪…
> <main-article>
> <article-header>
> <article-quote>
> <quote-body>
这并非最佳示例,因为实际情况中你完全可以直接使用标准HTML标签
使用预定义HTML标签时,浏览器还会自动应用其认为合适的默认样式。
这样就能为所有自定义元素设置默认样式:
太棒了,我正想尝试解决这个问题呢。谢谢!
当然可以!所有元素都有内联默认样式(如
<span>),可根据需要设置基础CSS。这简直是HTML最不为人知的秘密?未知标签会转换为HTMLUnknownElement并像span一样行为。编辑:过去避免这样做是因为命名空间问题。但标准规定使用连字符即可,原生元素永远不会使用
-。编辑2:更棒的是它也完美兼容CSS选择器。在纯HTML文档中写
<image-container>完全没问题。编辑3:即使像
<albums>这类短期内不会被HTML标准采纳的标签,只要不与现有元素冲突也能正常使用。即便未来罕见地被标准采纳为元素名,也可通过简单文本替换解决。编辑4:这些其实与JavaScript关联不大,但你可以像使用原生名称那样,用
querySelector和querySelectorAll查询任何自定义名称。这种编写方式非常美妙。我曾短暂使用过Vue并觉得不错(当时需要它?),但现代HTML已填补了这个空白。
细节纠正:若非标准元素名称包含连字符(且符合语法规范的自定义元素命名规则),该元素的DOM对象应继承自HTMLElement而非HTMLUnknownElement。
标准原文如此阐述:“在有效自定义元素名称的情况下使用 HTMLElement 而非 HTMLUnknownElement,旨在确保未来任何升级仅引发元素原型链的线性过渡——从 HTMLElement 到其子类,而非横向跳转至无关子类。”
早年间,Internet Explorer无法支持HTML5标签。我在2010年的库[0]中找到一段曾用于解决此问题的代码片段。若通过JavaScript创建标签,IE竟能识别它们——尽管创建后需立即销毁。以下是我的脚本:
很快我就意识到,只要添加任意随机标签,将其加入我的兼容层,就能在任何浏览器上渲染出来。
[0]: https://idiallo.com/blog/revisiting-my-old-javascript
我确信流行的html5shim过去也是这么运作的。记得当时出于好奇查看过源代码。
但这样做并无实质意义,反而会混淆哪些元素具有语义——即为屏幕阅读器和搜索引擎等提供格式、功能和含义——而哪些是自定义元素因而不具备语义意义。
若没有原生语义标签能满足需求,我宁愿根据场景选用div或span,并通过一个(或多个)类名进行标识。这正是类名的本质用途,且始终如此。
自定义HTML元素的支持更适用于:为真正官方元素提供polyfill,或处理更复杂的UX控件——这类控件在概念上确实应作为交互对象存在,而非单纯的CSS格式化工具。
若将自定义元素名称作为常规格式化替代CSS类名的通用做法,只会制造混乱而非清晰。
虽然文章未提及,但创造并使用自定义元素其实存在极佳理由:浏览器能自动为其动态行为注入数据。例如:
并通过JS处理展开器的行为:
对于事件处理程序设置时已存在于页面中的
.expanderdiv,这段代码运行正常。但若动态加载新的展开器 div 呢?你的事件处理程序无法追溯性地为它们设置点击监听器。自定义元素恰好解决了这个问题。现在你可以这样做:
然后设置监听器:
浏览器将确保为所有展开器始终设置监听器,无论它们是初始加载到页面还是后期动态注入。若无此机制,你将不得不费尽周折来确保实现。这提供了一个优雅的解决方案。
当你在轻量级DOM解析前定义Web组件时,this.querySelector将返回空值,因为connectedCallback会在标签初始化时触发。
上述代码仅在DOM解析后定义Web组件时有效;使用“defer”或“import”会使JS文件在DOM解析后执行,你只是“修复”了问题却未理解根本原因。
我很久以前就写过相关博文:https://dev.to/dannyengelman/web-component-developers-do-not…
正因如此,我总将JS文件置于HTML主体底部,正是为了规避此类问题:https://github.com/yawaramin/dream-html-ui/blob/92f2dfc51b75…
请注意,connectedCallback会在自定义元素每次被添加到DOM时触发。因此应通过内部追踪元素是否已初始化,确保仅添加一次事件监听器。
感谢提醒,这很有用。某些场景下自定义元素不会多次添加到 DOM 中,例如在 htmx 中,我返回的 HTML 标记会被注入页面后永久保留,至少会持续存在直到被新响应的标记替换。
这点值得注意,我确实说过自定义UX组件是概念上更适合使用自定义标签名的场景。
我真正反对的是将它们用于通用文本和布局的CSS格式化,而非作为类名使用。
没错,自定义元素的加载行为很出色。你甚至无需在JS包加载时做任何特殊处理。
只需渲染你的<element>(服务器端渲染即可),当JavaScript下载并执行时,自定义元素就会自动挂载并发挥作用。
> 没有实际原因
在https://janetdocs.org/实现语法高亮时,此举使首页.html文件从51kb缩减至24kb,压缩后从8kb降至6kb(当时数据)。
为什么会造成混淆?因为你不熟悉它?事物总在变化…
因为现在需要追踪的原生元素实在太多。
当看到名称看似简单的陌生标签时,你根本无法分辨它是原生标签还是格式标签。
这很混乱。它将两类事物混为一谈,导致无法区分。
其实有明确规则:含连字符的就是自定义元素
这条规则无法反向推导。若无连字符,则可能属于任意类型。
所以现在必须强制要求所有原类名标签都使用连字符?即便单词本身根本不需要连字符?
你明白吗?这只会让事情变得更混乱,而非更清晰。
直接用类名就行。这才是它们存在的意义。
只有原生元素才能用单词形式,创建自定义元素时必须使用连字符。
https://lit.dev/
这正是Lit框架(基于自定义元素API)的设计初衷!我最近用它构建项目,体验相当不错,个人认为比当前React的实现更易于理解。
该框架起源于谷歌,现已开源至OpenJS。
我刚为工作评估过Lit,虽然最终未采用,但体验非常出色。无论是否使用Lit,我都钟爱基础的自定义元素API——事实证明,仅凭它就能打造出无缝衔接的复杂UI。
关于Lit/Web组件有个未明确标注的特性:为元素样式化需要绕过诸多限制。若全局应用Tailwind样式库,你自然希望将其无缝集成到自定义组件中,而非添加冗余代码。我的主应用会编译成单一的压缩版 app.css,现在要把它嵌入每个组件感觉不够模块化。替代方案是创建子类将 Tailwind 注入 Lit 组件。如果能有个开关直接继承页面现有样式就完美了。
> 如果能有个开关直接继承页面现有样式就完美了。
它确实有!<https://lit.dev/docs/components/shadow-dom/>
默认情况下,Lit渲染到shadow DOM中。这带来了封装性等优势(包括你提到的样式封装)。若偏好全局样式,只需一行切换代码即可改为渲染到light DOM。
但需注意:组件嵌套(组合)必须依赖 shadow DOM。因此主题化方案通常建议利用组件样式数组选项:
将共享样式定义在
themeStyles中,即可让所有需统一主题的组件共享样式。我还编写了一个简易库,方便在Lit组件中实现通用样式:
https://github.com/gitaarik/lit-style
哦,不错!我之前不知道能直接切换到light dom。
就这么简单!我喜欢用tailwind/utility类,所以样式需要分层编译CSS文件,而不是一个巨型文件。
轻量级 DOM 的主要缺点在于元素无法整洁组合,因为无法区分组件自身渲染的内容与子内容。
当需要重渲染组件时,组件如何区分不替换你渲染的子内容与它渲染到轻量级 DOM 中的子内容?这就是为什么需要阴影 DOM 和插槽——这样就能避免内容与组件内容的混杂。
若无意组合组件则不成问题,但组合时将迅速遭遇限制
此问题存在长期标准争议:https://github.com/WICG/webcomponents/issues/909
虽然可以轻松地按组件关闭阴影 DOM 渲染,但这会导致无法使用插槽功能。该方案仅适用于叶节点。
不过将样式表引入每个组件其实并非坏事。采用样式表允许你在所有阴影根节点间共享同一个样式表实例,因此速度相当快。
有意思,既然你们愿意分享,我很想知道最终放弃这个方案的原因!至少能让我判断是否需要关注其他有潜力的框架。
我认为公司采用Lit框架来创建复杂组件(如高度交互的面板/控件)用于大型生态系统中React/Angular应用间的共享,具有充分合理性。但最终决策是:1. 优先共享纯JS/TS代码而非框架代码,故先尝试此方案;2. 若组件过于复杂且难以正确实现,则可能需要在每个框架中重新实现(或采用某种封装方案)。
我对Lit的次要顾虑在于:在长期运行的React/Angular应用中同时使用阴影DOM和轻量级DOM会增加复杂度。要求75名以上贡献者接受全新范式,其门槛相当高。
确实,若将此方案作为共享组件库推广至多个应用,情况就大不相同了。混合使用不同DOM抽象层确实可能引发复杂问题。
而且尝试为如此多人引入新范式,无疑是项艰巨任务。从许多角度看,这更多是政治博弈而非技术难题。
感谢分享!
最终你们采用了哪种方案?
我在https://lyra.horse/blog/2025/08/you-dont-need-js/#fn:3也看到过类似说明:
> 只要元素名称包含连字符,你就可以自由定义新元素。除链接中列出的8个现有标签外,没有任何HTML标签包含连字符,未来也不会出现。规范甚至将<math-α>和<emotion->作为允许的名称示例。在自主定制元素上可自由定义属性,但对于其他元素(内置或扩展),仅应创建data-*属性。我在博客中大量运用此机制,使HTML和CSS编写更优雅,避免无意义的div堆砌。↩
(HN过滤了第二个示例中的“心形眼睛表情”。)
这是Web组件及所有主流框架的基础。在此模型中,普通<div>的唯一用途是承载无需特殊可复用布局或行为的内容。所有酷炫功能都应提升为自定义组件。
其卓越之处在于:任何未来版本的HTML都无法使你的自定义组件失效,因为它在“底层硬件”级别就获得了支持。
几年前我曾撰文[0]阐述这种模式的形成过程与原理。
0: https://levelup.gitconnected.com/getting-started-with-web-co…
大约十五到二十年前,在连字符命名规范、影子 DOM 等概念出现之前,JavaScript 库曾短暂流行自定义元素。后来大家普遍认为这是糟糕的做法,这种做法逐渐失宠。
如果真要使用这类元素,我会倾向于采用厂商前缀命名,主动规避任何潜在冲突
Angular正是如此实现的——其组件通常以自定义标签形式渲染。我认为这是Angular为数不多的亮点之一,在大型代码库中追踪组件时尤为实用。虽然多年未使用 React,但不禁思考:若将自定义标签作为规范,是否同样能带来便利?
https://janetdocs.org/ 的语法高亮正是如此实现:
“` <pre><code class="janet">(<special>defn</special> <symb>bench</symb> <str>`Feed bench a wrapped func and int, receive int for time in ns`</str> [<symb>thunk</symb> <symb>times</symb>](<特殊>def</特殊> <符号>bench</符号> <字符串>`Feed bench a wrapped func and int, receive int for time in ns`</字符串> [<符号>thunk</符号> <符号>times</符号>] “`
这确实挺酷,但文章指出了该策略的一个重大隐患——本文未提及的隐患。即许多这类标签(如<special>、<keyword>等)未来可能成为HTML标准的一部分。
文章指出,任何带破折号的标签都保证不会被纳入标准。另有评论者分享了采用<x-special>、<x-symb>等命名规范的策略。或许将x替换为j更合理,能避免未来与网页标准冲突的隐患。
确实,我曾因<math>标签冲突困扰一个月,直到有人发现其中细微错误。
事物应当尽可能简单。
目标是让内容可被任何系统读取。随着越来越多用户通过ChatGPT等系统获取信息而非直接访问网站,无法被AI爬虫轻松解析的内容将面临实质性隐形风险。
参见:https://github.com/ai-first-guides
不知你怎么看,但我个人希望自己的网站内容不会被AI抄袭
ChatGPT让内容可见而作者隐形。谁还愿意为AI优化内容?
为可读性添加自定义标签,是那种理论上听起来不错、实践中却很愚蠢的主意。
想象一下
<readable-code>这种标签,结果Slack讨论组里三位资深工程师争论该用<user-profile-card>还是<profile-card-user>,而开发者早已默默用<div class="card">实装完毕。我会在自己的应用里直接用<card>(强调“自己的应用”)
我知道这些标签,但除了自定义HTML组件(需要JS支持)外,我认为它们实用性有限。我更倾向于尽可能使用标准语义元素,它们能直接提供良好的SEO和无障碍支持。
“可以”和“应该”在此处截然不同;当然存在例外情况,但通常而言我认为应优先使用现有标签。
这相当于…无模式但支持CSS的XML。很酷。
从事这行已逾二十载
任何需求都能完美实现,极大简化了我的工作。当然作为独立开发者,我对此并不在意。
你可以在这个演示中查看少量使用的自定义标签https://my.adminix.app/demo
太棒了!我最近还在琢磨如何实现这个功能,显然研究得不够透彻,因为我完全不知道它早已存在[0]。
我特别希望在无类HTML框架中看到这种设计。根据经验,开发者总会需要卡片类组件,结果要么手动编写类,要么依赖某种“按此顺序使用元素”的魔法公式[1]。
要是能有个极简框架,适时加入<card>、<accordian>这类元素就太棒了。
[0] 我确实问过大型语言模型,它也没提到这种特性存在。
[1] 比如pico css就实现了卡片/折叠面板的这类功能。
这是我最爱的技巧之一。当构建包含大量嵌套“上下文”的应用时(不仅限于样式/布局),它能显著提升上下文的检索跳转效率,并帮助大脑快速解析结构。但我会谨慎使用——一旦开始写<父元素-嵌套-第二级子元素-列表项>这类结构,很快就会失控。
自定义元素自有其价值,但多数情况下现有元素已足够使用。
本文的行文方式(如将“than”误用为“then”,提及“article-heading”却未在前例中使用该术语而采用“article-header”)让我觉得作者并未深入思考论题,只是草草写了篇速成文章。
此外,文中提及的问题可通过采用BEM结构命名类名来缓解。
可查看https://radio4000.com的DOM结构,了解如何运用custom-elements和web-components描述整个应用(并支持自定义主题等功能) (来源:https://github.com/radio4000/components)——无需CSS类名,通过HTML属性完整描述应用状态(并反映在样式中)
11年前的案例(但依然有趣):https://github.com/ebidel/html5demos/blob/master/html5-demos…
咦。这让我好奇是否有人为DocBook创建过CSS样式表,看来确实存在。
http://www.badgers-in-foil.co.uk/projects/docbook-css/
超喜欢这个(我的标签表情消失了,该标签意为“常用于表示标签、元数据、标记,以及各种标注含义”)
大约15年前HTML5刚问世时我就学过这个。若想使用<article>这类新标签,唯一需要的“polyfill”就是些CSS样式。早期版本的HTML5 Boilerplate里就能看到:
https://github.com/h5bp/html5-boilerplate/blob/v0.9/css/styl…
我意识到只要自创标签并定义样式就能实现功能。
我认为这种做法充满趣味与奇思妙想,但无疑是无障碍访问的噩梦。
与使用div/span并无区别。
仅用于替代<span>或<div>标签
aria标签大行其道
> 若在名称中包含连字符,可确保该标签永不会出现在未来任何HTML版本中。
哪个未来的版本?我是不是漏掉了什么?我希望HTML6能与原生功能完全兼容,但恐怕我们只停留在HTML5阶段。如果真有HTML6,为什么不能直接声明“本文档使用第5版”,这样就能避免支持标签和自定义标签之间的命名冲突?
HTML5仍在持续新增特性:https://github.com/whatwg/html
但他们永远不会添加带连字符的新标准标签。
> 但我担心我们停留在HTML5阶段就不再前进。
他们已放弃数字版本号。如今HTML正以向后兼容的方式持续演进。
> 若未来出现HTML6,为何不能直接声明“本文档使用第5版”?
因为浏览器厂商反对显式版本声明,这会导致多种渲染模式并存。
我想分享Shoelace[0]——这个精美的Web组件库我曾用于多个网站。它现已并入Web Awesome(Font Awesome背后的公司),不过原作者Cory似乎仍在持续维护。
[0] https://shoelace.style/
你可以这么做,但或许不该这么做。
若因某种原因CSS未能加载,你的网站可能彻底崩溃而非优雅降级。这可能还会影响那些使用特殊浏览器配置的用户。在你这边或许看起来不错,但在用户端我只看到弊端。看似节省了几字节,但经过压缩后可能毫无意义。
出于诸多原因,我大概不会这么做。
话虽如此,若你读完那篇文章仍感兴趣,或许也会喜欢自定义网页组件:https://web.dev/articles/custom-elements-v1
这是为自定义HTML标签增添功能的简便方式。例如创建<my-code>标签时,可自动附加复制按钮并实现代码语法高亮。
哇,这太棒了,释放了无限可能。我原以为这无法实现,或许通过Web组件或<slot>能做到。
顺带一提,我最近正逐个研究所有HTML元素来掌握基础知识,发现许多元素本质上只是带不同默认样式和ARIA属性的<div>或<span>。
而<div>不过是display:block的<span>…
这和TFA都让我意识到HTML其实相当简单。
> 而<div>本质上就是display:block的<span>…
实际情况比这更微妙。HTML5定义了“内容模型”,其中包含“分段内容”和“流式内容”两种类型。分段内容仅能包含文本及文本类标签(em、strong、bold),而流式内容可容纳任意内容。
严格来说,<span>被定义为接受短语内容,<div>接受流式内容。通过CSS改变这些属性并不会改变内容模型。
虽然浏览器对此非常宽容,实际效果并无差异,且这属于深奥领域——我甚至记不起上次有意识思考这些细节是什么时候了。
https://html.spec.whatwg.org/#the-span-element
https://html.spec.whatwg.org/#the-div-element
https://html.spec.whatwg.org/#content-models
值得注意的是,自定义元素无法像预定义元素那样定义特殊解析规则,例如推断省略的标签。通过浏览器API解析自定义标准元素的HTML片段时,其行为基本未被充分规范——因为缺少上下文元素,而该元素正是推断必需省略元素(如<head>、<body>或<html>本身)的关键。那么当自定义元素作为其他自定义元素的子内容出现时又该如何处理?
仅定义自定义元素就需要依赖JS,因此这并非面向文本作者的技术方案。然而作为网页应用的另一种代码组织方式,自定义元素正与JavaScript展开竞争——后者已具备模块、命名空间及面向对象导入等多重特性,灵活性远超前者。
所以照例,GitHub上那些随机人士(即WHAT工作组成员,亦称谷歌托儿)又在拙劣地重造SGML。反正无所谓?终极目标始终是让广告拦截沦为无解军备竞赛,并收集“遥测数据”。
作为极少编写HTML的人(我更像个“后端”开发者,甚至这个称谓都算宽松——我的网页开发经验大多停留在CGI时代,HTML通常由Perl脚本生成),且通常使用vim编辑,得知存在内置解决方案(无需我手动缩进或计数div标签)着实欣慰。感谢你的启发。
相较于计数div元素,更常见的替代方案是使用CSS类名或(针对页面上唯一元素)ID。你只需执行
document.querySelector(‘.my-class’)即可定位<div class="my-class">等元素,而非依赖诸如“某元素嵌套在<body>内三个div层级中”这类条件。即便这个自定义元素技巧失效,我也不理解为何需要计数div(至少在你能控制标记时如此,若无法控制则自定义标签本就不可行)。文章本身也提到了使用类名作为替代方案。
抱歉,我未提及类名是因为文章已明确说明,且我以为读者会理解我对额外输入操作的抵触。这是我的疏忽。
所以,我想我之前的感谢之辞未能充分表达的是:即使不使用CSS样式,能知道存在更简洁的追踪方式本身就值得赞赏。若我自定义标签,它们仅会继承默认样式,但在我看来能清晰区分已闭合的位置与后续插入点。我指的是手动编辑(如前所述在vim中操作),而非动态查询选择器。这样更清楚了吗?
我对自定义标签的顾虑在于其必须使用连字符,这导致标签名与变量名无法保持一致性。
使用类名时,我可以这样写:
但自定义标签无法实现,因为变量名不能包含连字符。
多年前IE浏览器要求使用
document.createElement。当时需要HTML5 Shiv库,相关历史详见https://www.paulirish.com/2011/the-history-of-the-html5-shiv… (2011)
存在一个利用此特性的CSS库:https://github.com/doeixd/CSS-Tags
此外,相较于“div汤”,这可能是为大型语言模型提供更多上下文的有效方式
我发现偏离标准往往会引发成长的阵痛。
https://blog.jim-nielsen.com/2023/html-web-components/ – Jim Nielsen撰写了一系列文章,探讨如何设计自定义HTML标签,使其在定义该元素的JavaScript未成功执行时仍能正常工作。
这正是我多年前将React逐出开发流程的原因。原生Web Components配合dispatchEvent,能让你获得现代网页体验却无需臃肿冗余的依赖;而Vite借助原生ES模块实现轻量级HMR。
服务器端可使用jsdom进行文档polyfill,它同样支持Web Components。
Web Components 糟糕透顶,除极少数需要沙箱隔离的特殊场景外,现代开发绝不该使用它。
若这都能成立,那制定标准的意义难道仅限于屏幕阅读器?
这难道不是所有Web框架的基础吗?比如Vue模板?
框架通常会在构建时将这些转换为标准标签。Vue可跳过构建步骤直接使用,因此该场景下确实会使用自定义组件标签,但不经构建步骤使用Vue的情况并不常见。
看到评论说它们默认像<span>而非<div>的行为,这简直是我今天最大的失望
HTML检测到未知元素时不自动赋予块级样式是合理的。除非你明确为该元素类型指定了块级样式。
内联样式本就是HTML的默认机制。
参见我另一条评论:可通过以下方式设置默认样式:
:where(:not(:defined)) { display: block }
这功能一直存在,甚至无需依赖HTML——序列化为XHTML时,可将标签置于自定义命名空间并为其单独编写CSS。
<!DOCTYPE html>
<html
>
<body>
<CustomElement>Hello</CustomElement><!– XHTML命名空间中的自定义元素 –>
ns1:CustomElementHello</ns1:CustomElement>
ns2:CustomElementHello</ns2:CustomElement>
<style type="text/css">
</style>
</body>
</html>
> 祝你好运,尝试在首次尝试时将内容插入到“article-heading”内部但位于“article-quote”之后的位置。
其实很简单,只需用编辑器折叠代码块,缩小视图至博客代码片段大小,此时当前标签的起止位置就会高亮显示,既不会遗漏也不会需要运气
> 祝你好运,试试看能否在首次尝试时将内容插入到“article-heading”内部但位于“article-quote”之后的位置。
缩进可以解决这个问题。
在该方案被广泛认知、接受并普及之前,我将拒绝采用。带类名的div元素通过伪类更易于检查和修改。我很好奇当JS通过这种方式获取元素时会发生什么。
多年前我被迫采用这种方案,因为当时只有
:nth-of-type选择器而没有:nth-of-class。所以需要按类编号时,就切换到自定义标签并使用:nth-of-type(标签即类型)。其实存在带过滤条件的第n个子元素选择器,例如可写成::nth-child(3 of .red)
https://waspdev.com/articles/2025-06-29/css-features-web-dev…
酷!这下nth-of-type也变得多余了吧。
依我之见,这还意味着自定义标签除了自定义HTML组件外已无太大价值(实现后者还需JS支持)。标准标签本身就具备良好的语义、SEO和无障碍特性。
我非常好奇屏幕阅读器会如何处理这个。真是个糟糕的主意
应该和div/span完全相同。
你可以这么做,但绝对不应该。千万别这么干。请使用
class属性为标签所代表的数据类型提供额外上下文,这才是它的用途。参见https://news.ycombinator.com/item?id=46417607
为什么这样?
嗯…
一方面我希望随意使用标签都能生效。
另一方面…
虽不完全确定,但我似乎更倾向div标签。
我明白语义上并不相同,但我大量使用div和p标签。我刻意回避新增的HTML语义标签,因为这会增加认知负担。宁可局限于div和p标签——毕竟更简单。我通过规范的id来传递附加信息;虽然不同,但我也想保持HTML简洁。所以真的不想新增500个自定义HTML标签。尽管我认为将其作为功能特性或许有用。
严肃提问:你的意思是,相比使用article和blockquote等标准标签,仅用div和p标签构建的网页更容易让你理解吗?
你正在放弃大量功能。听起来你似乎也没使用ARIA,这意味着辅助技术用户无法访问你的网站。
你可以在div标签上添加角色属性,为屏幕阅读器提供支持:
> 我避免使用新的HTML标签…
HTML5规范于2014年发布,因此article、section、header、figure等标签已存在十余年;它们并非如此新颖。