点击卡片展开全屏宽度内容的Accordion组件优化方案问询
问题:点击卡片展开全屏宽度内容的简洁实现方案?
我想实现点击指定卡片后,在该卡片下方展开一个**宽度为100%**的内容区域。目前用position: absolute加手动计算布局的方式实现,不仅复杂,适配移动端还得额外计算。有没有更简洁、动态的实现方案?
原实现代码
HTML
<div class="card-container"> <div class="card"> CARD1 <div class="card-content">CARD 1 CONTENT</div> </div> <div class="card"> CARD2 <div class="card-content">CARD 2 CONTENT</div> </div> <div class="card"> CARD3 <div class="card-content">CARD 3 CONTENT</div> </div> <div class="card"> CARD4 <div class="card-content">CARD 4 CONTENT</div> </div> <div class="card">CARD5</div> <div class="card">CARD6</div> <div class="card">CARD7</div> </div>
CSS
* { margin: 0; padding: 0; box-sizing: border-box; } .card-container { /* width: 100%; */ display: flex; flex-wrap: wrap; gap: 20px; } .card { width: 30%; height: 200px; background: gray; position: relative; margin-bottom: 200px; } .card-content { display: none; position: absolute; background: green; bottom: -200px; width: 1200px; height: 200px; } .card.active .card-content { display: block; }
JavaScript
const card = document.querySelectorAll('.card'); const cardContent = document.querySelectorAll('.card-content'); function accordion(e){ if(!this.classList.contains('active')) { closeOthers(); this.classList.add('active'); console.log(this) } else { this.classList.remove('active') } }; function closeOthers() { for (i = 0; i < card.length; i++) { card[i].classList.remove("active"); } }; for(i = 0; i < card.length; i++ ){ card[i].addEventListener('click', accordion); };
简洁动态实现方案
核心思路
把内容区域从卡片内部移出,作为容器的直接子元素,利用Flex布局的自动换行特性让内容区域占满整行;通过JS控制内容区域的位置和显示状态,完全避免手动计算布局。
改进后代码
HTML
<div class="card-container"> <div class="card" data-content="content1">CARD1</div> <div class="card-content" id="content1">CARD 1 CONTENT</div> <div class="card" data-content="content2">CARD2</div> <div class="card-content" id="content2">CARD 2 CONTENT</div> <div class="card" data-content="content3">CARD3</div> <div class="card-content" id="content3">CARD 3 CONTENT</div> <div class="card" data-content="content4">CARD4</div> <div class="card-content" id="content4">CARD 4 CONTENT</div> <div class="card">CARD5</div> <div class="card">CARD6</div> <div class="card">CARD7</div> </div>
CSS
* { margin: 0; padding: 0; box-sizing: border-box; } .card-container { display: flex; flex-wrap: wrap; gap: 20px; padding: 20px; } .card { width: 30%; min-height: 200px; background: gray; display: flex; align-items: center; justify-content: center; cursor: pointer; transition: background 0.2s; } .card:hover { background: #888; } .card-content { width: 100%; min-height: 200px; background: green; display: flex; align-items: center; justify-content: center; opacity: 0; height: 0; overflow: hidden; transition: all 0.3s ease; } .card-content.active { opacity: 1; height: 200px; margin-top: 20px; }
JavaScript
const cards = document.querySelectorAll('.card'); const cardContents = document.querySelectorAll('.card-content'); cards.forEach(card => { card.addEventListener('click', function() { const targetId = this.dataset.content; if (!targetId) return; // 关闭所有已激活的内容 cardContents.forEach(content => content.classList.remove('active')); const targetContent = document.getElementById(targetId); // 切换当前内容状态 if (targetContent.classList.contains('active')) { targetContent.classList.remove('active'); } else { // 将内容移动到当前卡片后方,确保在对应位置展开 this.after(targetContent); targetContent.classList.add('active'); } }); });
方案优势
- 无需手动计算:内容区域设
width:100%自动适配容器宽度,移动端无需额外调整 - 动态布局:利用Flex自动换行特性,内容始终出现在点击卡片的正下方
- 平滑过渡:通过CSS transition实现展开/收起的动画效果,提升交互体验
- 易维护:用
data-*属性关联卡片和内容,结构清晰,新增卡片只需对应添加内容块即可
内容的提问来源于stack exchange,提问作者Meto twi8
相关产品推荐
相关产品推荐

