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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/46044589/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 03:19:10  来源:igfitidea点击:

Dynamically resize columns in css grid layout with mouse

javascriptjquerycssresizecss-grid

提问by ccpizza

I am trying to dynamically resize css grid layout boxes by dragging the column dividers (or resize placeholders) with the mouse.

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

I set resize: horizontal;on the navelement to resize, and it gets resized when I drag the small resize handle in the lower right corner of the element, but the width of the neighbouring column is not automatically adjusted which leads to overlap. Here is a broken codepen.

resize: horizontal;nav元素上设置了resize,当我拖动元素右下角的resize小手柄时它会被resize,但是相邻列的宽度没有自动调整导致重叠。这是一个损坏的代码笔

HTML:

HTML:

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

CSS:

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;
}

I expected the css grid engine to automatically handle this case but apparently it does not.

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

I experimented with jquery-ui resizablebut it does not seem to work well with css grids.

我尝试了jquery-ui 可调整大小,但它似乎不适用于 css 网格。

I am looking into how to do it with jquery by setting the grid attribute grid-template-columns/rows:to a dynamic value but it is not clear how to catch the events thrown by resizing the element via the resize handle. The jquery resizeevent is only triggered on the windowobject, and not on dom elements.

我正在研究如何通过将 grid 属性grid-template-columns/rows:设置为动态值来使用 jquery 执行此操作,但尚不清楚如何捕获通过调整大小句柄调整元素大小所引发的事件。jquery resize事件仅在window对象上触发,而不在 dom 元素上触发。

What might be a way to do it without having to handle low-level mouse events like dragstart/dragend?

有什么方法可以在不必处理诸如 dragstart/dragend 之类的低级鼠标事件的情况下做到这一点?

采纳答案by baetheus

What you are looking to achieve is possible using only css. I've modified your example. The main takeaways are this:

仅使用 css 就可以实现您要实现的目标。我已经修改了你的例子。主要要点是:

  1. Most importantly, try not to insert raw content in your semantic layout tags. Use header, paragraph, and list tags rather than text and br tags. This makes your code both easier to read and easier to reason about. Many of your problems happened because of how reflow is handled in grid areas.
  2. Use grid-template to simplify your layout as it will make breakpoint reflow easier later on.
  3. Use overflow: auto; along with specifying resize: vertical/horizontal. Without setting overflow, resize will fail.
  4. Use min/max width/height values to create boundaries for resizing.
  1. 最重要的是,尽量不要在语义布局标签中插入原始内容。使用标题、段落和列表标签,而不是文本和 br 标签。这使您的代码更易于阅读和推理。您的许多问题都是由于在网格区域中处理回流的方式而发生的。
  2. 使用 grid-template 来简化你的布局,因为它会使断点回流更容易。
  3. 使用溢出:自动;并指定调整大小:垂直/水平。如果不设置溢出,调整大小将失败。
  4. 使用最小/最大宽度/高度值来创建调整大小的边界。

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>

回答by ccpizza

The solution is to notuse explicit fixed column size (grid-template-columns: 200px 1fr;) but use instead relative column sizes such as grid-template-columns: 0.2fr 1fr;— then the grid CSS engine will handle the resizing of adjacent boxes. Next thing is to add nested divs inside the grid boxes, set their min-height/width to 100% and make them resizable via jqueryui resizable.

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

The fixed jsfiddle.

固定的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 layoutwhich 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)

?? 虽然这适用于最简单的场景,但在现实生活用例中会出现问题。我尝试了jquery-ui 布局,它工作得更好(这里是一个演示),但是库已经过时并且框架有问题,所以我使用了angular-split-pane(基于 angular 1),它工作正常,并且在尺寸。(更新:该项目目前似乎已被放弃,因此可能不是最佳选择)