使用鼠标动态调整 css 网格布局中的列

Dynamically resize columns in css grid layout with mouse

我正在尝试通过用鼠标拖动列分隔符(或调整占位符)来动态调整 css 网格布局框的大小。

我在nav元素上设置了resize: horizontal;调整大小,当我拖动元素右下角的调整大小小手柄时,它会调整大小,但相邻列的宽度不会自动调整导致重叠。这是一个坏掉的 codepen.

HTML:

<main>
 <nav>#1</nav>
 <header>#2</header>
 <section>#3</section>
</main>

CSS:

main {
    display: grid;
    border: 3px dotted red;
    grid-gap: 3px;
    grid-template-columns: 200px 1fr;
    grid-template-rows: 100px 1fr;
    height: 100%;
}

nav {
    grid-column: 1;
    grid-row: 1;
    grid-row: 1 / span 2;
    resize: horizontal;
    overflow: scroll;
    border: 3px dotted blue;
}

我希望 css 网格引擎能够自动处理这种情况,但显然它不会。

我尝试了 jquery-ui resizable,但它似乎不适用于 css 网格。

我正在研究如何通过将网格属性 grid-template-columns/rows: 设置为动态值来使用 jquery 来做到这一点,但不清楚如何通过调整元素大小来捕获抛出的事件调整手柄。 jquery resize 事件仅在 window 对象上触发,而不在 dom 元素上触发。

有什么方法可以做到这一点而不必处理像 dragstart/dragend 这样的低级鼠标事件?

解决方案是不是使用明确的固定列大小(grid-template-columns: 200px 1fr;)而是使用相对列大小,例如grid-template-columns: 0.2fr 1fr; — 然后网格 CSS 引擎将处理相邻框的大小调整。接下来是在网格框中添加嵌套的 div,将它们的 min-height/width 设置为 100% 并通过 jqueryui resizable 调整它们的大小。

固定jsfiddle.

/* Javscript */

$('.left_inner').resizable();
$('.right_top_inner').resizable();
$('.right_bottom_inner').resizable();
/* CSS */

 .grid {
  display: grid;
  grid-template-columns: 0.2fr 1fr;
  grid-template-rows: 1fr 4fr;
        grid-gap: 3px;
  position: relative;
 }

 .left {
  grid-row: 1 / span 2;
 }

 .right_top {
  grid-column: 2;
  grid-row: 1;
 }

 .right_bottom {
  grid-column: 2;
  grid-row: 2;
 }

 .left_inner {
  background-color: #fedcd2;
  padding: 0;
  width: 100%;
  min-width: 100%;
  height: 100%;
  min-height: 100%;
  text-align: center;
 }

 .right_top_inner {
  background-color: #f9cf00;
  padding: 0;
  width: 100%;
  min-width: 100%;
  height: 100%;
  min-height: 100%;
  text-align: center;
 }

 .right_bottom_inner {
  background-color: #f8eee7;
  padding: 0;
  width: 100%;
  min-width: 100%;
  height: 100%;
  min-height: 100%;
  text-align: center;
 }
<!-- HTML -->

<script src="//code.jquery.com/jquery-2.1.3.min.js"></script>
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/jqueryui/1.10.0/css/smoothness/jquery-ui-1.10.0.custom.min.css" />
<script src="//cdnjs.cloudflare.com/ajax/libs/jqueryui/1.10.0/jquery-ui.js"></script>

 <main class="grid">
  <aside class='left'>
   <div class="left_inner">
  drag the bottom right handle to resize
   </div>
  </aside>
  <section class="right_top">
   <div class="right_top_inner">right_top_inner</div>
  </section>
  <section class="right_bottom">
   <div class="right_bottom_inner">right_bottom_inner</div>
  </section>
 </main>

❗️ While this works in the simplest possible scenario, it gets problematic in a real life use case. I tried jquery-ui layout which worked somewhat better (here is a demo), but the lib is outdated and is glitchy with frames, so I went with angular-split-pane (based on angular 1) which works fine and is smaller in size. (update: it appears that the project is currently abandoned so probably not the best choice)

您希望实现的目标仅使用 css 即可实现。我修改了你的例子。主要要点是:

  1. 最重要的是,尽量不要在语义布局标签中插入原始内容。使用 header、段落和列表标签,而不是文本和 br 标签。这使您的代码更易于阅读和推理。您的许多问题的发生都是因为网格区域的回流处理方式。
  2. 使用 grid-template 来简化您的布局,因为这将使以后断点重排更容易。
  3. 使用溢出:自动;以及指定调整大小:vertical/horizontal。不设置overflow,resize会失败
  4. 使用 min/max width/height 值创建调整大小的边界。

body {
    margin: 10px;
    height: 100%;
}

main {
    display: grid;
    border: 3px dotted red;
    padding: 3px;
    grid-gap: 3px;
    
    grid-template: 
    "nav head" min-content
    "nav main" 1fr
        / min-content 1fr;
}

nav {
    grid-area: nav;
    border: 3px dotted blue;
    overflow: auto;
    resize: horizontal;
    
    min-width: 120px;
    max-width: 50vw;
}

header {
    grid-area: head;
    border: 3px dotted orange;
    overflow: auto;
    resize: vertical;
    
    min-height: min-content;
    max-height: 200px;
}

section {
    grid-area: main;
    border: 3px dotted gray;
}
<main>
  <nav>
    <ul>
      <li>Nav Item</li>
      <li>Nav Item</li>
      <li>Nav Item</li>
      <li>Nav Item</li>
      <li>Nav Item</li>
      <li>Nav Item</li>
    </ul>
  </nav>

  <header>
    <h1>Header Title</h1>
    <small>Header Subtitle</small>
  </header>

  <section>
    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
  </section>
</main>