How to clip grid cell and provide scroll as well?

29 views Asked by At

There is very good post about trimming 1fr to 0: Why does minmax(0, 1fr) work for long elements while 1fr doesn't?

In general I would like to have a cell which expands as the content grows, but within the limits of its parent.

Currently I have a grid with cell with such lengthy content that even without expanding it is bigger than the entire screen. So I would to do two things -- clip the size of the cell, and secondly -- provide the scroll.

I used minmax(0, 1fr) from the post I mentioned, so grid has free hand to squash the cell to zero, but it still does not effectively compute the height, so the scroller does not not the "fixed" height. Without this information the scroll is not activated.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>

    body
    {
      width: 100vw;
      height: 100vh;
      margin: 0;
      padding: 0;
      overflow: hidden;
    }
    .page
    {
        height: 100%;
        
        /*display: flex;
        flex-direction: column;*/
        
        display:grid;
        grid-template-rows: min-content minmax(0, 1fr);
    }
    .header
    {
    }
    .content
    {
       flex-grow: 1;
       flex-shrink: 1;
       flex-basis: 0;
    }
    
    .quiz-grid
    {
      height: 100%;
      max-height: 100%;
      display: grid;
      grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
      grid-template-rows: minmax(0, 1fr) min-content;
      grid-template-areas: 
        "left    main   right" 
        "footer footer footer";
    }
    .quiz-cell-left
    { 
      grid-area: left;
      min-height: 0;
    }
    .quiz-cell-right
    { 
      grid-area: right;
      min-height: 0;
    }
    .quiz-cell-main
    { 
      grid-area: main;
      border: 1px red solid;
      min-height: 0;
    }
    .quiz-cell-footer 
    { 
      grid-area: footer;
      justify-self: center;
      align-self: center;
    }
    
    /* my scroll view component */
    .scroll-container
    {
      position: relative;
      width: 100%;
      min-height: 0;
      background-color: azure;
    
      
      max-height: 100%;
    }
    .scroll-content
    {
      height: 100%;
      width: 100%;
      overflow-y: auto;
    }
</style>
</head>
<body>

<div class="page">
  <div class="header">Header</div>
  
  <div class="content">
<div class="quiz-grid">
  <div class="quiz-cell-main">
    
    <div class="scroll-container">        <div class="scroll-content">
    <h1>something</h1>
    <h1>else</h1>
    <h1>alice</h1>
    <h1>cat</h1>
    <h1>or dog</h1>
    <h1>now</h1>
    <h1>world</h1>
    <h1>something</h1>
    <h1>else</h1>
    <h1>alice</h1>
    <h1>cat</h1>
    <h1>or dog</h1>
    <h1>now</h1>
    <h1>world</h1>
    <h1>something</h1>
    <h1>else</h1>
    <h1>alice</h1>
    <h1>cat</h1>
    <h1>or dog</h1>
    <h1>now</h1>
    <h1>world</h1>
    <h1>something</h1>
    <h1>else</h1>
    <h1>alice</h1>
    <h1>cat</h1>
    <h1>or dog</h1>
    <h1>now</h1>
    <h1>world</h1>
    
     </div>
   </div> 
    
  </div>
  
  <div class="quiz-cell-footer">
    footer
  </div>
</div>
  </div>
</div>

</body>
</html>

Comment to the code: the content sits in cell "main", the other elements (header, footer) are just to make sure the solution would not be over simplified.

Update 1: originally I used "flex" for outer layout, I switched to grid and I managed to achieve the partial clip at least, I am still stuck with my real clip with scroll.

Update 2: technically it seems I solved it (I am looking at hidden problems now) -- I based the two-div scroller on grid as well with the container scroller "grid-template-rows: minmax(0, auto);", but honestly it was dumb luck, I simply noticed grid propagates height information, so maybe it will work. But I still wonder why "flex" does not work for outer layout, and how to "pass" height info to scroller two-div without resorting to grid (I am not against grid, but with this pace I will have grid everywhere :-)).

1

There are 1 answers

1
Temani Afif On BEST ANSWER

