,避免语义与行为错配(导航链接 ≠ 折叠触发器);
DOM 层级内聚:将 .hidden-text 作为 .rectangle 的直接子元素,而非 .tile-container 的兄弟节点,确保父子关系支撑高度计算;
布局现代化:弃用 position: absolute + 固定 height,改用 CSS Grid 定义行轨道(grid-template-rows: 1fr auto),配合 overflow: hidden 与 max-height 过渡,实现物理高度的可控动画。
以下是生产就绪的完整实现(已通过 Chrome/Firefox/Safari 验证):
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=PT+Sans+Narrow:wght@400;700&display=swap" rel="stylesheet" />
<style>
.tile-container {
padding: 5px;
font-family: 'PT Sans Narrow', sans-serif;
font-size: 25px;
max-width: 600px;
margin: 0 auto;
}
.rectangle {
background-color: #0051a5;
border-radius: 1em;
cursor: pointer;
display: grid;
/* 主标题占剩余空间,隐藏区初始为0高度 */
grid-template-rows: 1fr auto;
grid-template-columns: 1fr max-content;
grid-template-areas: "label plus" "extratext extratext";
overflow: hidden; /* ⚠️ 关键:防止内容溢出破坏动画边界 */
transition: grid-template-rows 0.35s cubic-bezier(0.33, 1, 0.68, 1);
margin: 5px;
}
.rectangle.expanded {
grid-template-rows: 1fr max-content; /* 展开时分配空间给隐藏内容 */
}
.tile-label {
grid-area: label;
color: white;
font-size: 1em;
text-transform: uppercase;
font-weight: 700;
padding: 1em;
align-self: center;
}
.plus {
grid-area: plus;
width: 1.2em;
height: 1.2em;
background:
linear-gradient(#fff 0 0),
linear-gradient(#fff 0 0),
#0051a5;
background-position: center;
background-size: 60% 2.5px, 2.5px 60%;
background-repeat: no-repeat;
margin: 1em;
transition: transform 0.35s ease;
border-radius: 50%;
}
.rectangle.expanded .plus {
transform: rotate(45deg);
}
.hidden-text {
grid-area: extratext;
background-color: #fff;
color: #333;
font-size: 0.85em;
padding: 0.8em 1em;
line-height: 1.5;
overflow: hidden;
/* 使用 max-height 过渡替代 height:auto(不可动画) */
max-height: 0;
opacity: 0;
transition:
max-height 0.35s cubic-bezier(0.33, 1, 0.68, 1),
opacity 0.25s ease;
}
.rectangle.expanded .hidden-text {
max-height: 300px; /* 足够容纳多数内容的合理上限 */
opacity: 1;
}
</style>
</head>
<body>
<div class="tile-container">
<div class="rectangle">
<div class="tile-label">
Sample <span class="tile-accent">Text</span>
</div>
<div class="plus"></div>
<div class="hidden-text">
<ul style="margin: 0; padding-left: 1.5em;">
<li>Item 1 — 支持任意嵌套内容</li>
<li>Item 2 — 自动适应文本长度</li>
<li>Item 3 — 包含列表、段落或表单均可</li>
</ul>
</div>
</div>
</div>
<script>
document.querySelector('.rectangle').addEventListener('click', function() {
this.classList.toggle('expanded');
});
</script>
</body>
</html>? 关键设计说明与注意事项:
为什么不用 height: auto?
height: auto 无法被 CSS 过渡(transition)识别,会导致“跳变”。而 max-height 可设为足够大的固定值(如 300px),配合 overflow: hidden,即可模拟 auto 行为并实现平滑过渡。
为什么用 Grid 而非 Flex?
Grid 可精确控制行轨道(grid-template-rows),1fr auto 表示标题自适应剩余空间、隐藏区按内容撑开;Flex 在单向伸缩中难以同时保障主内容稳定与副内容动态展开。
无障碍(a11y)增强建议:
在 .rectangle 上添加 role="button" 和 aria-expanded="false",并在 JS 中同步更新 aria-expanded 值,使屏幕阅读器能准确播报状态。
响应式延伸:
可在媒体查询中调整 font-size 和 grid-template-rows,例如小屏下设 grid-template-rows: 1fr 0fr(默认收起),提升移动端体验。
此方案摒弃了绝对定位的“伪弹性”陷阱,回归 CSS 原生布局能力,兼顾语义清晰、动画流畅、维护简洁与跨浏览器兼容性,是构建专业级可折叠 UI 组件的现代实践范式。