资讯动态

Lynx CSS 伪类与伪元素使用指南:支持清单、实战用法与渲染器源码实现

发布时间:2026/9/14 17:44:04 来源:尧图企业网站定制
Lynx CSS 伪类与伪元素使用指南支持清单、实战用法与渲染器源码实现【免费下载链接】lynxEmpower the Web community and invite more to build across platforms.项目地址: https://gitcode.com/GitHub_Trending/lynx10/lynx本文围绕 Lynx 的 CSS 伪类pseudo-classes与伪元素pseudo-elements支持能力展开先给出完整的支持/不支持清单与可直接复制的实战 CSS 写法再结合 Lynx 渲染器源码CSS 选择器解析、匹配器、DOM 伪元素节点解释这些伪类在引擎内部是如何被解析、匹配和落到组件属性上的。读完本文你不仅能正确编写 Lynx 中可用的状态样式与占位符/选中文本样式还能理解哪些伪类能解析但不生效的根本原因避免踩坑。以下内容继承自官方 API 文档 pseudo-classes.md并结合 selector_matcher.cc、pseudo_element.cc 等源码进行了扩充。一、能力总览哪些能用、哪些只是能解析Lynx 的 CSS 引擎对伪类/伪元素采取解析面宽、匹配面窄的策略。CSS 解析器selector parser会识别几乎所有常见伪类并为其保留枚举定义但真正的选择器匹配器只实现了其中一小部分。从源码结构看这种差异集中体现在两处lynx_css_selector.h 中定义了完整的PseudoType枚举包含kPseudoNthChild、kPseudoIs、kPseudoWhere、kPseudoHas、kPseudoDisabled、kPseudoChecked、kPseudoBefore、kPseudoAfter等大量类型——这说明解析层认识它们但 selector_matcher.cc 的MatchPseudoClass/MatchPseudoElement只处理极少数类型未处理的一律返回false样式不会生效。受支持的伪类 / 伪元素伪类 / 伪元素类型说明:active状态伪类元素被激活按下时匹配:focus状态伪类元素获得焦点时匹配:hover状态伪类指针悬停在元素上时匹配平台支持程度有差异:not()否定伪类排除匹配指定选择器的元素::placeholder伪元素样式化 input 元素的占位符文本::selection伪元素样式化选中文本不受支持❌ 写了也不生效❌:first-child/:last-child/:nth-child()— 结构伪类❌:nth-of-type()/:only-child/:empty— 结构伪类❌:is()— 较新的选择器语法❌:where()— 较新的选择器语法❌:has()— 关系伪类❌:target— 目标伪类❌:disabled/:enabled— 表单状态伪类能解析、不匹配❌:checked— 选中状态伪类能解析、不匹配❌:valid、:invalid— 表单验证伪类❌:required、:optional❌::before/::after— 伪元素❌::first-line— 首行伪元素❌::first-letter— 首字母伪元素一个可以佐证的细节PseudoType枚举中根本没有kPseudoTarget、kPseudoValid等定义这些在解析阶段就会被归为未知类型而:disabled、:enabled、:checked虽然存在于枚举中可解析却不会进入匹配器的分支——这正是文档所说parsed but not matched的源码出处。二、状态伪类:active、:focus、:hover:active — 按下/激活态匹配元素正在被激活通常是手指按下时的状态常用于按钮的按压反馈.button:active { opacity: 0.8; transform: scale(0.98); }:focus — 焦点态匹配获得焦点的元素常用于输入框聚焦时的描边高亮input:focus { border-color: #ff351a; }:hover — 悬停态匹配指针悬停在元素上方时的状态。注意文档中明确提示平台支持程度有差异移动设备无物理指针时该状态可能不会触发写跨端样式时不要依赖它做唯一反馈。.button:hover { background-color: #e63016; }源码印证状态由 DOM 节点的 PseudoState 驱动三个状态伪类的匹配逻辑在 selector_matcher.cc 中实现bool SelectorMatcher::MatchPseudoClass(const SelectorMatchingContext context) const { auto element *context.holder; const LynxCSSSelector selector *context.selector; switch (selector.GetPseudoType()) { case LynxCSSSelector::kPseudoNot: return MatchPseudoNot(context); case LynxCSSSelector::kPseudoHover: return element.HasPseudoState(tasm::kPseudoStateHover); case LynxCSSSelector::kPseudoActive: return element.HasPseudoState(tasm::kPseudoStateActive); case LynxCSSSelector::kPseudoFocus: return element.HasPseudoState(tasm::kPseudoStateFocus); case LynxCSSSelector::kPseudoRoot: return element.tag().str() page; ... } return false; }从源码结构看:hover/:active/:focus并不是靠浏览器事件流实时重算的而是匹配时读取 DOM 节点上的kPseudoStateHover/kPseudoStateActive/kPseudoStateFocus状态位element.HasPseudoState(...)这些状态由平台侧的输入事件在按下/抬起/聚焦时更新。另外同一函数中还暴露了一个文档未列出的实现事实:root被实现为标签是page的节点即 Lynx 页面根元素——从源码看该能力存在但由于官方支持清单未收录使用时建议以文档口径为准。三、:disabled / :enabled 为什么能解析但不生效这是 Lynx 与标准 Web 平台差异最大的一处。文档中的说明是虽然 CSS 解析器认识:disabled和:enabled但 Lynx 的 DOM 层没有实现这两个伪类的匹配因此实际不生效。正确做法是通过增删 class 来表达禁用态样式。对应源码依据很直接PseudoType枚举里有kPseudoDisabled、kPseudoEnabled见 lynx_css_selector.h且 lynx_css_selector_impl.cc 的UpdatePseudoType会把它们合法地归类为伪类——所以解析、样式表构建阶段都不会报错但MatchPseudoClass的 switch 分支中没有这两个 case直接落到return false匹配永远失败。推荐写法直接继承自官方文档/* Recommended */ .button.disabled { opacity: 0.5; background-color: #ccc; }在 JS 侧通过classList增删disabled类名即可得到确定生效的禁用态样式。四、:not() 否定伪类:not()用于排除匹配某个指定选择器的元素在 Lynx 中是完整受支持的/* Exclude elements with a specific class */ .item:not(.exclude) { color: black; }匹配器路径Fiber 架构选择器匹配器对:not()实现了标准的存在即失败语义见 selector_matcher.ccbool SelectorMatcher::MatchPseudoNot(const SelectorMatchingContext context) const { const LynxCSSSelector selector *context.selector; DCHECK(selector.SelectorList()); SelectorMatchingContext sub_context(context); for (sub_context.selector selector.SelectorList()-First(); sub_context.selector; sub_context.selector LynxCSSSelectorList::Next(*context.selector)) { if (MatchSelector(sub_context) kMatches) { return false; } } return true; }即只要:not()内部的任意一个子选择器匹配上了当前元素整个:not()就返回false不应用样式。样式解析路径传统 Radon 架构在非 Fiber 架构下:not()走了另一套全局伪类样式表机制实现在 style_resolver.cc 的PreSetGlobalPseudoNotCSS与ApplyPseudoNotCSSStyle中。从源码注释与逻辑可以看出它做了不少工程化优化按tag/class/id三种作用域scope分别判断是否应用:not()样式元素没有任何 class 且:not()作用域是 class 选择器时直接命中明确处理了.class1:not(.class2)这类复合类 否定的场景见源码注释Handle the case of .class1:not(.class2)全局无元素前缀与局部:not()规则分别通过pseudo_not_global_map与pseudo_map预先组织好命中时直接MergeToken合并进计算样式。特异性specificity计算:not()的特异性规则在 lynx_css_selector_impl.cc 的CalcSpecificityForSimple中体现:not()/:is()/:has()取内部选择器列表的特异性:where()取 0其余伪类按 class 级0x000100计。这与 CSS 标准中:not()继承参数特异性的口径一致因此写.item:not(.exclude)时其特异性等价于.item.exclude的组合权重可以据此预判与其他规则的层叠胜负。五、伪元素::placeholder 与 ::selection注意官方文档口径::before和::after不受支持。CSS 解析器能识别它们但选择器匹配器与渲染引擎都没有实现使用它们不产生任何效果。源码层面同样印证了这一点MatchPseudoElement只处理kPseudoPlaceholder与kPseudoSelection两个分支selector_matcher.cckPseudoBefore/kPseudoAfter落入default返回false。::placeholder — 输入框占位符样式化 input 元素的占位符文本input::placeholder { color: #999; font-size: 14px; }::selection — 选中文本样式化用户选中的文本::selection { background-color: #1890ff; color: #fff; }源码印证伪元素样式如何落到组件属性上Fiber 架构中伪元素由PseudoElement节点承载pseudo_element.h / pseudo_element.cc它在构造时复制宿主元素当前的计算样式作为基底再通过属性映射表把命中 CSS 的属性翻译为组件属性下发。映射关系定义在 pseudo_element.cc// ::selection 支持映射到组件属性的样式 { {kPropertyIDBackgroundColor, selection-background-color}, {kPropertyIDXHandleColor, selection-handle-color}, {kPropertyIDXHandleSize, selection-handle-size}, } // ::placeholder 支持映射到组件属性的样式 { {kPropertyIDColor, placeholder-color}, {kPropertyIDFontSize, placeholder-font-size}, {kPropertyIDFontFamily, placeholder-font-family}, {kPropertyIDFontWeight, placeholder-font-weight}, {kPropertyIDFontStyle, placeholder-font-style}, }这段代码给出了一个文档之外的实用信息::placeholder实际生效的属性集合是color、font-size、font-family、font-weight、font-style这五个它们会被翻译为placeholder-color、placeholder-font-size等组件属性通过UpdateAttrMap/PropBundle::SetProps下发::selection则映射background-color、selection-handle-color、selection-handle-size。映射表之外的属性会被PushPseudoStylesToBundle直接跳过style_name map.end()时continue。此外PseudoElement::UpdatePropertyFromStyleMap中对font-size单独走了CSSStyleUtils::ResolveFontSize说明em/rem等相对单位会在伪元素样式应用时被按视口重新解析。相关行为有 pseudo_element_unittest.cc 覆盖例如Constructor用例验证了PseudoElement构造后状态与宿主元素绑定正确、style_map_初始为空。六、综合示例按钮状态继承自官方文档.button { background-color: #ff351a; color: #fff; padding: 12px 24px; } /* Pressed state */ .button:active { background-color: #e63016; transform: scale(0.98); } /* Disabled state implemented with a class */ .button.disabled { background-color: #ccc; opacity: 0.6; }要点回顾按压反馈用:active禁用态不要用:disabled而要用disabledclass 驱动。表单输入框继承自官方文档.input { border: 1px solid #ddd; padding: 8px 12px; } /* Focused state */ .input:focus { border-color: #ff351a; outline: none; } /* Placeholder styles */ .input::placeholder { color: #999; }这组示例组合了本文覆盖的三个支持点:focus焦点态、基础样式、::placeholder占位符颜色。注意::placeholder中如果写font-size单位会按视口解析em/rem支持而像background-color这类不在映射表内的属性不会生效。七、迁移与排查建议从 Web 迁移过来时凡是依赖:first-child、:nth-child()、:has()、::before/::after的样式需要重写结构选择可用显式 class 替代装饰性伪元素可用view子节点或background-image方案替代CSS 写进去没反应 的排查顺序先确认该伪类是否在第一节的受支持清单内若在检查平台是否触发了对应状态如:hover在无指针设备的限制若是::placeholder/::selection检查所用属性是否在前文映射表内以文档清单为契约本文引用的匹配器源码Fiber 架构的selector_matcher.cc与 Radon 架构的style_resolver.cc说明不同渲染架构内部实现路径不同但对外能力以 pseudo-classes.md 的支持清单为准。关键源码与文档索引内容路径伪类/伪元素支持文档ai/skills/lynx-api-docs/skills/using-lynx-api-docs/css/pseudo-classes.md伪类型枚举与特异性常量core/renderer/css/ng/selector/lynx_css_selector.h伪类型归类与特异性计算core/renderer/css/ng/selector/lynx_css_selector_impl.cc状态伪类 / :not / 伪元素匹配core/renderer/css/ng/matcher/selector_matcher.cc:not() 样式表机制Radon 路径core/renderer/dom/style_resolver.cc伪元素节点与属性映射Fiber 路径core/renderer/dom/fiber/pseudo_element.cc伪元素单测core/renderer/dom/fiber/pseudo_element_unittest.cc【免费下载链接】lynxEmpower the Web community and invite more to build across platforms.项目地址: https://gitcode.com/GitHub_Trending/lynx10/lynx创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价