hillin
hillin

Reputation: 1769

flex-column: how to limit the height of grow part so it does not expand?

I'm sure this kind of question was asked before, but I really can't describe it exactly and concisely enough to let the search engine to understand me. So here we go:

To better explain my question I'm writing the code in tailwind style here. A stack snippet is also attached below:

<div class="root w-screen h-screen flex flex-col">
  <div class="header h-[72px] w-full bg-red shrink-0"></div>
  <div class="content grow">
    <!-- a whole lot of content, very tall, height > 2000 px -->
  </div>
</div>

In this example, I would like to limit the height of the entire div.root to 100vh. However, because div.content is very tall, it expands the body that it shows a vertical scrollbar.

Well this is fairly easy to overcome, I only need to add scroll-y-auto to div.content. So the body scrollbar disappears, and div.content shows a vertical scrollbar. Perfect.

However later on, I decided to split div.content into two columns: both column shall have its own vertical scrollbar. Intuitively I changed the code to:

<div class="root w-screen h-screen flex flex-col">
  <div class="header h-[72px] w-full bg-red shrink-0"></div>
  <div class="content grow">
    <div class="left overflow-y-auto">
        <!-- a whole lot of content, very tall, height > 2000 px -->
    </div>
    <div class="right overflow-y-auto">
        <!-- a whole lot of content, very tall, height > 2000 px -->
    </div>
  </div>
</div>

But this does not work at all, as the attached snippet demonstrates. body got its scrollbar back, but not div.left or div.right.

I've explored several ways to solve this problem. In the end the best solution I got was to set the height of div.content to calc(100% - 72px). This works perfectly, but I understand it's only because I know the exact height of div.header is fixed at 72px.

Was I doing something wrong here? What's the most elegant way to solve this kind of problem?

body {
  margin: 0;
}

.root {
  width: 100vw;
  height: 100vh;
  display: flex;
  flex-direction: column;
}

.header {
  height: 72px;
  width: 100%;
  background-color: red;
  flex-shrink: 0;
}

.content {
  flex-grow: 1;
  display: flex;
  flex-direction: row;
}

.very-tall-content {
  background-color: green;
  height: 2400px
}

.left, .right {
  flex-grow: 1;
  margin: 0 4px;
  overflow-y: auto;
}
<div class="root">
  <div class="header"></div>
  <div class="content">
    <div class="left">
      <p class="very-tall-content"></p>
    </div>
    <div class="right">
      <p class="very-tall-content"></p>
    </div>
  </div>
</div>

Upvotes: 0

Views: 1160

Answers (1)

Alireza
Alireza

Reputation: 643

Allright, try this one maybe it fixed your problem :)

instead of using flex for .root use grid. down here we have a header with minimum height of 72px and if it's content overloads, the header will auto-fit them

:root {
  --header-min-height: 72px;
}

body {
  margin: 0;
}

.root {
  display: grid;
  grid-template-rows: minmax(var(--header-min-height), auto) 1fr;
  height: 100vh;
}

.header {
  grid-row: 1;
  background: darkcyan;
}

.content {
  grid-row: 2;
  display: flex;
  background-color: palegreen;
  overflow-y: hidden;
}

.content>div {
  flex-grow: 1;
  overflow-y: auto;
}

.white-space {
  height: 3000px;
}
<div class="root">
  <div class="header"></div>
  <div class="content">
    <div class="left">
      Left Side
      <div class="white-space"></div>
      Left Side
    </div>
    <div class="right">
      Right Side
      <div class="white-space"></div>
      Right Side
    </div>
  </div>
</div>

here's the example if it overloads.

:root {
  --header-min-height: 72px;
}

body {
  margin: 0;
}

.root {
  display: grid;
  grid-template-rows: minmax(var(--header-min-height), auto) 1fr;
  height: 100vh;
}

.header {
  grid-row: 1;
  background: darkcyan;
}

.content {
  grid-row: 2;
  display: flex;
  background-color: palegreen;
  overflow-y: hidden;
}

.content>div {
  flex-grow: 1;
  overflow-y: auto;
}

.white-space {
  height: 3000px;
}

.row {
  display: flex;
  flex-direction: row;
  width: fit-content;
}

.item {
  background: rgba(255, 255, 255, .5);
  width: fit-content;
  padding: 10px;
  margin: 5px;
  border-radius: 5px;
}
<div class="root">
  <div class="header">
    <div class="row">
      <div class="item">test</div>
      <div class="item">test</div>
      <div class="item">test</div>
    </div>
    <div class="row">
      <div class="item">test</div>
      <div class="item">test</div>
      <div class="item">test</div>
    </div>
    <div class="row">
      <div class="item">test</div>
      <div class="item">test</div>
      <div class="item">test</div>
    </div>
  </div>
  <div class="content">
    <div class="left">
      Left Side
      <div class="white-space"></div>
      Left Side
    </div>
    <div class="right">
      Right Side
      <div class="white-space"></div>
      Right Side
    </div>
  </div>
</div>

Upvotes: 1

Related Questions