Grid with viewport height and inner scrolling div

半城伤御伤魂 提交于 2019-11-30 09:32:29

问题


I'm trying to create a layout that uses a grid that takes up the entire browser viewport (height: 100vh) and then allows a div within one of the grid items to scroll in the Y dimension.

Here's some example code. There are three grid areas: a header across the top, a left nav, and a content area in the lower right.

I'm trying to make it so div inside the content area (the big-list), is the only thing with a vertical scrollbar, and the rest of the UI stays on the screen.

body {
    margin: 0;
}
.outer-grid {
    display: grid;
    height: 100vh;
    grid-template-columns: 180px 1fr;
    grid-template-rows: min-content 1fr;
}
.top-bar {
    grid-column-start: 1;
    grid-column-end: 3;
    border-bottom: 1px solid rgb(200, 200,200);
}
.header {
    font-weight: bold;
    margin: 8px;
}
.left-nav {
    overflow-y: scroll;
    padding: 8px;
    border-right: 1px solid rgb(200, 200, 200);
}
#content {
    padding-left: 8px;
    padding-right: 8px;
}
#search {
    width:100%;
}
.big-list {
    overflow-y: scroll;
}
.big-list div {
    padding: 8px 0;
    border-top: 1px solid rgb(230,230,230);
}
<body>
  <div class="outer-grid">

    <div class="top-bar">
      <div class="header">Header</div>
    </div>

    <div class="left-nav">
      <div>Nav 1</div>
      <div>Nav 2</div>
      <div>Nav 3</div>        
    </div>

    <div id="content">
      <input id='search' type="text"/>

      <div class='big-list'>
	<div> Row ... </div>
	<div> Row ... </div>
	<div> Row ... </div>    
	<div> Row ... </div>
	<div> Row ... </div>
	<div> Row ... </div>    
	<div> Row ... </div>
	<div> Row ... </div>
	<div> Row ... </div>    
	<div> Row ... </div>
	<div> Row ... </div>
	<div> Row ... </div>    
	<div> Row ... </div>
	<div> Row ... </div>
	<div> Row ... </div>    
	<div> Row ... </div>
	<div> Row ... </div>
	<div> Row ... </div>    
	<div> Row ... </div>
	<div> Row ... </div>
	<div> Row ... </div>    
	<div> Row ... </div>
	<div> Row ... </div>
	<div> Row ... </div>    
	<div> Row ... </div>
	<div> Row ... </div>
	<div> Row ... </div>    
	<div> Row ... </div>
	<div> Row ... </div>
	<div> Row ... </div>    
	<div> Row ... </div>
	<div> Row ... </div>
	<div> Row ... </div>    
	<div> Row ... </div>
	<div> Row ... </div>
	<div> Row ... </div>    
	<div> Row ... </div>
	<div> Row ... </div>
	<div> Row ... </div>    
	<div> Row ... </div>
	<div> Row ... </div>
	<div> Row ... </div>    
	<div> Row ... </div>
	<div> Row ... </div>
	<div> Row ... </div>    
	<div> Row ... </div>
	<div> Row ... </div>
	<div> Row ... </div>    
	<div> Row ... </div>
	<div> Row ... </div>
	<div> Row ... </div>    
	<div> Row ... </div>
	<div> Row ... </div>
	<div> Row ... </div>    
	<div> Row ... </div>
	<div> Row ... </div>
	<div> Row ... </div>    
	<div> Row ... </div>
	<div> Row ... </div>
	<div> Last Row </div>   
      </div>
    </div>
  </div>
</body>

回答1:


Solution

Add this to your code:

#content {
  display: flex;          /* new */
  flex-direction: column; /* new */
}

.big-list {
  flex: 1 0 1px;          /* new */
}

.outer-grid {
  display: grid;
  height: 100vh;
  grid-template-columns: 180px 1fr;
  grid-template-rows: min-content 1fr;
}

