Lynx CSS 与 Web CSS 差异全解析:display、盒模型、margin 折叠与布局陷阱的迁移实战指南

Lynx CSS 与 Web CSS 差异全解析:display、盒模型、margin 折叠与布局陷阱的迁移实战指南 Lynx CSS 与 Web CSS 差异全解析display、盒模型、margin 折叠与布局陷阱的迁移实战指南【免费下载链接】lynxEmpower the Web community and invite more to build across platforms.项目地址: https://gitcode.com/GitHub_Trending/lynx10/lynxLynx 支持绝大多数常用 CSS 特性但在布局引擎 Starlight 中仍存在若干与 Web 渲染引擎的系统性差异直接影响页面从 Web 迁移到 Lynx 后的视觉效果。本文系统梳理 Lynx 与 Web CSS 在display取值、flex 收缩下界、默认布局行为、百分比尺寸循环依赖、盒模型、定位、文本处理、伪元素、z-index、选择器、单位与动画函数等 15 个维度的差异并给出可落地的迁移改写方案与完整检查清单。读完本文你可以对照源码级证据定位每一处差异的底层成因并在迁移项目中一次性排除绝大多数像素级偏差。1.display属性取值支持与 Starlight 布局模式Lynx 的display属性取值与 Web 存在显著差异核心区别在于Lynx 没有真正的块级盒布局block只是兼容值而 Lynx 独有的linear、relative是 Web 没有的一等布局模式。WebLynx说明display: block⚠️ 兼容值会解析为某种 Lynx 布局模式建议显式使用 Flex 或 Linear 布局display: inline❌ 不支持改用text元素display: inline-block❌ 不支持使用 Flex 或 Linear 布局display: table*❌ 不支持改用 Grid 或 Flex见下方迁移示例display: flex✅ 支持标准 Flexboxdisplay: grid✅ 支持CSS Grid 子集display: linear✅ Lynx 独有类似 Flex column性能更好display: relative✅ Lynx 独有Android 风格的相对布局display: none✅ 支持隐藏元素注意Lynx不支持display: table、table-row、table-cell及相关取值。CSS 解析器会将它们视为无效并回退到默认布局Starlight 布局引擎中不存在TableLayoutAlgorithm。从源码结构看这一结论可以得到印证core/renderer/starlight/layout/ 目录下实际存在的布局算法实现只有box_layout_algorithm、flex_layout_algorithm、grid_layout_algorithm、linear_layout_algorithm、relative_layout_algorithm和staggered_grid_layout_algorithm没有任何 Table 布局算法因此table*系列取值在 Lynx 中无实现基础。display: block的兼容行为也有明确的源码路径。GetDisplay 函数中} else if (display_ DisplayType::kBlock) { if (!configs.css_align_with_legacy_w3c_) { LOGW(Unexpected display type: (int)display_ !! Fall back to default display.); return DisplayType::kFlex; } else { return DisplayType::kLinear; } }警告在非 W3C 兼容模式未开启css_align_with_legacy_w3c_下使用display: block控制台会输出Unexpected display type!! Fall back to default display.此时实际回退为 Flex 布局在 legacy W3C 兼容模式下则解析为 Linear 布局。建议统一改用display: flex或display: linear显式声明布局模式。2. Flex 收缩与基于内容的最小尺寸min-content 下界flex-shrink只在主轴可用空间不足时才生效flex-direction: row时看宽度flex-direction: column时看高度。如果父容器既没有显式width或height也没有被外层布局、最大尺寸或视口约束它会随内容展开不会产生负的空闲空间flex-shrink也就不会改变最终尺寸。Lynx 与 Web 的关键差异在于主轴收缩的下界。Web flex item 默认min-width: auto或min-height: auto文本、图片、嵌套子节点等固有内容可以建立起基于内容content-based的min-content最小尺寸收缩到该尺寸即停止。Lynx 在解析flex-shrink时不会自动应用这一保护你必须显式设置min-width、min-height或flex-shrink: 0。可以认为 Lynx 的默认行为等价于在 Web 上把 flex item 的主轴最小值显式设为0——类似 row 中的min-width: 0或 column 中的min-height: 0。该差异对 row 和 column 都成立.row { display: flex; width: 80px; } .row .content-item { width: 120px; flex-shrink: 1; } .column { display: flex; flex-direction: column; height: 80px; } .column .content-item { height: 120px; flex-shrink: 1; }在 Lynx 中.content-item会沿主轴继续收缩实际宽度或高度可能小于内容所需尺寸。在 Web 中row 的默认min-width: auto或 column 的min-height: auto会基于内容建立自动最小尺寸item 收缩到该值就停止从而导致溢出、挤压缩放兄弟项或产生 Web 预览与 Lynx 结果不一致的问题。让 Web 预览对齐 Lynx 的收缩行为——显式关闭 Web 的自动最小尺寸/* Row允许文本项继续收缩 */ .text-flex-item { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } /* Column允许纵向项继续收缩 */ .column-flex-item { min-height: 0; }让 Lynx 更接近 Web 的内容不可收缩行为——在 Lynx 中显式保护该元素.content-item { flex-shrink: 0; /* 或者显式设置主轴最小值 */ min-width: 120px; min-height: 120px; }3. 默认布局行为重点Web 默认是块级流布局Lynx 默认是 Linear 布局/* Web省略 display 时默认 block 流布局。 */ div { /* 默认display: block */ } /* 块级子元素 width: auto 时使用父级可用宽度纵向排列。 */ /* Lynx省略 display 时默认 Linear 布局。 */ view { /* 默认display: linear; linear-direction: column */ } /* 未指定交叉轴尺寸的孩子会填满父级交叉轴。 */对子元素尺寸的影响Web 块级布局中width: auto的块级子元素使用父级可用宽度。Lynx Linear 布局中子元素并非在所有方向上都继承父级尺寸但交叉轴默认会拉伸当父级交叉轴尺寸是确定值且子元素在该方向没有尺寸或尺寸为auto时子元素在扣除该轴 margin 后会填满父级交叉轴。在默认linear-direction: column下宽度是交叉轴父级有显式width而子级没有时子级填满父级宽度。高度是主轴没有height的子级仍由内容、linear-weight或显式尺寸决定不会自动填满父级高度。/* Web子元素自动填满父级可用宽度。 */ .parent { width: 200px; } .child { /* 默认 width: auto使用父级可用宽度。 */ } /* Lynxcolumn Linear 布局中无宽度的子元素填满交叉轴。 */ .parent { width: 200px; display: linear; linear-direction: column; } .child { /* 默认 width: auto等于父级内容宽度减去水平 margin。 */ } /* Lynx主轴尺寸不会自动拉伸。 */ .parent { height: 200px; display: linear; linear-direction: column; } .child { /* 没有 height 时高度由内容决定不会变成 200px。 */ }嵌套元素尺寸Web 中嵌套块元素的宽度逐级使用每一层父级的可用宽度。Lynx Linear 布局中嵌套view可以跟随父级交叉轴尺寸但不会自动填满主轴。一个没有内容、没有显式主轴尺寸、也没有linear-weight的空view主轴尺寸可能为0。/* Web嵌套 div 逐级使用各父级的可用宽度。 */ .grandparent { width: 100px; height: 100px; } .parent { /* width: auto 解析为 100px高度仍由内容决定。 */ } .child { /* width: auto 跟随父级可用宽度高度由内容决定。 */ } /* Lynx交叉轴宽度跟随父级主轴高度不拉伸。 */ .grandparent { width: 100px; height: 100px; display: linear; linear-direction: column; } .parent { /* 无 width 时为 100px 宽若为空且无 height其 height 可能为 0。 */ } .child { /* 无 width 时跟随父级若为空且无 height其 height 可能为 0。 */ } /* 两个维度都要填满时显式设置主轴尺寸。 */ .parent { width: 100%; height: 100%; } .child { width: 100%; height: 100%; }4. 百分比尺寸的循环依赖当子元素使用百分比尺寸时其解析尺寸依赖于父级。如果父级或祖先对应方向尺寸是auto、fit-content或max-content且必须由内容推导就形成循环依赖内容尺寸决定容器尺寸。容器尺寸决定内容的百分比尺寸。Web 浏览器通常按 CSS Sizing 规则解决此类循环百分比若初始无法解析就以auto参与固有尺寸计算在 Flexbox 等布局中浏览器可能在容器获得确定尺寸后重新测量得到新的百分比结果。Lynx Linear 布局为性能考虑倾向于单次测量路径不会像 Web 或 Flex 布局那样反复解析循环依赖因此百分比尺寸更可能无效、空节点主轴尺寸可能为0、或 Lynx 与 Web 结果不一致。典型风险场景包括子元素在height: auto的容器中使用height: 50%而子树内容决定容器高度。文本或组件在width为fit-content或其他由内容决定的容器中使用width: 50%。ReactLynx 2 组件没有显式display、width、height中间层使用默认布局而打断了预期的 Flex 百分比解析链。多层嵌套的百分比尺寸在默认 Linear 布局下依赖auto主轴尺寸例如水平 Linear 布局中多层height: 50%。/* 有风险内容决定父容器高度 * 而子元素高度又依赖该容器。 */ .outer { display: linear; height: auto; width: 200px; } .middle { display: linear; height: 50%; } .inner { height: 100px; }迁移建议避免在内容定尺寸content-sized的祖先之下使用百分比尺寸。在依赖链上的关键祖先设置显式width或height。分配剩余空间时优先使用flex-grow/flex-shrink或 Linear 布局中的linear-weight而不是先用内容撑开容器、再套百分比。如果必须依赖循环百分比尺寸确保整个子树都使用 Flex 布局。中间插入 Linear 布局、带自定义测量的元素如text、或 ReactLynx 2 组件的默认布局都会产生与 Web 不同的结果。在 ReactLynx 2 中组件本身就是布局元素。在组件根元素上显式设置display、width、height防止隐式默认布局改变百分比解析结果。5. 盒模型默认box-sizing不同/* Web 默认 */ box-sizing: content-box; /* Lynx 默认 */ box-sizing: border-box;说明Lynx 默认border-boxwidth和height包含 padding 与 border而 Web 默认content-box宽高只作用于内容盒。仓库中BoxSizingType枚举定义了kContentBox与kBorderBox两种取值见 css_type.h并在 layout_computed_style.cc 中参与计算样式解析。从 Web 迁移时可以用全局 reset 保留原盒模型行为* { box-sizing: content-box; }显式设置box-sizing: border-box或content-box只能控制盒模型计算不能消除其他 Web 布局依赖带来的差异。若页面依赖float、浏览器默认bodymargin、行高、绝对定位包含块或 min/max 尺寸钳制这些布局条件也要一并改写否则盒模型正确也可能残留像素级差异。5.1 margin 折叠margin collapsing不支持相邻元素的垂直 margin 在 Lynx 中不会折叠而是直接相加。从 Web 迁移的页面可能因此出现意外的间距/* Web垂直 margin 折叠为 20px。 */ .item1 { margin-bottom: 20px; } .item2 { margin-top: 20px; } /* Lynxmargin 不折叠间距为 40px。 */通用解决方案场景Web 行为Lynx 行为迁移策略相邻兄弟margin-bottom与margin-top折叠为较大值两个 margin相加只在其中一个元素上设置 margin或改用gap、padding父级与首子父级margin-top与子级margin-top折叠两个 margin相加去掉父级 margin交由子级控制父级与末子父级margin-bottom与子级margin-bottom折叠两个 margin相加去掉父级 margin交由子级控制相邻空元素空元素的 margin 参与折叠空元素的 margin正常相加去掉其 margin或加min-height: 1px方案一只在单一元素上设置 margin兄弟场景.item1 { margin-bottom: 20px; } .item2 { margin-top: 0; }方案二用一个 padding 替换一个 margin.item1 { margin-bottom: 0; padding-bottom: 20px; } .item2 { margin-top: 0; }方案三父级使用 Flex 或 Grid 布局时用gap.parent { display: flex; flex-direction: column; gap: 20px; } .item1, .item2 { margin: 0; }方案四推荐去掉父容器 margin交由子级控制父子场景复现 Web 中容器margin-top: 8px、子级margin-top: 1em、折叠后结果为1em的场景/* 原 Web 代码 */ .container { margin-top: 8px; } .child { margin-top: 1em; /* 16px与容器 8px 折叠后仍是 16px。 */ } /* 等价的 Lynx 代码 */ .container { margin-top: 0; /* 去掉容器顶部 margin。 */ } .child { margin-top: 1em; /* 16px直接得到目标间距。 */ }常见触发场景连续块级元素用 margin 拉开间距如段落、标题、列表项。容器与首个/末个子的间距如 body 与其内容、卡片与卡片内容。嵌套组件中外层与内层容器间 margin 叠加。多层嵌套中 margin 逐级累加。空元素如仅含 border 的div带有 margin。5.2 Linear 布局中的负 margin负 margin 在 Lynx 默认display: linear; linear-direction: column布局中工作正常轴场景行为交叉轴margin-left/margin-right负 margin 把子元素拉回父级边界✅ 符合预期主轴margin-top/margin-bottom负 margin 使兄弟元素重叠✅ 符合预期/* 用负 margin 拉回子元素 —— 有效。 */ .parent { border-left: 2px solid red; padding-left: 96px; } .child { border-left: 2px solid black; margin-left: -98px; /* 左移盖住父级的红色边框。 */ } /* 用负 margin 让兄弟元素重叠 —— 有效。 */ .sibling1 { border-top: 2px solid red; padding-bottom: 96px; } .sibling2 { border-bottom: 2px solid black; margin-top: -98px; /* 上移贴住 sibling1 的红色边框。 */ }迁移建议负 margin 在 Lynx Linear 布局中交叉轴与主轴均可用无需特殊处理若看到微小渲染差异应优先检查 margin 折叠补偿项而不是怀疑负 margin 本身。5.3 负 paddingCSS 中非法但 Lynx 接受CSS 规范中padding-bottom: -1px这类负 padding 是非法声明在没有其他合法声明兜底时属性回退到初始值0。Lynx 的 padding 长度解析器LengthHandler::Process不强制非负约束bool Process(const lepus::Value input, CSSValue css_value, const CSSParserConfigs configs) { if (input.IsString()) { CSSStringParser parser CSSStringParser::FromLepusString(input, configs); parser.ParseLengthTo(css_value); return !css_value.IsEmpty(); } ... }解析后的值直接交给布局。布局路径只调用ClampIndefiniteToZero()layout_unit.h该函数只处理不确定值indefinite而不处理负值调用点见 layout_algorithm.cc 与 box_info.cc。结果是负 padding 被原样应用造成布局差异。/* Web-1px 非法回退为 0。 */ padding-bottom: -1px; /* 实际效果0 */ /* Lynx-1px 被解析为合法长度并直接应用。 */ padding-bottom: -1px; /* 实际效果-1px */规避方案在 WPT 迁移或代码评审时把负 padding 替换为0/* 将非法负 padding 替换为 0。 */ .element { padding: 0; /* 而不是 padding: -1px */ }5.4bodymargin 与首子元素margin-top的特判Web 中body的margin: 8px与其首个p的margin-top: 1em会折叠为max(8px, 1em)约 16px。Lynx 中.body { margin: 8px; }与首子的margin-top不折叠而是相加/* Lynx 迁移策略 */ .body { display: linear; linear-direction: column; margin: 8px; } /* 若首子 margin-top 为 0顶部总间距只有 8px。 * 给首子补 margin-top: 8px 进行补偿。 */ .first-child { margin-top: 8px; } /* 顶部总间距 8px (.body) 8px (.first-child) 16px。 */6. 长度值与单位固有尺寸关键词intrinsic sizing keywords✅max-content—— 完整支持⚠️fit-content—— 常规流中可用。但对于position: absolute且设置top: 0; bottom: 0或left: 0; right: 0的元素max-height/max-width起不到约束作用需改用显式height/width。/* ❌ Lynxmax-height: fit-content 无效 * 元素会拉伸到包含块高度。 */ .abs-box { position: absolute; top: 0; bottom: 0; max-height: fit-content; } /* ✅ 使用显式 height。 */ .abs-box { position: absolute; top: 0; bottom: 0; height: 100px; }❌min-content—— 不支持不支持的单位❌ch、ex❌ 物理单位cm、mm、in、pt、pccalc()的支持范围✅ 支持的属性34 个长度类属性尺寸width、height、max-width、min-width、max-height、min-height定位top、left、right、bottom内边距padding-left、padding-right、padding-top、padding-bottom外边距margin-left、margin-right、margin-top、margin-bottomFlexboxflex-basisFlex/Grid 间距grid-column-gap、grid-row-gap、column-gap、row-gap文本font-size、text-indent变换perspectiveRTL 支持margin-inline-start/end、padding-inline-start/end、inset-inline-start/end❌ 不支持的属性颜色类如color、background-color枚举类如flex-direction、justify-content、align-items边框圆角如border-radius变换类如transform数值类如opacity、z-index/* ✅ 合法 */ width: calc(100% - 20px); margin: calc(var(--spacing) * 2); /* ❌ 非法 */ flex-direction: calc(row); /* 枚举属性 */ color: calc(#ff0000); /* 颜色属性 */推荐单位✅px—— 像素✅%—— 百分比✅vw、vh—— 视口单位与rem搭配时推荐✅rem—— 根字号倍数响应式设计中推荐⚠️rpx—— Lynx 特有响应式像素功能完整但不与 Web 兼容7. 定位Positioningstatic不支持/* Web */ position: static; /* 默认 */ /* Lynx改用 relative。 */ position: relative; /* 默认 */position: fixed必须显式给出left和topWeb 上left: auto或top: auto的 fixed 元素定位在其静态位置正常流中的原始位置。Lynx 不支持静态定位left或top的auto等价于left: 0; top: 0即视口左上角/* ❌ Lynx省略 left/top 时元素落在视口左上角。 */ #fixed-box { position: fixed; /* 实际效果left: 0; top: 0 */ } /* ✅ Lynx始终显式指定 left 和 top。 */ #fixed-box { position: fixed; left: 20px; top: 20px; }8. Float 不支持/* ❌ 不支持 */ float: left; float: right; clear: both; /* ✅ 改用 Flexbox。 */ display: flex; flex-direction: row;9. 文本处理文本必须使用text元素!-- Web文本可以直接出现在 div 内。 -- divHello World/div !-- Lynx使用 text 元素。 -- view textHello World/text /view换行行为/* Web文本默认自动换行。 */ /* Lynxtext 默认不换行需显式开启。 */ text { white-space: normal; /* 允许换行。 */ }10. 伪元素::before与::after不支持/* ❌ 不支持 */ .element::before { content: Prefix; } .element::after { content: ; background-color: red; }说明Lynx 不支持::before/::after。虽然 CSS 解析器能识别这两个伪元素但选择器匹配器与渲染引擎均未实现声明不产生任何效果。11.z-index必须配合position使用/* Webz-index 可独立于 position 使用。 */ z-index: 10; /* Lynx必须同时设置 position。 */ position: relative; /* 或 absolute、fixed、sticky */ z-index: 10;层叠上下文与合成层compositing layerLynx 中z-index会创建新的层叠上下文并可能把元素提升为合成层。结果是scroll-view、scroll-coordinator等滚动容器内的子元素可能无法跟随滚动/* ❌ 问题带 z-index 的子元素可能不跟随滚动。 */ scroll-coordinator-header { /* header 内的子元素设置了 z-index。 */ } .header-item { position: relative; z-index: 10; /* 该元素可能被提升为独立层无法跟随 header 滚动。 */ } /* ✅ 解法父级用 z-index: 0 建立同一层叠上下文。 */ scroll-coordinator-header { position: relative; z-index: 0; /* 让 header 本身成为合成层。 */ } .header-item { position: relative; z-index: 10; /* 现在能正确跟随 scroll-coordinator-header 滚动。 */ }原理子元素设置z-index后会被提升为独立合成层。该层的坐标变换可能不包含父容器的滚动偏移。在父级加上z-index: 0或任意z-index建立层叠上下文子元素保持在同一层内即可跟随滚动。常见场景scroll-coordinator-header内带z-index的元素不跟随滚动。scroll-view内 fixed 元素与可滚动内容的层叠顺序交互异常。浮层弹窗与可滚动内容的层叠顺序交互异常。12. 选择器限制不支持❌ 较新的选择器:is()、:where()、:has()❌ 复杂的属性选择器[attr^val]、[attr$val]等仅部分支持❌ 通用兄弟组合器在复杂场景下可能受限13. 自定义字体字体格式/* Web支持多种格式。 */ font-face { src: url(font.woff2) format(woff2); } /* Lynx使用系统字体或内联 base64 数据。 */ font-family: PingFang SC, Helvetica Neue, Arial, sans-serif;14. 3D 变换函数子集Web CSS 支持scale3d(x, y, z)与rotate3d(x, y, z, angle)但 Lynx 的 transform 解析器目前不识别这两个函数名。含不支持变换函数的声明会被解析为非法若出现在keyframes中对应的transform关键帧不会加入动画曲线。Web 语法Lynx 状态迁移建议scale3d(x, y, z)❌ 不支持只需 XY 缩放时改用scale(x, y)Z 轴缩放用matrix3d(...)显式表达rotate3d(x, y, z, angle)❌ 不支持单轴旋转用rotateX(...)、rotateY(...)、rotateZ(...)任意轴旋转用matrix3d(...)translate3d(x, y, z)✅ 支持直接使用matrix3d(...)✅ 支持复杂 3D 变换的显式兼容形式/* ❌ Web 语法Lynx 不识别 scale3d 与 rotate3d。 */ .card { transform: scale3d(0.6, 0.6, 1) rotate3d(0, 1, 0, 180deg); } /* ✅ Lynx拆分为支持的函数。 */ .card { transform: scale(0.6, 0.6) rotateY(180deg); }迁移动画时尤其要注意/* ❌ 该 transform 关键帧在 Lynx 中解析失败。 */ keyframes zoom { 0% { transform: scale3d(0.6, 0.6, 1); } 100% { transform: scale3d(1, 1, 1); } } /* ✅ 改用 scale(x, y)。 */ keyframes zoom { 0% { transform: scale(0.6, 0.6); } 100% { transform: scale(1, 1); } }15.steps(...)动画时间函数Web 中steps(n)的第二参数可省略默认等价于steps(n, jump-end)。Lynx 中steps(...)必须显式给出步进位置参数steps(1)、steps(4)这类写法非法。Web 语法Lynx 状态Lynx 语法steps(4)❌ 不支持steps(4, end)或steps(4, jump-end)steps(4, start)✅ 支持直接使用steps(4, end)✅ 支持直接使用steps(4, jump-start)✅ 支持直接使用steps(4, jump-end)✅ 支持直接使用steps(4, jump-none)✅ 支持直接使用steps(4, jump-both)✅ 支持直接使用step-start✅ 支持等价于steps(1, start)step-end✅ 支持等价于steps(1, end)/* ❌ Web 上合法Lynx 中非法。 */ animation-timing-function: steps(4); /* ✅ Lynx 要求显式步进位置。 */ animation-timing-function: steps(4, end);与 Web 一致关键帧内部的animation-timing-function作用于当前关键帧到下一关键帧的区间而不是当前点本身keyframes fade-out-after-hold { 0% { opacity: 1; } 80% { opacity: 1; animation-timing-function: step-end; } 100% { opacity: 0; } }其中step-end控制80%到100%的区间透明度保持不变直到区间结束才跳变。快速迁移检查清单从 Web 迁移到 Lynx 时逐项确认替换display: inline与display: inline-block优先显式声明 Lynx 布局模式而非依赖display: block兼容值所有文本包裹进text元素移除所有float与clear改用 Flexbox将position: static替换为relative替换固有宽高的min-contentflex-basis: min-content会退化为0pxmax-content可用凡使用z-index处均补充position检查scroll-view、scroll-coordinator等滚动容器内的z-index是否导致元素不跟随滚动若是在父级添加z-index: 0建立同一层叠上下文移除所有::before与::after二者均不支持排查 margin 折叠依赖将 Web 的scale3d()、rotate3d()替换为 Lynx 支持的scale()、rotateX/Y/Z()或matrix3d()为steps(n)补充步进位置参数如steps(n, end)逐一测试所有white-space设置常见陷阱陷阱一省略text元素// ❌ 错误 viewText content/view // ✅ 正确 view textText content/text /view陷阱二依赖 margin 折叠/* Webmargin 折叠为 20px。 */ .top { margin-bottom: 20px; } .bottom { margin-top: 20px; } /* Lynxmargin 不折叠产生 40px需要调整。 */ .top { margin-bottom: 10px; } .bottom { margin-top: 10px; } /* 或者 */ .top { margin-bottom: 20px; } .bottom { margin-top: 0; }陷阱三使用不支持或仅部分支持的单位/* ❌ 不支持 */ width: 1in; /* ⚠️ 部分支持 */ width: 100vmin; /* ✅ 使用替代方案。 */ width: auto; width: 100%;陷阱四遗漏white-space/* 文本默认不换行。 */ text { white-space: nowrap; } /* 需要换行时显式开启。 */ text { white-space: normal; }陷阱五忘记把body样式复制到page元素Web 用户代理样式表通常给body默认 margin编写样式可能再加 padding 或替换该 margin。Lynx 根元素page默认既无 margin 也无 padding/* Web常见用户代理默认 margin: 8pxpadding 在此编写。 */ body { margin: 8px; padding: 0 8px; } /* Lynx显式复现 body 的计算样式或编写样式。 */ page { margin: 8px; padding: 0 8px; }迁移时保留布局的关键做法是检查 Web 端body的计算样式computed styles与编写样式authored styles再把相关间距在page上复现而不是假设一个固定的浏览器默认值。陷阱六把 Web 的html/body背景映射到普通容器Web 中html是文档根、body是页面内容容器二者遵循特殊的画布背景传播规则。Lynx 没有同名元素page既是页面根也是整页背景的面/* Webhtml 提供页面底色body 提供内容区背景。 */ html { background-color: #f5f5f5; } body { margin: 8px; background-color: white; }迁移到 Lynx 时先判断每个 Web 背景的用途需要整页背景时设置page。需要内容容器背景时设置根view。Web 版本html与body分别设置背景时通常把html背景映射到pagebody背景映射到根view。/* Lynx */ page { background-color: #f5f5f5; } .root { margin: 8px; background-color: white; }若 Web 页面仅靠body背景撑满视口在 Lynx 中直接设置page即可得到最接近的整页效果/* Web */ body { background-color: green; } /* Lynx */ page { background-color: green; }不要把命名为.body的普通view当作 Webbody的等价物普通view只在自身布局边界内绘制背景page才是 Lynx 的根与整页背景面。陷阱七迁移含background-attachment的background简写Web 的background简写可包含background-attachment槽位取值如fixed、scroll。当前支持属性列表不包含background-attachment。迁移时把简写展开为 Lynx 支持的背景属性并单独判断是否需要保留 attachment 行为/* Web */ .box { background: url(bg.png) 0 0 / cover no-repeat fixed #fff; }/* Lynx */ .box { background-image: url(bg.png); background-position: 0 0; background-size: cover; background-repeat: no-repeat; background-color: #fff; }/* 纯色背景直接使用 background-color。 */ .box { background-color: green; }结语Lynx 与 Web 的 CSS 差异集中在布局引擎层默认布局模式Linear 对 block 流、收缩下界无 min-content 保护、盒模型默认值border-box、margin 折叠缺失、滚动容器中的合成层行为以及若干解析器差异负 padding 被接受、scale3d/rotate3d与单参数steps(n)非法。这些差异大多有明确的源码依据——从 GetDisplay 的display回退逻辑到 LengthHandler::Process 对负长度的放行再到 ClampIndefiniteToZero 只处理不确定值——按本文的检查清单逐项排查可以在迁移阶段系统性地消除绝大多数 Web 与 Lynx 之间的渲染偏差。【免费下载链接】lynxEmpower the Web community and invite more to build across platforms.项目地址: https://gitcode.com/GitHub_Trending/lynx10/lynx创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考