【问题标题】:Dynamically resize columns in css grid layout with mouse使用鼠标动态调整css网格布局中的列大小
【发布时间】:2018-02-13 03:16:52
【问题描述】:

我正在尝试通过用鼠标拖动列分隔符(或调整占位符大小)来动态调整 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 这样的低级鼠标事件?

【问题讨论】:

  • 好问题。我认为一旦这项技术真正传播开来,重新调整网格区域的大小将是一件大事。至于为什么拖出第一列时第二列没有重新调整大小,我认为这是因为该操作不会重排文档。这里有一个更完整的解释:stackoverflow.com/q/37406353/3597276
  • @Dekel:谢谢!将尝试查看是否可以适应 css 网格布局;否则可能不得不切换到使用浮点数。

标签: javascript jquery css resize css-grid


【解决方案1】:

解决方案是使用显式的固定列大小 (grid-template-columns: 200px 1fr;) 而是使用相对列大小,例如 grid-template-columns: 0.2fr 1fr; — 然后网格 CSS 引擎将处理相邻框的大小调整。接下来是在网格框中添加嵌套的 div,将它们的最小高度/宽度设置为 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>

❗️ 虽然这适用于最简单的场景,但在现实生活用例中会出现问题。我尝试了jquery-ui layout,效果更好一些(这里是demo),但是库已经过时并且框架有问题,所以我选择了angular-split-pane(基于角度1),它工作正常并且尺寸更小. (更新:目前看来该项目已被放弃,因此可能不是最佳选择)

【讨论】:

    【解决方案2】:

    仅使用 css 即可实现您想要实现的目标。我已经修改了你的例子。主要内容如下:

    1. 最重要的是,尽量不要在语义布局标签中插入原始内容。使用标题、段落和列表标签,而不是文本和 br 标签。这使您的代码更易于阅读和推理。您的许多问题都是由于在网格区域中如何处理回流造成的。
    2. 使用 grid-template 来简化您的布局,因为它会使断点重排以后更容易。
    3. 使用溢出:自动;连同指定调整大小:垂直/水平。不设置溢出,resize会失败。
    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>

    【讨论】:

    • 是否可以拖过整个边框,而不是只拖到右下角?
    • 是:$( ".selector" ).resizable({handles: "e, w"});
    • 非常感谢,溢出:'auto',调整大小:'horizo​​ntal' 为我工作
    • @AlanTygel 由于此答案是纯 CSS,因此您为拖动边框问题找到的解决方案涉及 jQuery,这令人沮丧。我仍在寻找正确的方法来做到这一点(网格布局+完整的边框调整大小处理程序),使用最少或没有额外标记,并且尽可能不依赖......
    • 我想知道网格模板中的语法“1fr / min-content 1fr”是什么
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多