.top-bar {
  grid-column-start: 1;
  grid-column-end: 3;
  border-bottom: 1px solid rgb(200, 200, 200);
}

.header {
  font-weight: bold;
  margin: 8px;
}

.left-nav {
  /* overflow-y: scroll; */ /* removed */
  padding: 8px;
  border-right: 1px solid rgb(200, 200, 200);
}

#content {
  display: flex;            /* new */
  flex-direction: column;   /* new */
  padding-left: 8px;
  padding-right: 8px;
}

#search {
  width: 100%;
}

.big-list {
  flex: 1 0 1px;             /* new */
  overflow-y: auto;          /* adjusted */
}

.big-list div {
  padding: 8px 0;
  border-top: 1px solid rgb(230, 230, 230);
}

body {
  margin: 0;
}
<div class="outer-grid">
  <div class="top-bar">
    <div class="header">Header</div>
  </div>
  <div class="left-nav">
    <div>Nav 1</div>
    <div>Nav 2</div>
    <div>Nav 3</div>
  </div>
  <div id="content">
    <input id='search' type="text" />
    <div class='big-list'>
      <div> Row ... </div>
      <div> Row ... </div>
      <div> Row ... </div>
      <div> Row ... </div>
      <div> Row ... </div>
      <div> Row ... </div>
      <div> Row ... </div>
      <div> Row ... </div>
      <div> Row ... </div>
      <div> Row ... </div>
      <div> Row ... </div>
      <div> Row ... </div>
      <div> Row ... </div>
      <div> Row ... </div>
      <div> Row ... </div>
      <div> Row ... </div>
      <div> Row ... </div>
      <div> Row ... </div>
      <div> Row ... </div>
      <div> Row ... </div>
      <div> Row ... </div>
      <div> Row ... </div>
      <div> Row ... </div>
      <div> Row ... </div>
      <div> Row ... </div>
      <div> Row ... </div>
      <div> Row ... </div>
      <div> Row ... </div>
      <div> Row ... </div>
      <div> Row ... </div>
      <div> Row ... </div>
      <div> Row ... </div>
      <div> Row ... </div>
      <div> Row ... </div>
      <div> Row ... </div>
      <div> Row ... </div>
      <div> Row ... </div>
      <div> Row ... </div>
      <div> Row ... </div>
      <div> Row ... </div>
      <div> Row ... </div>
      <div> Row ... </div>
      <div> Row ... </div>
      <div> Row ... </div>
      <div> Row ... </div>
      <div> Row ... </div>
      <div> Row ... </div>
      <div> Row ... </div>
      <div> Row ... </div>
      <div> Row ... </div>
      <div> Row ... </div>
      <div> Row ... </div>
      <div> Row ... </div>
      <div> Row ... </div>
      <div> Row ... </div>
      <div> Row ... </div>
      <div> Row ... </div>
      <div> Row ... </div>
      <div> Row ... </div>
      <div> Last Row </div>
    </div>
  </div>
</div>

Explanation

For an overflow to occur, content must overflow the container.

For content to overflow the container, the container must have a size limitation. Usually it's a fixed or maximum length, such as width: 150px or max-height: 50vh.

From MDN:

In order for overflow to have an effect, the block-level container must have either a set height (height or max-height) or white-space set to nowrap.

You're trying to render a vertical scrollbar on your list element (.big-list), but it doesn't have a height limitation.

The heights you have in place for it are:

  1. 1fr (for the row, set by .outer-container). This isn't even a length. It's a distribution of free space. This cannot trigger an overflow.

  2. height: auto, which is the default height on elements. This doesn't provide any limitation, as content will simply keep expanding the container. So this cannot trigger an overflow, either.

Since you don't want to use fixed heights, but want the list element to render a scrollbar when necessary, you've got to be a bit sneaky. Still, it's a win-win. The browser gets what it wants. You get what you want.

Add this to your code:

#content {
  display: flex;
  flex-direction: column;
}

.big-list {
  height: 1px;
  flex-grow: 1;
}

