在 CSS 网格布局中为每一列添加滚动

Posted

技术标签:

【中文标题】在 CSS 网格布局中为每一列添加滚动【英文标题】:Add scroll to each column in CSS Grid Layout 【发布时间】:2017-10-08 07:39:29 【问题描述】:

我想在我的网格布局中的每一列上单独滚动。

目前,我正在开发一个仅限移动设备的 Web 应用程序。我想为纵向和横向使用不同的网格布局。

纵向只有 1 列,每个元素一个接一个。这里没问题。

在横向中,我想使用 2 列。我的全部内容显示在左侧,我的导航移动到右侧。现在我希望这两个部分都有一个单独的卷轴。有没有办法实现这个?如果当前列的内容结束,滚动应该停止。

CodePen 上的代码:https://codepen.io/SuddenlyRust/pen/rmJOqV

.grid-container 
  display: grid;
  grid-template-columns: 1fr;
  grid-template-rows: 1fr;
  grid-gap: 15px 0;


header 
  background-color: green;
  grid-column: 1;
  grid-row: 1


main 
  background-color: blue;
  grid-column: 1;
  grid-row: 2;


nav 
  background-color: pink;
  grid-column: 1;
  grid-row: 3;


footer 
  background-color: teal;
  grid-column: 1;
  grid-row: 4;


@media only screen and (orientation: landscape) 
  .grid-container 
    grid-template-columns: 5fr 4fr;
  
  nav 
    grid-column: 2;
    grid-row: 1 / span 3;
  
  footer 
    grid-row: 3;
  


h1 
  min-height: 200px;
<div class="grid-container">
  <header>
    <h1>Logo</h1>
  </header>
  <main>
    <h1>content</h1>
  </main>
  <nav>
    <h1>Navigation</h1>
  </nav>
  <footer>
    <h1>Footer</h1>
  </footer>
</div>

非常感谢您的宝贵时间!

【问题讨论】:

【参考方案1】:

这是来自my answer on your earlier question 的扩展版本,如何使用flexbox 获得标题/内容/主目录和导航的滚动。

Fiddle demo

堆栈sn-p

(function(w, d, timeout) 
  w.addEventListener("load", function() 
    resizer();
  , false);

  w.addEventListener("resize", function() 
    if (!timeout) 
      timeout = setTimeout(function() 
        timeout = null;
        // do resize stuff
        resizer();
      , 66);
    
  , false);

  function resizer() 
    if (w.innerHeight < w.innerWidth) 
      if (!(d.body.classList.contains('landscape'))) 
        d.body.classList.add('landscape');
        d.body.appendChild(d.querySelector('nav'));
      
     else 
      if (d.body.classList.contains('landscape')) 
        d.body.classList.remove('landscape')
        d.querySelector('section').appendChild(d.querySelector('nav'));
      
    
  
(window, document));
html, body 
  margin:0;

header, footer, main, nav 
  margin: 5px;
  padding: 5px;
  border-radius: 5px;
  min-height: 120px;
  border: 1px solid #eebb55;
  background: #ffeebb;

footer 
  order: 2;

nav 
  order: 1;

section 
  display: flex;
  flex-direction: column;


@media only screen and (orientation: landscape) 

  main div 
    height: 400px;
    border: 1px dashed red;
  
  nav div 
    height: 800px;
    border: 1px dashed red;
  

  body.landscape 
    display: flex;
  
  section 
    display: block;
    width: calc(60% - 10px);         /*  10px is for the margin  */
    box-sizing: border-box;
    max-height: calc(100vh - 20px);
    overflow: auto;
  
  nav 
    width: calc(40% - 10px);         /*  10px is for the margin  */
    box-sizing: border-box;
    max-height: calc(100vh - 20px);
    overflow: auto;
  
<section>
  <header>header</header>
  <main>content
    <div>
      This div get a height when in landscape to show scroll in section
    </div>
  </main>
  <footer>footer</footer>
  <nav>navigation
    <div>
      This div get a height when in landscape to show scroll in nav
    </div>
  </nav>
</section>

【讨论】:

是的,干得好@LGSon。这很完美。我能问你一些基本的问题吗?我对javascript不太熟练。第一部分和最后一部分实际上是做什么的? “(函数(d,超时)”和“(文档));”您总是使用变量 d 来操作 dom,但它是如何定义的?我不明白语法。而且我没有得到超时变量。对我来说就像魔术一样。该代码确实有意义,您如何在树周围移动导航部分。 @SuddenlyRust (function(d, timeout) ...)(); 调用一个闭包并包装其中的内容,这样它就不会用变量和其他东西污染全局范围。它使用最后一个(document) 执行自身,其中document(DOM 的文档)作为第一个参数d 传入。我这样做是为了代替写document.body 等,我可以使用较短的d.bodytimeout 用于调整大小事件,因为它是这样传入的,作为参数,它可以通过整个闭包函数访问,就像全局变量一样。希望这是有道理的。 是的,谢谢。要学的东西太多了;)真的很珍惜你的时间。祝你有个美好的一天。我要用jQuery重写它哈哈。所以我可以更容易理解它。但我想我可以使用你的解决方案。它工作得很好 @SuddenlyRust 我建议不要重写 resize 处理程序部分并使用 jQuery resize 事件,因为它没有我的 throttler 功能,除非你添加等效插件当然在。我提供的纯 javascript 对性能的影响尽可能小,并且没有真正的理由 jQuery-fy 它。 @SuddenlyRust 类似这样的东西:codepen.io/anon/pen/PmdJGR ... 虽然使用 jQuery 和纯 javascript 都很好。关于动画事件,这里有一篇好文章:sitepoint.com/css3-animation-javascript-event-handlers【参考方案2】:

在横向我想使用 2 列。我的全部内容显示在左侧,我的导航移到右侧。现在我希望这两个部分都有一个单独的卷轴。有没有办法实现这个?如果当前列的内容结束,滚动应该停止。

在左列中有三个单独的网格项:headermainfooter 元素。

在右列中有一个网格项:nav 元素。

向左列添加滚动条(垂直或水平)是不可行的,因为存在三个单独的元素。您需要将所有元素包装在一个容器中以使单个滚动条起作用。

在右列添加滚动条(垂直或水平)非常简单,因为只有一个元素。

假设您在谈论垂直滚动条,这里有一种方法可以使它工作:

body 
  margin: 0;


.grid-container 
  display: grid;
  grid-template-columns: 1fr;
  grid-template-rows: 1fr;
  grid-gap: 15px 0;
  height: 100vh;


header 
  background-color: green;
  grid-column: 1;
  grid-row: 1


main 
  background-color: blue;
  grid-column: 1;
  grid-row: 2;


nav 
  background-color: pink;
  grid-column: 1;
  grid-row: 3;
  overflow: auto;


footer 
  background-color: teal;
  grid-column: 1;
  grid-row: 4;


@media only screen and (orientation: landscape) 
  .grid-container 
    grid-template-columns: 5fr 4fr;
    grid-template-rows: 1fr 1fr 1fr;
  
  nav 
    grid-column: 2;
    grid-row: 1 / span 3;
  
  footer 
    grid-row: 3;
  
<div class="grid-container">
  <header>
    <h1>Logo</h1>
  </header>
  <main>
    <h1>content</h1>
  </main>
  <nav>
    <h1>Navigation<br><br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br></h1>
  </nav>
  <footer>
    <h1>Footer</h1>
  </footer>
</div>

revised codepen


浏览器支持 CSS 网格

Chrome - 自 2017 年 3 月 8 日起提供全面支持(版本 57) Firefox - 自 2017 年 3 月 6 日起提供全面支持(版本 52) Safari - 自 2017 年 3 月 26 日起全面支持(版本 10.1) Edge - 自 2017 年 10 月 16 日起提供全面支持(版本 16) IE11 - 不支持当前规范;支持过时版本

这是完整的图片:http://caniuse.com/#search=grid

【讨论】:

非常感谢@Michael_B 抽出宝贵时间。但是这个解决方案只有在导航大于左侧内容时才有效。我的导航只占用左侧内容的一半空间。我不确定这是否真的适用于网格布局。 几乎可以使用。但是,如果我在左侧滚动,我的导航就会消失。有没有办法把左边的内容包装在一起? 如果您可以将左侧元素包装在一个容器中,那么一切都会变得容易得多。只需使用弹性盒。 codepen.io/anon/pen/jmZgEo?editors=1100 是的,谢谢。那是我使用 flex 的下一个想法。看起来网格不适合我的解决方案!非常感谢您抽出宝贵时间@Michael_B,您帮了大忙;)

以上是关于在 CSS 网格布局中为每一列添加滚动的主要内容,如果未能解决你的问题,请参考以下文章

在 CSS 网格布局中使用 *ngFor 不希望地在一列中显示所有内容

超过12列的材料设计布局网格

grid实现响应式布局

一行 CSS 代码实现响应式布局 – 使用 Grid 实现的响应式布局

Grid 网格布局

【PyQt】网格布局 QGridLayout