You code contains a lot of useless declarations. We should not try to force things to work by adding a lot of height/min-height/max-height, etc.

body {
  margin: 0;
}
.page {
  height: 100vh; /* full page*/
  display: grid;
  grid-template-rows: min-content minmax(0,1fr);
}
.quiz-grid {
  height: 100%; /* 100% .content height (.content needs nothing)*/
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  grid-template-rows: minmax(0, 1fr) min-content;
  grid-template-areas: 
   "left    main   right" 
   "footer footer footer";
}
.quiz-cell-main {
  grid-area: main;
  border: 1px red solid;
}
.scroll-container {
  background-color: azure;
  height: 100%; /* 100% height of .quiz-cell-main */
  overflow-y: auto; /* add scrollbar */
}
.quiz-cell-footer {
  grid-area: footer;
  place-self: center;
}

/*.quiz-cell-left {
  grid-area: left;
  min-height: 0;
}

.quiz-cell-right {
  grid-area: right;
  min-height: 0;
}
*/
<div class="page">
  <div class="header">Header</div>

  <div class="content">
    <div class="quiz-grid">
      <div class="quiz-cell-main">

        <div class="scroll-container">
          <div class="scroll-content">
            <h1>something</h1>
            <h1>else</h1>
            <h1>alice</h1>
            <h1>cat</h1>
            <h1>or dog</h1>
            <h1>now</h1>
            <h1>world</h1>
            <h1>something</h1>
            <h1>else</h1>
            <h1>alice</h1>
            <h1>cat</h1>
            <h1>or dog</h1>
            <h1>now</h1>
            <h1>world</h1>
            <h1>something</h1>
            <h1>else</h1>
            <h1>alice</h1>
            <h1>cat</h1>
            <h1>or dog</h1>
            <h1>now</h1>
            <h1>world</h1>
            <h1>something</h1>
            <h1>else</h1>
            <h1>alice</h1>
            <h1>cat</h1>
            <h1>or dog</h1>
            <h1>now</h1>
            <h1>world</h1>

          </div>
        </div>

      </div>

      <div class="quiz-cell-footer">
        footer
      </div>
    </div>
  </div>
</div>

Using flexbox you will need almost the same code structure

body {
  margin: 0;
}
.page {
  height: 100vh; /* full page*/
  display: flex;
  flex-direction: column;
}
.content {
  flex: 1;
  min-height: 0;
}
.quiz-grid {
  height: 100%;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  grid-template-rows: minmax(0, 1fr) min-content;
  grid-template-areas: 
   "left    main   right" 
   "footer footer footer";
}
.quiz-cell-main {
  grid-area: main;
  border: 1px red solid;
}
.scroll-container {
  background-color: azure;
  height: 100%; 
  overflow-y: auto;
}
.quiz-cell-footer {
  grid-area: footer;
  place-self: center;
}

/*.quiz-cell-left {
  grid-area: left;
  min-height: 0;
}

.quiz-cell-right {
  grid-area: right;
  min-height: 0;
}
*/
<div class="page">
  <div class="header">Header</div>

  <div class="content">
    <div class="quiz-grid">
      <div class="quiz-cell-main">

        <div class="scroll-container">
          <div class="scroll-content">
            <h1>something</h1>
            <h1>else</h1>
            <h1>alice</h1>
            <h1>cat</h1>
            <h1>or dog</h1>
            <h1>now</h1>
            <h1>world</h1>
            <h1>something</h1>
            <h1>else</h1>
            <h1>alice</h1>
            <h1>cat</h1>
            <h1>or dog</h1>
            <h1>now</h1>
            <h1>world</h1>
            <h1>something</h1>
            <h1>else</h1>
            <h1>alice</h1>
            <h1>cat</h1>
            <h1>or dog</h1>
            <h1>now</h1>
            <h1>world</h1>
            <h1>something</h1>
            <h1>else</h1>
            <h1>alice</h1>
            <h1>cat</h1>
            <h1>or dog</h1>
            <h1>now</h1>
            <h1>world</h1>

          </div>
        </div>

      </div>

      <div class="quiz-cell-footer">
        footer
      </div>
    </div>
  </div>
</div>