So what you're doing is turning the list element's parent (#content) into a flex container for the sole purpose of enabling flex-grow on the child (.big-list).

You set a tiny fixed height on the list element (height: 1px). This satisfies the condition needed for an overflow. The browser gets what it wants.

Then, for the list element to fill remaining height, you add flex-grow: 1. You get what you want.

Since height is equivalent to flex-basis in a column-direction flex container, you can simplify to:

flex: 1 0 1px /* flex-grow, flex-shrink, flex-basis */



回答2:


You can apply height to .big-list and .left-nav to height: calc(100vh - 51px); overflow-y: auto; of subtract height of header and search

.big-list {
    overflow-y: scroll;
    height:calc(100vh - 56px);
}

body {
    margin: 0;
}
.outer-grid {
    display: grid;
    height: 100vh;
    grid-template-columns: 180px 1fr;
    grid-template-rows: min-content 1fr;
}
.top-bar {
    grid-column-start: 1;
    grid-column-end: 3;
    border-bottom: 1px solid rgb(200, 200,200);
}
.header {
    font-weight: bold;
    margin: 8px;
}
.left-nav {
    overflow-y: auto;
    padding: 8px;
    border-right: 1px solid rgb(200, 200, 200);
    height: calc(100vh - 51px);
}
#content {
    padding-left: 8px;
    padding-right: 8px;
}
#search {
    width:100%;
}
.big-list {
    overflow-y: scroll;
    height:calc(100vh - 56px);
}
.big-list div {
    padding: 8px 0;
    border-top: 1px solid rgb(230,230,230);
}
<body>
  <div class="outer-grid">

    <div class="top-bar">
      <div class="header">Header</div>
    </div>

    <div class="left-nav">
      <div>Nav 1</div>
      <div>Nav 2</div>
      <div>Nav 3</div>        
    </div>

    <div id="content">
      <input id='search' type="text"/>

      <div class='big-list'>
	<div> Row ... </div>
	<div> Row ... </div>
	<div> Row ... </div>    
	<div> Row ... </div>
	<div> Row ... </div>
	<div> Row ... </div>    
	<div> Row ... </div>
	<div> Row ... </div>
	<div> Row ... </div>    
	<div> Row ... </div>
	<div> Row ... </div>
	<div> Row ... </div>    
	<div> Row ... </div>
	<div> Row ... </div>
	<div> Row ... </div>    
	<div> Row ... </div>
	<div> Row ... </div>
	<div> Row ... </div>    
	<div> Row ... </div>
	<div> Row ... </div>
	<div> Row ... </div>    
	<div> Row ... </div>
	<div> Row ... </div>
	<div> Row ... </div>    
	<div> Row ... </div>
	<div> Row ... </div>
	<div> Row ... </div>    
	<div> Row ... </div>
	<div> Row ... </div>
	<div> Row ... </div>    
	<div> Row ... </div>
	<div> Row ... </div>
	<div> Row ... </div>    
	<div> Row ... </div>
	<div> Row ... </div>
	<div> Row ... </div>    
	<div> Row ... </div>
	<div> Row ... </div>
	<div> Row ... </div>    
	<div> Row ... </div>
	<div> Row ... </div>
	<div> Row ... </div>    
	<div> Row ... </div>
	<div> Row ... </div>
	<div> Row ... </div>    
	<div> Row ... </div>
	<div> Row ... </div>
	<div> Row ... </div>    
	<div> Row ... </div>
	<div> Row ... </div>
	<div> Row ... </div>    
	<div> Row ... </div>
	<div> Row ... </div>
	<div> Row ... </div>    
	<div> Row ... </div>
	<div> Row ... </div>
	<div> Row ... </div>    
	<div> Row ... </div>
	<div> Row ... </div>
	<div> Last Row </div>   
      </div>
    </div>
  </div>
</body>


来源:https://stackoverflow.com/questions/54564976/grid-with-viewport-height-and-inner-scrolling-div

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!