@doubao-dev/plugin-app-dev 0.0.0-stage → 0.0.40-canary-dea0ddc73-20261026073950

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/README.md +10 -2
  2. package/dist/147.js +9 -0
  3. package/dist/assets.d.ts +5 -0
  4. package/dist/assets.js +4 -0
  5. package/dist/index.d.ts +43 -0
  6. package/dist/index.js +1378 -0
  7. package/dist/plugin.d.ts +102 -0
  8. package/dist/plugin.js +4995 -0
  9. package/dist/preview.js +16 -0
  10. package/dist/rslib-runtime.js +33 -0
  11. package/dist/skills/doubao-plugin-app/SKILL.md +21 -0
  12. package/dist/skills/doubao-plugin-app/references/app-development.md +85 -0
  13. package/dist/skills/doubao-plugin-app/references/frontend/components/container-overlay.md +131 -0
  14. package/dist/skills/doubao-plugin-app/references/frontend/components/form-controls.md +146 -0
  15. package/dist/skills/doubao-plugin-app/references/frontend/components/interactive-controls.md +120 -0
  16. package/dist/skills/doubao-plugin-app/references/frontend/components/map-canvas.md +107 -0
  17. package/dist/skills/doubao-plugin-app/references/frontend/components/overview.md +43 -0
  18. package/dist/skills/doubao-plugin-app/references/frontend/components/scroll-list.md +149 -0
  19. package/dist/skills/doubao-plugin-app/references/frontend/components/text-media.md +209 -0
  20. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/01-/345/237/272/347/241/200.md +1389 -0
  21. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/02-/347/263/273/347/273/237.md +1376 -0
  22. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/03-/350/207/252/345/256/232/344/271/211/351/200/232/344/277/241.md +127 -0
  23. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/04-/345/256/232/344/275/215.md +784 -0
  24. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/05-/345/255/230/345/202/250.md +1176 -0
  25. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/06-/350/267/257/347/224/261.md +839 -0
  26. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/07-/347/225/214/351/235/242.md +376 -0
  27. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/08-/344/272/244/344/272/222.md +1319 -0
  28. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/09-/350/276/223/345/205/245.md +192 -0
  29. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/10-/347/275/221/347/273/234.md +900 -0
  30. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/11-/345/252/222/344/275/223.md +1496 -0
  31. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/12-/344/270/232/345/212/241/350/203/275/345/212/233.md +1281 -0
  32. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/13-/347/231/273/345/275/225.md +511 -0
  33. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/14-/346/224/257/344/273/230.md +943 -0
  34. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/15-/346/225/260/346/215/256/345/210/206/346/236/220.md +124 -0
  35. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/16-/350/223/235/347/211/231.md +3364 -0
  36. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/17-wi-fi.md +1028 -0
  37. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/18-/345/212/240/351/200/237/345/272/246/350/256/241.md +354 -0
  38. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/19-ibeacon.md +508 -0
  39. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/20-/347/275/227/347/233/230.md +320 -0
  40. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/21-/350/256/276/345/244/207/346/226/271/345/220/221.md +351 -0
  41. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/22-/351/231/200/350/236/272/344/273/252.md +354 -0
  42. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/23-/345/252/222/344/275/223-/350/256/276/345/244/207-/347/275/221/347/273/234.md +264 -0
  43. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/24-/347/237/255/344/277/241.md +155 -0
  44. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/25-/346/227/240/351/232/234/347/242/215.md +144 -0
  45. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/26-/345/237/272/347/241/200/344/277/241/346/201/257.md +238 -0
  46. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/27-/347/224/265/346/261/240.md +235 -0
  47. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/28-/345/211/252/350/264/264/346/235/277.md +303 -0
  48. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/29-/345/212/240/345/257/206.md +126 -0
  49. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/30-/346/227/245/345/216/206.md +417 -0
  50. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/31-/347/224/265/350/257/235.md +144 -0
  51. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/32-/346/211/253/347/240/201.md +236 -0
  52. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/33-/345/261/217/345/271/225.md +747 -0
  53. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/34-/351/234/207/345/212/250.md +277 -0
  54. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/35-/346/226/207/344/273/266/347/263/273/347/273/237.md +431 -0
  55. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/common-errors.md +69 -0
  56. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/groups.md +43 -0
  57. package/dist/skills/doubao-plugin-app/references/frontend/doubao-agentic-service-api/quick-reference.md +436 -0
  58. package/dist/skills/doubao-plugin-app/references/frontend/examples/common-patterns.md +590 -0
  59. package/dist/skills/doubao-plugin-app/references/frontend/examples/doubao-agentic-service-api-recipes.md +209 -0
  60. package/dist/skills/doubao-plugin-app/references/frontend/examples/page-widget-basics.md +368 -0
  61. package/dist/skills/doubao-plugin-app/references/frontend/examples/page-widget-recipes.md +65 -0
  62. package/dist/skills/doubao-plugin-app/references/frontend/framework/core.md +283 -0
  63. package/dist/skills/doubao-plugin-app/references/frontend/guides/auth.md +277 -0
  64. package/dist/skills/doubao-plugin-app/references/frontend/guides/best-practices.md +574 -0
  65. package/dist/skills/doubao-plugin-app/references/frontend/guides/client-tools-and-events.md +209 -0
  66. package/dist/skills/doubao-plugin-app/references/frontend/guides/component-development.md +832 -0
  67. package/dist/skills/doubao-plugin-app/references/frontend/guides/debugger-mcp.md +537 -0
  68. package/dist/skills/doubao-plugin-app/references/frontend/guides/expired-widget.md +101 -0
  69. package/dist/skills/doubao-plugin-app/references/frontend/guides/performance-optimization.md +417 -0
  70. package/dist/skills/doubao-plugin-app/references/frontend/guides/troubleshooting.md +278 -0
  71. package/dist/skills/doubao-plugin-app/references/frontend/lynx/best-practices.md +720 -0
  72. package/dist/skills/doubao-plugin-app/references/frontend/lynx/css/pseudo-classes.md +149 -0
  73. package/dist/skills/doubao-plugin-app/references/frontend/lynx/css/selectors.md +224 -0
  74. package/dist/skills/doubao-plugin-app/references/frontend/lynx/css/supported-properties.md +269 -0
  75. package/dist/skills/doubao-plugin-app/references/frontend/lynx/css/values-and-units.md +314 -0
  76. package/dist/skills/doubao-plugin-app/references/frontend/lynx/layout/flex-layout.md +334 -0
  77. package/dist/skills/doubao-plugin-app/references/frontend/lynx/layout/grid-layout.md +408 -0
  78. package/dist/skills/doubao-plugin-app/references/frontend/lynx/layout/linear-layout.md +355 -0
  79. package/dist/skills/doubao-plugin-app/references/frontend/lynx/layout/relative-layout.md +189 -0
  80. package/dist/skills/doubao-plugin-app/references/frontend/lynx/lynx-vs-web/css-differences.md +737 -0
  81. package/dist/skills/doubao-plugin-app/references/frontend/lynx/lynx-vs-web/migration-guide.md +669 -0
  82. package/dist/skills/doubao-plugin-app/references/frontend/lynx/lynx-vs-web/unsupported-features.md +290 -0
  83. package/dist/skills/doubao-plugin-app/references/frontend/lynx/overview.md +60 -0
  84. package/dist/skills/doubao-plugin-app/references/frontend/lynx/patterns/animation.md +243 -0
  85. package/dist/skills/doubao-plugin-app/references/frontend/lynx/patterns/responsive.md +194 -0
  86. package/dist/skills/doubao-plugin-app/references/frontend/lynx/patterns/theming.md +143 -0
  87. package/dist/skills/doubao-plugin-app/references/frontend/lynx/quick-reference.md +229 -0
  88. package/dist/skills/doubao-plugin-app/references/frontend/rules/dos-and-donts.md +479 -0
  89. package/dist/skills/doubao-plugin-app/references/frontend/widget-templates/design-boundary.md +46 -0
  90. package/dist/skills/doubao-plugin-app/references/frontend/widget-templates/overview.md +118 -0
  91. package/dist/skills/doubao-plugin-app/references/frontend/widget-templates/props.md +301 -0
  92. package/dist/skills/doubao-plugin-app/references/mcp-and-cards.md +38 -0
  93. package/dist/templates/README.md.template +11 -0
  94. package/dist/templates/com.doubao/app/manifest.yaml +41 -0
  95. package/dist/templates/com.doubao/app/package.json.template +13 -0
  96. package/dist/templates/com.doubao/app/src/app.config.ts.template +5 -0
  97. package/dist/templates/com.doubao/app/src/app.ts.template +3 -0
  98. package/dist/templates/com.doubao/app/src/pages/home/index.css +14 -0
  99. package/dist/templates/com.doubao/app/src/pages/home/index.tsx.template +14 -0
  100. package/dist/templates/com.doubao/app/src/widgets/example/index.tsx.template +29 -0
  101. package/dist/templates/com.doubao/app/tsconfig.json +19 -0
  102. package/dist/templates/mcp.json +9 -0
  103. package/dist/templates/plugin.json.template +29 -0
  104. package/dist/templates/skills/example/SKILL.md.template +14 -0
  105. package/dist/upload.d.ts +44 -0
  106. package/dist/upload.js +38 -0
  107. package/package.json +60 -3
