details聚焦收起或闪退是因原生动画与浏览器焦点滚动策略冲突所致:chrome/firefox用max-height过渡,而input.focus()强制滚动,导致重排后焦点被交还body。

details里放为什么一聚焦就收起或闪退
根本不是代码写错了,是details的原生展开动画和浏览器焦点滚动策略冲突。Chrome/Firefox 展开时用max-height过渡,而input.focus()会强制滚动到可视区,两者打架——结果就是:输入框刚获得焦点,details高度突变触发重排,焦点被浏览器“礼貌地”交还给body。
常见现象包括:
- iOS Safari 点一下没反应,点两下才展开,且光标不出现
- Android Chrome 键盘弹出 300ms 后自动收起
- 桌面端看似正常,但快速点击 summary → input,偶尔失焦
禁用原生动画 + 手动控制展开高度
别碰details[open]的默认过渡,直接用 CSS 覆盖掉它,再自己加可控的max-height动画:
details {
/* 关键:干掉浏览器默认动画 */
animation: none;
}
details[open] > * {
animation: none;
}
details > summary {
list-style: none;
}
details[open] > div {
max-height: 500px;
transition: max-height 0.25s ease-in-out;
}
details:not([open]) > div {
max-height: 0;
overflow: hidden;
transition: max-height 0.25s ease-in-out;
}
注意:<div>必须是<code><summary></summary>的**直接兄弟节点**,不能套在<p></p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill3458" title="html-ppt-to-pdf"><img
src="https://img.php.cn/upload/skill/000/000/081/178956546773641.jpg" alt="html-ppt-to-pdf" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/skill3458" title="html-ppt-to-pdf" class="overflowclass">html-ppt-to-pdf</a>
<p class="overflowclass">将使用 `<section class="slide">` 约定的 HTML 幻灯片转换为高保真、矢量文本 PDF(使用 Playwright + Chromium 原生 PDF 功能)。</p>
</div>
<a rel="nofollow" href="/xiazai/skill3458" title="html-ppt-to-pdf" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div>或<section></section>里,否则 Safari 会忽略open状态。
聚焦后手动滚动对齐,避免错位跳动
即使禁用了动画,input.focus()仍可能因 DOM 高度变化导致页面意外滚动。解决方案不是阻止滚动,而是精准控制:
- 调用
input.focus({ preventScroll: true })(Safari 15.4+、Chrome 86+ 支持) - 若需兼容旧版,在
focus()后立刻补一句input.scrollIntoView({ block: 'nearest' }) - 绝对不要在
<summary></summary>里放<input>——这会破坏按钮语义,Safari 下点击输入框不触发toggle事件
动态插入 input 时的 focus 时机陷阱
如果输入框是 JS 动态塞进details里的(比如模态框打开后渲染),autofocus属性完全无效。此时必须等 DOM 真正挂载完毕再聚焦:
- 原生 JS:监听
details.addEventListener('toggle', () => { if (details.open) setTimeout(() => input.focus(), 0); }) - React:用
useEffect配合ref,且确保依赖项包含details.open - Vue:在
nextTick中聚焦,并加防御判断if (input && document.activeElement !== input) - 移动端必须包裹在用户手势中:比如按钮
onclick回调里调用focus(),否则 iOS Safari 静默拦截
最易被忽略的一点:details展开后,其子元素的tabindex和可聚焦性由 DOM 结构决定——如果中间插了display: none的占位节点,或用了visibility: hidden包裹input,焦点就永远进不去。










