You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

CSS响应式下拉菜单优化:实现下拉时下方元素动态位移

解决下拉菜单展开时下方元素自动下移的问题

核心问题分析

你的下拉菜单使用了position: absolute,导致菜单脱离文档流,展开时不会占据空间,因此下方元素无法自动下移。同时.items-below-dropdown的固定margin-top设置,让元素无论菜单状态如何都保持下移状态。

修改方案

通过调整菜单定位逻辑、使用CSS类控制显示状态,让菜单展开时占据文档流空间,下方元素自然随菜单状态变化而上移/下移,无需手动固定margin值。

修改后的完整代码

HTML

(无需修改,保持原有结构即可)

<div class="button-stack">
  <li class="dropdown">
    <button type="submit" class="card" onclick="toggleDropdown('introduction-dropdown')">
      <div class="card-content">
        <h2 class="card-title">Introduccion a Haskell</h2>
      </div>
      <div class="card-divider"></div>
      <span class="letter">1</span>
    </button>
      <ul class="dropdown-content" id="introduction-dropdown">
        <li>
          <form action="/home" method="post">
            <input type="hidden" name="lesson_id" value="1">
            <button type="submit" class="card lesson-card">
              <div class="card-content">
                <h2 class="card-title">Titulo de leccion</h2>
              </div>
              <div class="card-divider"></div>
              <span class="number">1.1</span>
            </button>
          </form>
        </li>
        <li>
          <form action="/home" method="post">
            <input type="hidden" name="lesson_id" value="1">
            <button type="submit" class="card lesson-card">
              <div class="card-content">
                <h2 class="card-title">Titulo de leccion</h2>
              </div>
              <div class="card-divider"></div>
              <span class="number">1.2</span>
            </button>
          </form>
        </li>
        <li>
          <form action="/home" method="post">
            <input type="hidden" name="lesson_id" value="1">
            <button type="submit" class="card lesson-card">
              <div class="card-content">
                <h2 class="card-title">Titulo de leccion</h2>
              </div>
              <div class="card-divider"></div>
              <span class="number">1.3</span>
            </button>
          </form>
        </li>
        <li>
          <form action="/home" method="post">
            <input type="hidden" name="test_id" value="1">
            <button type="submit" class="card test-card">
              <div class="card-content">
                <h2 class="card-title">Test</h2>
                <h3 class="card-subtitle">Temas del test</h3>
              </div>
              <div class="card-divider"></div>
              <span class="letter">1.A</span>
            </button>
          </form>
        </li>
      </ul>  
  </li>
  <div class="items-below-dropdown">
    <li>
      <button type="submit" class="card">
        <div class="card-content">
          <h2 class="card-title">Funciones</h2>
        </div>
        <div class="card-divider"></div>
        <span class="letter">2</span>
      </button>
    </li>
    <li>
      <button type="submit" class="card">
        <div class="card-content">
          <h2 class="card-title">Monadas</h2>
        </div>
        <div class="card-divider"></div>
        <span class="letter">3</span>
      </button>
    </li>
    <li>
      <button type="submit" class="card">
        <div class="card-content">
          <h2 class="card-title">Functores</h2>
        </div>
        <div class="card-divider"></div>
        <span class="letter">4</span>
      </button>
    </li>
  </div>  
</div>

CSS

@import url('font-sets.css');
@import url('common.css');

/* Styles for the dropdown menu */
* {
    list-style: none;
}

/* 下拉菜单父容器:设置flex布局确保子元素对齐 */
.dropdown {
    position: relative;
    width: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
}

.dropdown-content {
    /* 移除绝对定位,改为相对定位,让菜单留在文档流 */
    position: relative;
    display: none;
    min-width: 600px;
    z-index: 1;
    margin-top: 10px;
}

/* 通过类控制菜单展开状态 */
.dropdown-content.active {
    display: block;
}

.dropdown-content li {
    display: block;
    margin-bottom: 20px;
}

/* 移除固定margin-top,让文档流自然布局 */
.items-below-dropdown {
    position: relative;
    width: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
}

/* Styles for the lesson and test cards */
.button-stack {
    margin-top: 20px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 20px; /* 用gap替代分散的margin-bottom,布局更可控 */
}

.card {
    background-color: var(--primary-color);
    color: var(--text-color);
    position: relative;
    width: 700px;
    height: 113px;
    border-radius: 15px;
    border: none;
    box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1);
    font-size: 24px;
    display: flex;
    justify-content: center;
    align-items: center;
    cursor: pointer;
    transition: transform 0.2s;
}

.card:hover {
    transform: scale(1.15);
}

.card::before {
    content: "";
    position: absolute;
    top: 10%;
    bottom: 10%;
    left: 20%;
    transform: translateX(-50%);
    width: 2px;
    background-color: var(--text-color);
}

.card .number, 
.card .letter {
    position: absolute;
    top: 50%;
    left: 10%;
    transform: translate(-50%, -50%);
    font-size: 48px;
    font-weight: bold;
}

.card-content {
    width: 55%;
    padding: 0 20px;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: flex-start;
}

.card-title {
    font-size: 25px;
    font-weight: bold;
    margin-bottom: 10px;
}

.card-subtitle {
    font-size: 18px;
    color: var(--text-color);
}

.lesson-card {
    width: 600px;
    height: 90px;
    background: var(--primary-color);
    color: var(--text-color);
}

.test-card {
    width: 600px;
    height: 90px;
    background: var(--accent-color);
    color: var(--text-color);
}

JavaScript

function toggleDropdown(id) {
  var dropdown = document.getElementById(id);
  // 切换active类,替代直接修改display属性
  dropdown.classList.toggle('active');
}

document.addEventListener('click', function(event) {
  var dropdown = document.getElementById('introduction-dropdown');
  var trigger = document.querySelector('.dropdown');
  if (!trigger.contains(event.target)) {
    // 点击外部时移除active类关闭菜单
    dropdown.classList.remove('active');
  }
});

关键修改说明

  1. 调整菜单定位:移除.dropdown-content的position: absolute,改为position: relative,让菜单留在文档流中,展开时自动占据空间,下方元素会被自然挤开。
  2. CSS类控制显示:通过active类切换菜单的显示/隐藏,符合CSS与JS分离的原则,也方便后续扩展动画效果。
  3. 移除固定margin:删除.items-below-dropdown的固定margin-top,让文档流自动处理元素间距,菜单关闭时元素自动恢复原位。
  4. 布局优化:给父容器添加flex布局,确保菜单与子元素对齐;用gap替代分散的margin-bottom,让布局更简洁可控。

可选优化:平滑过渡动画

如果需要菜单展开/关闭时有平滑的高度变化,可以修改.dropdown-content的CSS:

.dropdown-content {
    position: relative;
    max-height: 0;
    overflow: hidden;
    min-width: 600px;
    z-index: 1;
    margin-top: 10px;
    transition: max-height 0.3s ease-out;
}

.dropdown-content.active {
    max-height: 800px; /* 设置足够大的值覆盖菜单展开后的高度 */
}

内容的提问来源于stack exchange,提问作者Juani Villanueva

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 05:02:07