@@ -0,0 +1,737 @@
1
+ # Lynx 与 Web CSS 差异指南
2
+
3
+ Lynx 支持大部分常用 CSS,但也有一些重要差异。
4
+
5
+ ## 重要差异一览
6
+
7
+ ### 1. Display 属性
8
+
9
+ | Web | Lynx | 说明 |
10
+ | ----------------------- | ------------ | ---------------------------------------- |
11
+ | `display: block` | ❌ 不支持 | 使用 Flex 或 Linear 代替 |
12
+ | `display: inline` | ❌ 不支持 | 使用 `<text>` 组件代替 |
13
+ | `display: inline-block` | ❌ 不支持 | 使用 Flex 或 Linear |
14
+ | `display: table*` | ❌ 不支持 | 使用 Grid 或 Flex 代替(见下方迁移示例) |
15
+ | `display: flex` | ✅ 支持 | 标准 Flexbox |
16
+ | `display: grid` | ✅ 支持 | CSS Grid 子集 |
17
+ | `display: linear` | ✅ Lynx 特有 | 类似 Flex Column,性能更好 |
18
+ | `display: relative` | ✅ Lynx 特有 | Android-style 相对布局 |
19
+ | `display: none` | ✅ 支持 | 隐藏元素 |
20
+
21
+ > **⚠️ 注意**:`display: table` / `table-row` / `table-cell` 等在 Lynx 中**完全不支持**。CSS parser 会将其视为无效值并回退到默认布局。Starlight 布局引擎中不存在 TableLayoutAlgorithm。
22
+
23
+ > **⚠️ 警告**:在非 W3C 标准模式下使用 `display: block` 会触发控制台警告:
24
+ >
25
+ > ```
26
+ > "Unexpected display type!! Fall back to default display."
27
+ > ```
28
+ >
29
+ > 建议使用 `display: flex` 或 `display: linear` 替代。
30
+
31
+ ### 2. Flex 收缩与内容最小尺寸
32
+
33
+ `flex-shrink` 只有在主轴可用空间不足时才会触发:`flex-direction: row` 时看宽度,`flex-direction: column` 时看高度。如果父容器没有显式 `width` / `height`,也没有被外层布局、最大尺寸或视口约束限制,容器会按内容撑开,不产生负剩余空间,`flex-shrink` 不会改变最终尺寸。
34
+
35
+ 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`。
36
+
37
+ 这个差异既可能出现在 row,也可能出现在 column:
38
+
39
+ ```css
40
+ .row {
41
+ display: flex;
42
+ width: 80px;
43
+ }
44
+
45
+ .row .content-item {
46
+ width: 120px;
47
+ flex-shrink: 1;
48
+ }
49
+
50
+ .column {
51
+ display: flex;
52
+ flex-direction: column;
53
+ height: 80px;
54
+ }
55
+
56
+ .column .content-item {
57
+ height: 120px;
58
+ flex-shrink: 1;
59
+ }
60
+ ```
61
+
62
+ 在 Lynx 中,`.content-item` 会继续参与主轴压缩,实际宽度或高度可能小于内部内容需要的尺寸。在 Web 中,row 方向的默认 `min-width: auto` 或 column 方向的默认 `min-height: auto` 可能让内容形成自动最小尺寸,导致该 item 不继续压缩,表现为溢出、其它兄弟节点被压缩,或 H5 预览和 Lynx 结果不一致。
63
+
64
+ 需要 Web 预览页对齐 Lynx 压缩行为时,在 Web 侧显式取消自动最小尺寸:
65
+
66
+ ```css
67
+ /* row 方向:允许文本项继续缩小 */
68
+ .text-flex-item {
69
+ min-width: 0;
70
+ overflow: hidden;
71
+ text-overflow: ellipsis;
72
+ white-space: nowrap;
73
+ }
74
+
75
+ /* column 方向:允许纵向子项继续缩小 */
76
+ .column-flex-item {
77
+ min-height: 0;
78
+ }
79
+ ```
80
+
81
+ 需要 Lynx 更接近 Web 的“内容不被压缩”效果时,在 Lynx 侧显式保护该项目:
82
+
83
+ ```css
84
+ .content-item {
85
+ flex-shrink: 0;
86
+ /* 或按主轴方向设置明确下限 */
87
+ min-width: 120px;
88
+ min-height: 120px;
89
+ }
90
+ ```
91
+
92
+ ### 3. 默认布局行为差异(关键)
93
+
94
+ **Web 默认是 block/flow layout,Lynx 默认是 linear layout**:
95
+
96
+ ```css
97
+ /* Web: 不设置 display 时,默认是 block flow */
98
+ div {
99
+ /* 默认 display: block */
100
+ }
101
+ /* 子元素默认宽度 100%,垂直排列 */
102
+
103
+ /* Lynx: 不设置 display 时,默认是 linear layout */
104
+ view {
105
+ /* 默认 display: linear; linear-direction: column */
106
+ }
107
+ /* 子元素不会自动填满父元素宽度 */
108
+ ```
109
+
110
+ **对子元素尺寸的影响**:
111
+
112
+ 在 Web 的 block layout 中,块级子元素默认 `width: 100%`(自动填满父元素宽度)。在 Lynx 的 linear layout 中,子元素默认尺寸由内容决定,**不会自动填满父元素**。
113
+
114
+ ```css
115
+ /* Web: 子元素自动填满父元素 */
116
+ .parent {
117
+ width: 200px;
118
+ }
119
+ .child {
120
+ /* 默认 width: 100%,实际 200px */
121
+ }
122
+
123
+ /* Lynx: 子元素不会自动填满 */
124
+ .parent {
125
+ width: 200px;
126
+ display: linear;
127
+ }
128
+ .child {
129
+ /* 默认宽度由内容决定,可能远小于 200px */
130
+ }
131
+
132
+ /* Lynx 修复方案 1:显式设置 width */
133
+ .child {
134
+ width: 100%;
135
+ }
136
+
137
+ /* Lynx 修复方案 2:使用 linear-layout-gravity */
138
+ .child {
139
+ linear-layout-gravity: stretch;
140
+ }
141
+
142
+ /* Lynx 修复方案 3:父元素设置 linear-cross-gravity */
143
+ .parent {
144
+ linear-cross-gravity: stretch;
145
+ }
146
+ ```
147
+
148
+ **嵌套元素尺寸问题**:
149
+
150
+ 在 Web 中,嵌套的 block 元素会逐层填满父元素。在 Lynx linear layout 中,嵌套的 view 如果没有显式宽高,可能尺寸为 0(尤其是空 view)。
151
+
152
+ ```css
153
+ /* Web: 嵌套 div 自动填满 */
154
+ .grandparent {
155
+ width: 100px;
156
+ height: 100px;
157
+ }
158
+ .parent {
159
+ /* 自动 100x100 */
160
+ }
161
+ .child {
162
+ /* 自动 100x100 */
163
+ }
164
+
165
+ /* Lynx: 需要每层都显式设置 */
166
+ .grandparent {
167
+ width: 100px;
168
+ height: 100px;
169
+ display: linear;
170
+ }
171
+ .parent {
172
+ width: 100%;
173
+ height: 100%;
174
+ }
175
+ .child {
176
+ width: 100%;
177
+ height: 100%;
178
+ }
179
+ ```
180
+
181
+ ### 4. 盒模型
182
+
183
+ **box-sizing 默认**:
184
+
185
+ ```css
186
+ /* Web 默认 */
187
+ box-sizing: content-box;
188
+
189
+ /* Lynx 默认 */
190
+ box-sizing: border-box;
191
+ ```
192
+
193
+ > **注意**: Lynx 默认使用 `border-box`,即 `width` / `height` 已包含 `padding` 和 `border`。这与 Web 浏览器默认的 `content-box`(`width` / `height` 仅指内容区域)有本质区别。
194
+ >
195
+ > 若从 Web 迁移且需保持原有盒模型行为,可全局重置:
196
+ >
197
+ > ```css
198
+ > * {
199
+ > box-sizing: content-box;
200
+ > }
201
+ > ```
202
+
203
+ 显式设置 `box-sizing: border-box` 或 `box-sizing: content-box` 可以控制盒模型计算,但它不能消除其它 Web 布局依赖带来的差异。迁移依赖 `float`、浏览器默认 `<body>` margin/line-height、绝对定位包含块或 min/max 尺寸夹取的页面时,需要同时重写这些布局条件;否则即使盒模型计算正确,Lynx 与 Web 仍可能出现像素级偏移。
204
+
205
+ **Margin collapsing 不支持**:
206
+
207
+ Lynx 中相邻元素的垂直 margin **不会合并**,而是直接相加。这会导致从 Web 迁移过来的页面出现意料之外的间距。
208
+
209
+ ```css
210
+ /* Web: 上下 margin 会合并为 20px */
211
+ .item1 {
212
+ margin-bottom: 20px;
213
+ }
214
+ .item2 {
215
+ margin-top: 20px;
216
+ }
217
+
218
+ /* Lynx: margin 不合并,间距为 40px */
219
+ ```
220
+
221
+ **通用解决方案**:
222
+
223
+ | 场景 | Web 行为 | Lynx 行为 | 修复策略 |
224
+ |------|----------|-----------|----------|
225
+ | 相邻兄弟元素 | `margin-bottom` 和 `margin-top` 合并为较大值 | 两个 margin **相加** | 只给一个元素设置 margin,或改用 gap/padding |
226
+ | 父元素 + 第一个子元素 | 父 `margin-top` 和子 `margin-top` 合并 | 两个 margin **相加** | 移除父元素 margin,由子元素独立控制 |
227
+ | 父元素 + 最后一个子元素 | 父 `margin-bottom` 和子 `margin-bottom` 合并 | 两个 margin **相加** | 移除父元素 margin,由子元素独立控制 |
228
+ | 空元素相邻 | 空元素的 margin 会与其他 margin 合并 | 空元素的 margin **正常参与相加** | 移除空元素的 margin 或添加 `min-height: 1px` |
229
+
230
+ **方案 1:只给其中一个元素设置 margin(适用于兄弟元素)**
231
+ ```css
232
+ .item1 { margin-bottom: 20px; }
233
+ .item2 { margin-top: 0; }
234
+ ```
235
+
236
+ **方案 2:使用 padding 替代其中一个 margin**
237
+ ```css
238
+ .item1 { margin-bottom: 0; padding-bottom: 20px; }
239
+ .item2 { margin-top: 0; }
240
+ ```
241
+
242
+ **方案 3:使用 gap(如果父元素是 flex 或 grid 布局)**
243
+ ```css
244
+ .parent {
245
+ display: flex;
246
+ flex-direction: column;
247
+ gap: 20px;
248
+ }
249
+ .item1, .item2 { margin: 0; }
250
+ ```
251
+
252
+ **方案 4(推荐):移除父容器 margin,由子元素独立控制(适用于容器+子元素场景)**
253
+
254
+ 当需要模拟 Web 中 "容器有 8px margin-top,子元素有 1em margin-top,最终间距为 1em" 的 collapsed 效果时:
255
+ ```css
256
+ /* Web 原始代码 */
257
+ .container {
258
+ margin-top: 8px;
259
+ }
260
+ .child {
261
+ margin-top: 1em; /* 16px,与容器的 8px collapse 后仍为 16px */
262
+ }
263
+
264
+ /* Lynx 等效代码 */
265
+ .container {
266
+ margin-top: 0; /* 移除容器顶部 margin */
267
+ }
268
+ .child {
269
+ margin-top: 1em; /* 16px,直接得到目标间距 */
270
+ }
271
+ ```
272
+
273
+ **常见场景**:
274
+ - 连续的块级元素使用 margin 控制间距(段落、标题、列表项)
275
+ - 容器与第一个/最后一个子元素之间的间距(body 与内容、卡片与内部元素)
276
+ - 嵌套组件中外层容器和内层容器之间的 margin 叠加
277
+ - 多层嵌套结构中 margin 的累积效应
278
+ - 空元素(如仅含 border 的 div)的 margin 处理
279
+
280
+ **负 margin(negative margin)在 Linear Layout 中的行为**:
281
+
282
+ 在 Lynx 的 `display: linear; linear-direction: column` 默认布局中,负 margin 可以正常工作:
283
+
284
+ | 方向 | 场景 | 行为 |
285
+ |------|------|------|
286
+ | **Cross-axis**(`margin-left` / `margin-right`) | 子元素负 margin 拉回到父元素边界 | ✅ **正常工作** |
287
+ | **Main-axis**(`margin-top` / `margin-bottom`) | 兄弟元素间负 margin 重叠 | ✅ **正常工作** |
288
+
289
+ ```css
290
+ /* 子元素负 margin 回拉 —— WORKS ✓ */
291
+ .parent {
292
+ border-left: 2px solid red;
293
+ padding-left: 96px;
294
+ }
295
+ .child {
296
+ border-left: 2px solid black;
297
+ margin-left: -98px; /* 子元素向左回拉,覆盖父元素的红色边框 */
298
+ }
299
+
300
+ /* 兄弟元素负 margin 重叠 —— WORKS ✓ */
301
+ .sibling1 {
302
+ border-top: 2px solid red;
303
+ padding-bottom: 96px;
304
+ }
305
+ .sibling2 {
306
+ border-bottom: 2px solid black;
307
+ margin-top: -98px; /* 向上重叠,与 sibling1 的红色边框贴合 */
308
+ }
309
+ ```
310
+
311
+ **适配建议**:
312
+ - 负 margin(包括 cross-axis 和 main-axis)在 Lynx linear layout 中均可正常工作,无需特殊 workaround。
313
+ - 若遇到细微 diff,优先检查 margin collapsing 补偿是否正确,而非负 margin 本身。
314
+
315
+ **Negative padding values are invalid in CSS but accepted in Lynx**:
316
+
317
+ In CSS, negative padding values (e.g. `padding-bottom: -1px`) are **invalid values**. When no other valid declaration exists, the property falls back to its initial value (`0`). Lynx's padding length parser (`LengthHandler::Process`) does **not** perform non-negative validation, so negative values are parsed as valid lengths and continue into layout. The layout path only calls `ClampIndefiniteToZero()`, which handles indefinite values, not negative ones. As a result, the negative padding is applied directly, causing layout differences.
318
+
319
+ ```css
320
+ /* Web: -1px is an invalid value, falls back to 0 */
321
+ padding-bottom: -1px; /* actual effect: 0 */
322
+
323
+ /* Lynx: -1px is parsed as a valid length and applied directly */
324
+ padding-bottom: -1px; /* actual effect: -1px */
325
+ ```
326
+
327
+ **Workaround**: Replace negative padding with `0` during WPT adaptation or code review:
328
+
329
+ ```css
330
+ /* Replace invalid negative padding with 0 */
331
+ .element {
332
+ padding: 0; /* instead of padding: -1px */
333
+ }
334
+ ```
335
+
336
+ **`<body>` margin + 第一个子元素 margin-top 的特殊处理**:
337
+
338
+ 在 Web 中,`<body>` 的 `margin: 8px` 和第一个 `<p>` 的 `margin-top: 1em` 会 margin collapse,最终顶部间距为 `max(8px, 1em)`(约 16px)。
339
+
340
+ 在 Lynx 中,`.body { margin: 8px; }` 和第一个子元素的 margin-top **不会 collapse**,而是相加:
341
+
342
+ ```css
343
+ /* Lynx 适配策略 */
344
+ .body {
345
+ display: linear;
346
+ linear-direction: column;
347
+ margin: 8px;
348
+ }
349
+
350
+ /* 如果第一个子元素的 margin-top 为 0,总顶部间距只有 8px */
351
+ /* 需要给第一个子元素添加 margin-top: 8px 来补偿 */
352
+ .first-child {
353
+ margin-top: 8px;
354
+ }
355
+ /* 总顶部间距 = 8px (.body) + 8px (first-child) = 16px ✓ */
356
+ ```
357
+
358
+ **WPT 适配建议**:
359
+
360
+ - 将 `.__ua-p`(模拟 `<p>`)等段落类元素的 `margin-top: 1em; margin-bottom: 1em;` 改为 `margin-top: 0.5em; margin-bottom: 0.5em;`
361
+ - 这样相邻段落相加后为 `0.5em + 0.5em = 1em`,与 Web 的 margin collapse 效果一致
362
+ - 如果第一个子元素的 margin-top 为 0,需要额外添加 `margin-top: 8px` 来模拟 `<body>` + `<p>` 的 collapse 效果
363
+ - 若根容器和第一个子元素都有 `8px` 顶部 margin,Web 中 margin collapse 后顶部间距是 `max(8px, 8px) = 8px`;Lynx 中两者会相加为 `16px`。迁移时需要显式分配根容器和第一个子元素的 margin,使相加后的值等于 Web 中 collapse 后的目标间距。
364
+
365
+ ### 5. 长度值
366
+
367
+ **内在尺寸单位**:
368
+
369
+ - ✅ `max-content` - 完全支持
370
+ - ✅ `fit-content` - 完全支持
371
+ - ❌ `min-content` - 不支持
372
+
373
+ **不支持的单位**:
374
+
375
+ - ❌ `ch`, `ex`
376
+ - ❌ 物理单位:`cm`, `mm`, `in`, `pt`, `pc`
377
+
378
+ ### calc() 函数支持
379
+
380
+ **✅ 支持的属性(34 个长度属性)**:
381
+
382
+ - 尺寸:`width`, `height`, `max-width`, `min-width`, `max-height`, `min-height`
383
+ - 定位:`top`, `left`, `right`, `bottom`
384
+ - 内边距:`padding-left`, `padding-right`, `padding-top`, `padding-bottom`
385
+ - 外边距:`margin-left`, `margin-right`, `margin-top`, `margin-bottom`
386
+ - Flex:`flex-basis`
387
+ - Flex/Grid 间距:`grid-column-gap`, `grid-row-gap`, `column-gap`, `row-gap`
388
+ - 文本:`font-size`, `text-indent`
389
+ - 变换:`perspective`
390
+ - RTL 支持:`margin-inline-start/end`, `padding-inline-start/end`, `inset-inline-start/end`
391
+
392
+ **❌ 不支持的属性**:
393
+
394
+ - 颜色属性(`color`, `background-color` 等)
395
+ - 枚举属性(`flex-direction`, `justify-content`, `align-items` 等)
396
+ - 边框圆角(`border-radius` 等)
397
+ - 变换属性(`transform` 等)
398
+ - 数值属性(`opacity`, `z-index` 等)
399
+
400
+ ```css
401
+ /* ✅ 有效 */
402
+ width: calc(100% - 20px);
403
+ margin: calc(var(--spacing) * 2);
404
+
405
+ /* ❌ 无效 */
406
+ flex-direction: calc(row); /* 枚举属性 */
407
+ color: calc(#ff0000); /* 颜色属性 */
408
+ ```
409
+
410
+ **推荐的单位**:
411
+
412
+ - ✅ `px` - 像素
413
+ - ✅ `%` - 百分比
414
+ - ✅ `vw`, `vh` - 视口单位(**推荐**,配合 rem 使用)
415
+ - ✅ `rem` - 根元素字体倍数(**推荐**,响应式适配首选)
416
+ - ⚠️ `rpx` - 响应式像素(Lynx 特有,功能完整但缺乏 Web 兼容性)
417
+
418
+ ### 6. 定位
419
+
420
+ **不支持 static**:
421
+
422
+ ```css
423
+ /* Web */
424
+ position: static; /* 默认 */
425
+
426
+ /* Lynx - 使用 relative 代替 */
427
+ position: relative; /* 默认 */
428
+ ```
429
+
430
+ ### 7. Float 不支持
431
+
432
+ ```css
433
+ /* ❌ 不支持 */
434
+ float: left;
435
+ float: right;
436
+ clear: both;
437
+
438
+ /* ✅ 使用 Flex 代替 */
439
+ display: flex;
440
+ flex-direction: row;
441
+ ```
442
+
443
+ ### 8. 文本处理
444
+
445
+ **Text 组件隔离**:
446
+
447
+ ```css
448
+ /* Web: 可以直接在 div 中放文字 */
449
+ <div>Hello World</div>
450
+
451
+ /* Lynx: 必须使用 Text 组件 */
452
+ <view>
453
+ <text>Hello World</text>
454
+ </view>
455
+ ```
456
+
457
+ **文本不换行**:
458
+
459
+ ```css
460
+ /* Web: 默认会换行 */
461
+ /* Lynx Text 组件: 默认不换行,需要设置 */
462
+ text {
463
+ white-space: normal; /* 允许换行 */
464
+ }
465
+ ```
466
+
467
+ ### 9. 伪元素
468
+
469
+ **::before, ::after 不支持**:
470
+
471
+ ```css
472
+ /* ❌ 不支持 */
473
+ .element::before {
474
+ content: 'Prefix';
475
+ }
476
+
477
+ .element::after {
478
+ content: '';
479
+ background-color: red;
480
+ }
481
+ ```
482
+
483
+ > **注意**: `::before` 和 `::after` 在 Lynx 中完全不支持。虽然 CSS 解析器可以识别这些伪元素,但选择器匹配器和渲染引擎并未实现它们,因此使用它们不会有任何效果。
484
+
485
+ ### 10. Z-index
486
+
487
+ **需要配合 position**:
488
+
489
+ ```css
490
+ /* Web: 无 position 也能用 z-index */
491
+ z-index: 10;
492
+
493
+ /* Lynx: 必须设置 position */
494
+ position: relative; /* 或 absolute/fixed/sticky */
495
+ z-index: 10;
496
+ ```
497
+
498
+ **Stacking Context and Compositing Layer**:
499
+
500
+ In Lynx, `z-index` creates a new **stacking context** and may trigger **compositing layer** promotion. This causes child elements in scrollable containers (e.g., `scroll-view`, `fold-view`) to not follow the scroll movement.
501
+
502
+ ```css
503
+ /* ❌ Problem: Child elements with z-index may not follow scroll */
504
+ fold-view-header {
505
+ /* Child elements inside header have z-index set */
506
+ }
507
+ .header-item {
508
+ position: relative;
509
+ z-index: 10; /* This element is promoted to compositing layer, may not follow header scroll */
510
+ }
511
+
512
+ /* ✅ Solution: Add z-index: 0 to parent container to establish the same stacking context */
513
+ fold-view-header {
514
+ position: relative;
515
+ z-index: 0; /* Key: Make header itself a compositing layer */
516
+ }
517
+ .header-item {
518
+ position: relative;
519
+ z-index: 10; /* Now correctly follows fold-view-header scroll */
520
+ }
521
+ ```
522
+
523
+ **How It Works**:
524
+
525
+ - When a child element sets `z-index`, it is promoted to an independent compositing layer
526
+ - The coordinate transformation of this layer may not follow the parent container's scroll offset
527
+ - Adding `z-index: 0` (or any z-index) to the parent container makes it a stacking context, so child elements stay within the same layer and follow the scroll
528
+
529
+ **Common Scenarios**:
530
+
531
+ - Elements inside `fold-view-header` with `z-index` don't follow scroll
532
+ - Fixed-position elements inside `scroll-view` and their stacking with scrollable content
533
+ - Overlay popups and their stacking with scrollable content
534
+
535
+ ### 11. 选择器限制
536
+
537
+ **不支持**:
538
+
539
+ - ❌ `:is()`, `:where()`, `:has()` - 较新的选择器
540
+ - ❌ 复杂属性选择器: `[attr^="val"]`, `[attr$="val"]`(部分支持)
541
+ - ❌ 通用兄弟选择器在复杂场景可能有限制
542
+
543
+ ### 12. 自定义字体
544
+
545
+ **字体格式**:
546
+
547
+ ```css
548
+ /* Web: 支持多种格式 */
549
+ @font-face {
550
+ src: url('font.woff2') format('woff2');
551
+ }
552
+
553
+ /* Lynx: 使用系统字体或 base64 内联 */
554
+ font-family: 'PingFang SC', 'Helvetica Neue', Arial, sans-serif;
555
+ ```
556
+
557
+ ## 快速迁移检查表
558
+
559
+ 从 Web 迁移到 Lynx 时,检查以下项目:
560
+
561
+ - [ ] 移除所有 `display: block` / `display: inline` / `display: inline-block`
562
+ - [ ] 将所有文本包裹在 `<text>` 组件中
563
+ - [ ] 移除所有 `float` 和 `clear`,改用 Flex
564
+ - [ ] 检查 `position: static`,改用 `relative`
565
+ - [ ] 替换 `min-content` / `max-content` 为固定值或百分比
566
+ - [ ] 为所有 `z-index` 添加 `position`
567
+ - [ ] Check if z-index in scrollable containers (scroll-view/fold-view) causes scroll not to follow
568
+ - [ ] If so, add `z-index: 0` to parent container to establish the same stacking context
569
+ - [ ] 移除所有 `::before` / `::after` 使用(完全不支持)
570
+ - [ ] 检查 margin collapsing 问题
571
+ - [ ] 测试 `white-space` 设置
572
+
573
+ ## 常见陷阱
574
+
575
+ ### 陷阱 1:忘记使用 Text 组件
576
+
577
+ ```jsx
578
+ // ❌ 错误
579
+ <view>Text content</view>
580
+
581
+ // ✅ 正确
582
+ <view>
583
+ <text>Text content</text>
584
+ </view>
585
+ ```
586
+
587
+ ### 陷阱 2:依赖 margin collapsing
588
+
589
+ ```css
590
+ /* Web: 会合并为 20px */
591
+ .top {
592
+ margin-bottom: 20px;
593
+ }
594
+ .bottom {
595
+ margin-top: 20px;
596
+ }
597
+
598
+ /* Lynx: 不会合并,为 40px,需要调整 */
599
+ .top {
600
+ margin-bottom: 10px;
601
+ }
602
+ .bottom {
603
+ margin-top: 10px;
604
+ }
605
+ /* 或者 */
606
+ .top {
607
+ margin-bottom: 20px;
608
+ }
609
+ .bottom {
610
+ margin-top: 0;
611
+ }
612
+ ```
613
+
614
+ ### 陷阱 3:使用不支持的单位
615
+
616
+ ```css
617
+ /* ❌ 不支持 */
618
+ width: min-content;
619
+ width: 100vw; /* vh 支持,但 vmin/vmax 可能不支持 */
620
+
621
+ /* ✅ 使用替代方案 */
622
+ width: auto;
623
+ width: 100%;
624
+ ```
625
+
626
+ ### 陷阱 4:忘记设置 white-space
627
+
628
+ ```css
629
+ /* 默认不换行 */
630
+ text {
631
+ white-space: nowrap;
632
+ }
633
+
634
+ /* 需要显式设置才能换行 */
635
+ text {
636
+ white-space: normal;
637
+ }
638
+ ```
639
+
640
+ ### 陷阱 5:忘记同步 body 样式到 page 元素
641
+
642
+ Web 的 `body` 元素通常带有浏览器默认的 `margin` 和 `padding`,而 Lynx 的根元素 `page` **默认没有这些样式**。
643
+
644
+ ```css
645
+ /* Web: body 有默认 margin/padding */
646
+ body {
647
+ margin: 8px;
648
+ padding: 0 8px;
649
+ }
650
+
651
+ /* Lynx: page 默认无 margin/padding,需手动同步 */
652
+ page {
653
+ margin: 8px;
654
+ padding: 0 8px;
655
+ }
656
+ ```
657
+
658
+ 从 Web 迁移时,若需保持完全一致的布局,记得将 `body` 上的样式同步到 `page`。
659
+
660
+ ### 陷阱 6:把 Web 的 html/body 背景直接映射成普通容器
661
+
662
+ Web 中 `html` 是文档根节点,`body` 是页面内容容器,两者在背景绘制上有专门的 canvas 传播规则。Lynx 中没有这两个同名节点;`page` 是页面根节点,也是全页背景承载面。
663
+
664
+ ```css
665
+ /* Web: html 提供页面底色,body 提供内容区域背景 */
666
+ html {
667
+ background-color: #f5f5f5;
668
+ }
669
+
670
+ body {
671
+ margin: 8px;
672
+ background-color: white;
673
+ }
674
+ ```
675
+
676
+ 迁移到 Lynx 时,先判断 Web 背景的职责:
677
+
678
+ - 需要全页背景时,设置 `page`。
679
+ - 需要内容容器背景时,设置根 `view`。
680
+ - Web 中同时使用 `html` 和 `body` 两层背景时,通常把 `html` 背景映射到 `page`,把 `body` 背景映射到根 `view`。
681
+
682
+ ```css
683
+ /* Lynx */
684
+ page {
685
+ background-color: #f5f5f5;
686
+ }
687
+
688
+ .root {
689
+ margin: 8px;
690
+ background-color: white;
691
+ }
692
+ ```
693
+
694
+ 如果 Web 只依赖 `body` 背景铺满视口,Lynx 中直接设置 `page` 更接近该全页视觉:
695
+
696
+ ```css
697
+ /* Web */
698
+ body {
699
+ background-color: green;
700
+ }
701
+
702
+ /* Lynx */
703
+ page {
704
+ background-color: green;
705
+ }
706
+ ```
707
+
708
+ 不要把一个名为 `.body` 的普通 `view` 当成 Web `body` 的等价物。普通 `view` 的背景只覆盖它自己的布局尺寸;`page` 才是 Lynx 的根节点和全页背景面。
709
+
710
+ ### 陷阱 7:迁移包含 background-attachment 的简写
711
+
712
+ Web 的 `background` 简写可能包含 `fixed` / `scroll` 等 `background-attachment` 槽位。当前支持属性列表中没有 `background-attachment`,迁移时应明确拆出 Lynx 支持的背景属性,并单独确认 attachment 语义是否真的需要保留:
713
+
714
+ ```css
715
+ /* Web */
716
+ .box {
717
+ background: url('bg.png') 0 0 / cover no-repeat fixed #fff;
718
+ }
719
+ ```
720
+
721
+ ```css
722
+ /* Lynx */
723
+ .box {
724
+ background-image: url('bg.png');
725
+ background-position: 0 0;
726
+ background-size: cover;
727
+ background-repeat: no-repeat;
728
+ background-color: #fff;
729
+ }
730
+ ```
731
+
732
+ ```css
733
+ /* 如果只需要纯色背景,直接使用 background-color */
734
+ .box {
735
+ background-color: green;
736
+ }
737
+ ```