v0.10.8 首页 H6 宣言条 + H7 四列图标卡 1:1:section 根 padding/列 gap 默认 populated padding(10px 全向)/WidgetNode 双层 el-w-auto 修复 width:100% 强推;EAEL 取证改以原站实际加载的 eael-18.css 为准(icon/content 默认 block、title width:max-content maxW100%);H2~H7 全量 computed 归零(仅 0.8px 页级漂移),清理被取代的 scoped 补丁

This commit is contained in:
bigcode
2026-11-01 09:41:41 +08:00
parent 544cbdc5f6
commit 2cbfc82a08
5 changed files with 109 additions and 43 deletions
+35 -19
View File
@@ -282,18 +282,20 @@ function collectResponsiveCss(elements: ElElement[]): string {
return css;
}
/** # 组件 单个元素节点分发(section/column/container/widget) */
function ElementNode({ el }: { el: ElElement }) {
/** # 组件 单个元素节点分发(section/column/container/widget)
* 参数 gapPad 所属 section 的默认列内边距(Elementor gap 档位,仅 column 消费)
*/
function ElementNode({ el, gapPad }: { el: ElElement; gapPad?: string }) {
const type = s(el.elType);
if (type === "widget") return <WidgetNode el={el} />;
if (type === "section" || type === "container") return <SectionNode el={el} />;
if (type === "column") return <ColumnNode el={el} />;
if (type === "column") return <ColumnNode el={el} gapPad={gapPad} />;
// 未知结构:有子元素则递归,否则忽略
if (el.elements?.length) {
return (
<>
{el.elements.map((c, i) => (
<ElementNode key={c.id || i} el={c} />
<ElementNode key={c.id || i} el={c} gapPad={gapPad} />
))}
</>
);
@@ -303,23 +305,29 @@ function ElementNode({ el }: { el: ElElement }) {
/** # 组件 section / container:背景 + 内部布局
* 取证(原站实测/post CSS):boxed 内容容器 = margin auto + flex wrap 的定宽行;
* 内容宽度 content_width 优先,否则沿用 Elementor kit 默认 1140px;
* 自带 padding 只取 settings.padding(不再叠加通用 px/py)。
* 内容宽度 content_width 优先,否则沿用 Elementor kit 默认 1140px。
* padding 挂在 section 根(原站 computed padding 在 .elementor-section 上,行容器无 padding,
* 根 padding 同时把行往内推:1436 视口 + 1.6px 侧 padding 时行仍为整宽 1360,实测一致)。
* gap 档位决定子列的默认 populated padding(frontend.min.css:no 0 / narrow 5 / default 10 /
* extended 15 / wide 20 / wider 30;settings 缺省 = default)。
*/
const GAP_PAD: Record<string, string> = {
no: "0px", narrow: "5px", default: "10px", extended: "15px", wide: "20px", wider: "30px",
};
function SectionNode({ el }: { el: ElElement }) {
const settings = resolveGlobals(el.settings || {});
const style = sectionBgStyle(settings);
const width = sizeCss(settings.content_width) || sizeCss((settings as Record<string, unknown>).width) || "1140px";
const secPad = paddingCss(settings.padding);
if (secPad) style.padding = secPad;
const inner: CSSProperties = {};
if (s(settings.layout) === "full_width") {
// 通栏 section:内容不设上限、无内边距(如首页 hero 轮播)
// 通栏 section:内容不设上限(如首页 hero 轮播)
inner.maxWidth = "none";
inner.padding = "0";
} else {
inner.maxWidth = width;
const innerPad = paddingCss(settings.padding);
if (innerPad) inner.padding = innerPad;
}
const gapPad = GAP_PAD[s(settings.gap) || "default"] || "10px";
// section 高度模式(Elementor: min-height / full),配合 custom_height;
// 取证(原站 09fe4b7 实测):height 未设置时 custom_height 不生效(min-height 0px),
// 故仅在显式 height 模式下应用
@@ -331,7 +339,7 @@ function SectionNode({ el }: { el: ElElement }) {
<section style={style} data-el={el.id}>
<div className="mx-auto flex flex-wrap" style={inner}>
{(el.elements || []).map((c, i) => (
<ElementNode key={c.id || i} el={c} />
<ElementNode key={c.id || i} el={c} gapPad={gapPad} />
))}
</div>
</section>
@@ -342,8 +350,11 @@ function SectionNode({ el }: { el: ElElement }) {
* 外层参与 flex 布局(按 _inline_size 百分比否则均分),不承载盒样式;
* 内层承载 populated 的盒样式:_margin(margin,移动卡片间距且不影响 flex 宽度,与原站一致)、
* padding、背景、边框、圆角。
* padding:列自带 settings.padding 优先;否则用所属 section 的 gap 默认值
* (frontend.min.css .elementor-column-gap-default > … > .elementor-element-populated{padding:10px},
* 实测 H6 列 59bc2e1 四向 10px、H7 列 66de90a 设置覆盖为 8/16/16/0,两端一致)。
*/
function ColumnNode({ el }: { el: ElElement }) {
function ColumnNode({ el, gapPad }: { el: ElElement; gapPad?: string }) {
const settings = resolveGlobals(el.settings || {});
const outer: CSSProperties = { minWidth: 0, flex: "1 1 0" };
const inline = settings._inline_size;
@@ -359,8 +370,7 @@ function ColumnNode({ el }: { el: ElElement }) {
inner.width = "100%";
inner.margin = mg;
}
const pad = paddingCss(settings.padding);
if (pad) inner.padding = pad;
inner.padding = paddingCss(settings.padding) || gapPad || "10px";
const bg = sectionBgStyle(settings);
Object.assign(inner, { backgroundColor: bg.backgroundColor, backgroundImage: bg.backgroundImage });
const radius = paddingCss(settings.border_radius);
@@ -375,9 +385,9 @@ function ColumnNode({ el }: { el: ElElement }) {
}
return (
<div className="el-col min-w-0" style={outer} data-el={el.id}>
<div className="px-2.5" style={inner}>
<div style={{ display: "flex", flexWrap: "wrap", alignContent: "flex-start", width: "100%", ...inner }}>
{(el.elements || []).map((c, i) => (
<ElementNode key={c.id || i} el={c} />
<ElementNode key={c.id || i} el={c} gapPad={gapPad} />
))}
</div>
</div>
@@ -421,16 +431,22 @@ function WidgetNode({ el }: { el: ElElement }) {
<WidgetNodeInner el={el} />
</WidgetGuard>
);
// 原站 .elementor-widget-wrap > .elementor-element { width:100% }:
// widget 默认满宽(flex wrap 中独占一行),_element_width=auto 时按内容宽(横排)
const widthAuto = s(settings._element_width) === "auto";
const cls = s(settings._css_classes) || undefined;
const baseCls = cls ? (widthAuto ? cls + " el-w-auto" : cls) : widthAuto ? "el-w-auto" : undefined;
const hasContainerStyle = Object.keys(style).length > 0;
if (hasContainerStyle) {
return (
<div data-el={el.id}>
<div className={cls} style={style}>{inner}</div>
// 外层也要带 el-w-auto:列内基础规则按 :not(.el-w-auto) 放行 width:auto 的根,
// 否则 width-auto widget(如图标)被 width:100% 强推成每行一个(H7 回归根因)
<div className={widthAuto ? "el-w-auto" : undefined} data-el={el.id}>
<div className={baseCls} style={{ width: widthAuto ? "auto" : "100%", ...style }}>{inner}</div>
</div>
);
}
return <div className={cls} data-el={el.id}>{inner}</div>;
return <div className={baseCls} style={{ width: widthAuto ? "auto" : "100%" }} data-el={el.id}>{inner}</div>;
}
/** # 组件 单个 widget 渲染错误边界:异常 widget 降级为空,不拖垮整页 */