原生 无法满足新闻列表多条独立展开、图标旋转、动态测高及 IE 兼容等需求,因其强制 summary 为首个直接子元素、::marker 跨浏览器支持差、无状态监听机制,且不支持 max-height 动画与动态内容高度计算。

用 <details></details> + <summary></summary> 能快速做出语义正确、无需 JS 的新闻列表折叠效果,但真要控制多条新闻独立展开、带图标旋转、支持动态内容或 IE 兼容,就得用 JS + max-height + classList.toggle()。
为什么不能直接用 <details></details> 做多条新闻折叠
单条新闻用 <details></details> 没问题,但新闻列表通常需要:每条新闻独立开关、点击标题不跳页、展开后箭头旋转、收起时不留空白行。原生 <details></details> 有硬限制:
-
<summary></summary>必须是<details></details>的第一个子元素,不能套在<h3></h3>或<div class="news-header"> 里再加图标 <li>Safari 对 <code>summary::marker支持差,自定义 ▶→▼ 旋转动画基本失效 - 无法监听“哪一条被点了”,JS 拿不到当前新闻的 ID 或状态,做不了联动(比如只允许展开一条)
- 内容高度动态(含图片、异步加载文本),
max-height过渡必须 JS 测高,原生不支持
用 data-id + nextElementSibling 实现逐条控制
新闻列表结构必须保证 DOM 可预测,否则 JS 找不到对应内容块。别用 nextSibling(可能拿到换行符文本节点),也别用 querySelector('.content')(全局查重名类易误匹配)。
推荐 HTML 结构:
立即学习“前端免费学习笔记(深入)”;
<div class="news-list">
<div class="news-item" data-id="1">
<button class="news-toggle" aria-expanded="false">
<span class="toggle-icon">▶</span> 国内首颗量子通信卫星发射成功
</button>
<div class="news-content"><p>……详细报道内容……</p><div class="aritcle_card flexRow">
<div class="artcardd flexRow">
<a class="aritcle_card_img" href="/xiazai/skill12116" title="DeepBI DHTML 页面生成器"><img
src="https://img.php.cn/upload/skill/001/246/273/6adaf20d3191a227.jpg" alt="DeepBI DHTML 页面生成器" ></a>
<div class="aritcle_card_info flexColumn">
<a href="/xiazai/skill12116" title="DeepBI DHTML 页面生成器">DeepBI DHTML 页面生成器</a>
<p>生成可在 deepbi 沙箱 iframe 内运行或作为独立文件运行的交互式 HTML 页面,使用 `window.deepbi` JS SDK 实现数据查询、空间管理、文件浏览及用户操作。当用户提出以下需求时启用该能力:
- 创建 KPI 仪表盘、数据表格、文件浏览器、成员列表、管理页面;
- 明确要求“转成 dhtml”、“转译成 HTML”、“把 XX 页面转成……”、“控制台页面”、“管理后台”、“DeepBI 页面迁移”;
- 提及位于 `apps/console/src/featur</p>
</div>
<a href="/xiazai/skill12116" title="DeepBI DHTML 页面生成器" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span> </a>
</div>
</div></div>
</div>
<div class="news-item" data-id="2">
<button class="news-toggle" aria-expanded="false">
<span class="toggle-icon">▶</span> 全球气候峰会达成新减排协议
</button>
<div class="news-content"><p>……详细报道内容……</p></div>
</div>
</div>
JS 控制逻辑(绑定到父容器,事件委托更轻量):
document.querySelector('.news-list').addEventListener('click', e => {
if (!e.target.matches('.news-toggle')) return;
const item = e.target.closest('.news-item');
const content = item.querySelector('.news-content');
const icon = e.target.querySelector('.toggle-icon');
const isExpanded = e.target.getAttribute('aria-expanded') === 'true';
if (isExpanded) {
content.style.maxHeight = '0';
icon.textContent = '▶';
e.target.setAttribute('aria-expanded', 'false');
} else {
// 动态测高,避免固定值截断或动画过慢
content.style.maxHeight = content.scrollHeight + 'px';
icon.textContent = '▼';
e.target.setAttribute('aria-expanded', 'true');
}
});
CSS 关键部分(必须设 overflow: hidden,否则 max-height 无效):
.news-content {
overflow: hidden;
max-height: 0;
transition: max-height 0.4s cubic-bezier(0.4, 0, 0.2, 1);
}
IE11 兼容时绕开 max-height 动画
IE11 不支持 max-height 过渡,且 scrollHeight 在 display: none 下返回 0。此时只能退化为 toggle display,但需避免覆盖 CSS 中的原始 display 值。
- 不要写
el.style.display = 'block'—— 它会覆盖外部样式表里设置的display: table-row或其他值 - 改用
el.classList.toggle('is-open'),CSS 里定义.news-content.is-open { display: block; } - 图标旋转用
transform: rotate(90deg),IE11 完全支持,比改textContent更稳 - 初始状态全部收起:HTML 里不写
style="display:none",靠 JS 第一次执行时统一设类
最易被忽略的一点:新闻内容若含图片,scrollHeight 在图片未加载完成时取值偏小,导致展开后底部被截。必须监听 img.onload 后重新计算,或用 ResizeObserver(不支持 IE)。


















