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

flex-grow导致可调整窗口向下滑动时底部容器无法完全展开求助

CodePen风格侧边栏底部容器无法向下展开的修复方案

问题描述

我正在设计一个类似CodePen侧边栏的布局,已复刻大部分交互行为。向上拖动分割线调整窗口时一切正常,但向下拖动时,底部的编辑器容器无法像示例那样完全展开,求问题定位与修复方法。

问题根源

  1. 拖动时的固定高度限制:原JS中给分割线的下一个容器设置了固定height,把容器高度锁死,无法自动填充剩余空间。
  2. CSS初始高度硬编码:所有编辑器容器默认设置height: calc(100% / 3),底部容器无法利用flex布局自动扩展。
  3. 高度计算语法错误:calc(max(${h}%, ${labelHeight}px) 缺少闭合括号,导致样式失效。
  4. 分割线高度未纳入计算:拖动时计算高度未考虑分割线的实际高度,可能导致整体布局溢出。

修正后的代码

JavaScript

function handleEditorWindowResize () {
    const parent = document.querySelector("aside")
    const editorWindows = document.querySelectorAll("aside > div")
    const labelHeight = document.querySelector(".lang-label").getBoundingClientRect().height - 4
    const dividerHeight = 4; // 分割线总高度(2px上下border)

    const handleResize = (ele)=> {
        let startY = 0, height = 0;
        
        const disableInteraction = (ele, state)=> {
            if(state) {
                ele.style.userSelect = 'none';
                ele.style.pointerEvents = 'none';
            } else {
                ele.style.removeProperty('user-select');
                ele.style.removeProperty('pointer-events');
            }
        }

        const handleMouseDown = (e)=> {
            startY = e.clientY - 2; // 抵消分割线的border宽度
            height = ele.previousElementSibling.getBoundingClientRect().height;

            editorWindows.forEach((ele) => {
                disableInteraction(ele, true)
            });

            window.addEventListener("mousemove", handleMouseMove);
            window.addEventListener("mouseup", handleMouseUp);

            ele.style.borderWidth = `5px`;
        }
        
        const handleMouseMove = (e)=> {
            const dy = e.clientY - startY;
            // 计算可用高度(父容器高度减去所有分割线的总高度)
            const availableHeight = parent.getBoundingClientRect().height - (dividerHeight * (editorWindows.length - 1));
            const h = ((height + dy) * 100) / availableHeight;
            // 修复calc括号闭合问题
            ele.previousElementSibling.style.height = `calc(max(${h}%, ${labelHeight}px))`;

            editorWindows.forEach(win=> {
                if(win === ele.nextElementSibling) {
                    // 移除固定高度,用flex:1让容器自动填充剩余空间
                    win.style.flex = '1';
                    win.style.removeProperty("height");
                } else if(win !== ele.previousElementSibling) {
                    // 仅保留前一个容器的固定高度,其余容器恢复默认布局
                    win.style.removeProperty("flex")
                    win.style.removeProperty("height")
                }
            })
        }   
        
        const handleMouseUp = (e)=> {
            editorWindows.forEach(ele => disableInteraction(ele, false));
            window.removeEventListener("mousemove", handleMouseMove);
            window.removeEventListener("mouseup", handleMouseUp);
            ele.style.borderWidth = `2px`;
        }

        ele.addEventListener("mousedown", handleMouseDown);
    }

    document.querySelectorAll("aside > .h-divider").forEach(ele => handleResize(ele));
}

handleEditorWindowResize()

CSS

:root {
  --black: #111;
  --maroon: rgb(117, 14, 33);
  --orange: rgb(227, 101, 29);
  --green: rgb(190, 215, 84);
  --text-color: rgba(255,255,255,1);
  --light-text-color: rgba(255,255,255,0.8);
  --overlay-color: rgba(255,255,255,0.1);

  --gray-100: #111;
  --gray-400: #444;
}

body, html {
  width: 100%;
  height: 100%;
  overflow-x: hidden;
  margin: 0;
  padding: 0;
}

main {
  display: flex;
  width: 100%;
  height: 100%;
}

.divider {
  background-color: var(--gray-400);
  cursor: ew-resize;
  height: 100%;
  width: 8px;
}

aside {
  width: 100%;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

aside > div {
  width: 100%;
  display: flex;
  flex-direction: column;
  flex: 1; /* 用flex分配初始空间,替代固定高度 */
  position: relative;
  min-height: fit-content; /* 保证容器至少能容纳标签栏 */
}  

aside > .h-divider {
  border: 2px solid var(--gray-400);
  cursor: row-resize;
  height: 0; /* 让分割线仅通过border占据高度 */
}

aside textarea {
  overflow-y: auto;
  min-width: 100%;
  max-width: 100%;
  flex:1;
  padding: 0.5rem;
  font-size: 0.8em;
  background: var(--black);
  border: none;
  font-weight: 300;
  border-bottom: 1px solid var(--gray-400);
  background: var(--gray-100);
  color: var(--light-text-color);
}

aside textarea:focus { outline: none; }

.lang-label {
  padding: 0.3rem;
  background-color: var(--maroon);
  font-weight: 700;
  display: flex;
  align-items: center; 
  gap: 0.3rem;
  position: relative;
}

HTML(无修改)

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
  
  <!-- main layout -->

  <main>
    <!-- code -->
    <aside>
      <div>
        <div class="lang-label">
          HTML
        </div>
        <textarea data-lang="html"></textarea>
      </div>
      <span class="h-divider"></span>

      <div>
        <div class="lang-label">
          CSS
        </div>
        <textarea data-lang="css"></textarea>
      </div>
      
      <span class="h-divider"></span>

      <div>
        <div class="lang-label">
          JS
        </div>
        <textarea data-lang="js"></textarea>
      </div>
    </aside>
  </main>
</body>
</html>

内容的提问来源于stack exchange,提问作者zain ul din

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 13:24:57