Shachar Har-Shuv
Shachar Har-Shuv

Reputation: 822

How to set up an element with max-height so that the elements inside it will take the available space evenly (See description)

I have a CSS issue which perhaps is too specific for this forum but I think maybe other people will benefit from it as well. I have an element which has a max-height set, inside it there are two additional elements like so:

enter image description here

Code example:

<div class="container">
  <div class="inner-element">...</div>
  <div class="inner-element">...</div>
</div>

The the content of the two inner element has unknown height, which can be changed in runtime. I want the following behavior:

  1. If the sum of the contents are less than max-height, they should each have their content's height, and the outer element should not be higher then their content: enter image description here

  2. If the sum of contents is more than max-height and both are more than half of it, each should get half the max-height: enter image description here

  3. If the sum of contents is more than max-height but one of the elements' content is less then 50%, the smaller one should have its content's height, and the bigger one should fill the remaining space:

enter image description here

I feel like that should be possible with pure CSS but I couldn't figure out a way to do it. Anyone has any idea?...

Upvotes: 7

Views: 8297

Answers (3)

BeanBoy
BeanBoy

Reputation: 855

Here you go, a flexbox is perfect for this case:

You can give the children also a max-height. The problem with that is that they cant be bigger of that value, if there is still space in the parent div.

If you dont have max-height in the children they will fill all the available space if needed. But now you have the problem that if both if taller then half of the space, they won't share the space 50/50. They will share it proportional of their height.

If you really really want the condition of the 2. behavior you mentiont in your question you need to use javascript.

-> You can add both height from the children and if they the total is bigger than the max-height you can set both to a spesific height.

#parent {
  max-height: 180px;
  width: 100px;
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  align-items: stretch;
}

.child {
  background: yellow;
  border: 2px solid black;
  overflow-x: hidden;
  padding: 5px;
}
<body>

  <div id="parent">

    <div id="a" class="child">
      test<br>te<br>sttes<br>ttes<br>ttes<br>tte<br>sttes<br>t<br>t<br>es<br>t<br>t<br>e<br>stt<br>e<br>s<br>t
    </div>

    <div id="b" class="child">
      t<br>e<br>s<br>t
    </div>

  </div>

</body>

Upvotes: 1

the Hutt
the Hutt

Reputation: 18408

If you do not specify height on container then it's initial value is auto. Auto means it's height is determined by it's children. So height will always be equal to it's content height.

max-height is not same as height, it is applied after height is calculated ref. Setting max-height doesn't mean you are setting height also. You are just clipping the element height.
Your case 2 and 3 demands children to be dependent on parent containers height. But the container's height is dependent on the children. That is why you'll need javascript to implement case 2 and 3.


In case if you decide to have fixed height to the container then you can use grid with auto-fit templet-rows to achieve all the test cases using pure CSS:

//the script is used only for increasing content heights for the demo
var c1, c2;
var r1, r2;

document.addEventListener('DOMContentLoaded', init);

function init() {
  c1 = document.getElementById('c1');
  c2 = document.getElementById('c2');

  r1 = document.getElementById('r1');
  r2 = document.getElementById('r2');

  r1.addEventListener('change', update1);
  r2.addEventListener('change', update2);

  update1();
  update2();
}

function update1() {
  c1.style.height = r1.value + 'px';
  c1.innerText = 'Content Height: ' + r1.value + 'px';
}

function update2() {
  c2.style.height = r2.value + 'px';
  c2.innerText = 'Content Height: ' + r2.value + 'px';
}
* {
  box-sizing: border-box;
}

.container {
  height: 200px;
  border: 2px solid;
  background-color: lemonchiffon;

  display: grid;
  grid-template-rows: repeat(auto-fit, minmax(0, min-content));
}

.container>div {
  border: 1px dashed gray;
  overflow: auto;
  height: fit-content;
  max-height: 100%;
}

.inner-element:nth-child(1) {
  background: lightgreen;
}

.inner-element:nth-child(2) {
  background: lightblue;
}
<div>
  <label for="r1">Element one height: 0</label>
  <input type="range" id="r1" name="r1" min="0" max="400" value="50">400
</div>
<div>
  <label for="height2">Element two height: 0</label>
  <input type="range" id="r2" name="r2" min="0" max="400" value="50">400
</div>

<div class="container">
  <div class="inner-element">
    <div id=c1></div>
  </div>
  <div class="inner-element">
    <div id=c2></div>
  </div>
</div>

Upvotes: 5

Aur&#233;lien B.
Aur&#233;lien B.

Reputation: 517

You do not need to put max-height on any of the children. Just put a max-height on the parent, then the flexbox will do the rest !

.grid {
    --gutterH : 30px;
    --gutterV : 30px;

    display: flex;
    flex-wrap: wrap;
    flex-grow: 1;
    width: calc(100% + var(--gutterV));
    margin: calc(var(--gutterH) / -2) calc(var(--gutterV) / -2);
}

.grid-item {
    --gridItemWidth : auto;
    
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    align-content: flex-start;
    margin: calc(var(--gutterH) / 2) calc(var(--gutterV) / 2);
    width: calc(var(--gridItemWidth) - var(--gutterV));
}

.grid-item.grid-item--onethird {
    --gridItemWidth : calc(100% / 3);
}

.container {
    display: flex;
    flex-direction: column;
    width: 100%;
    max-height: 250px;
    border: solid 1px #000;
}

.inner-element {
    display: flex;
    justify-content: center;
    align-items: center;
    padding: 15px;
    overflow: hidden;
}

.inner-element:not(:last-child) {
    border-bottom: solid 1px #000;
}
<div class="grid">
    <div class="grid-item grid-item--onethird">
        <!-- Case 1 -->
        <div class="container">
            <div class="inner-element">
                1
            </div>
            <div class="inner-element">
                2
            </div>
        </div>
    </div>
    <div class="grid-item grid-item--onethird">
        <!-- Case 2 -->
        <div class="container">
            <div class="inner-element">
                Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed ut risus dapibus purus blandit tristique non vel purus. Nam bibendum elementum justo, rutrum tristique massa faucibus id. Integer ut metus justo. Etiam vitae congue risus. Nulla quis libero vel est fermentum efficitur. Cras mollis aliquet metus id rhoncus. Proin gravida, leo quis rhoncus lacinia, erat nulla consequat magna, at elementum dui tellus facilisis leo. Ut nec ex eleifend, scelerisque lorem nec, bibendum quam. Fusce quis sapien ut sapien lacinia congue.
            </div>
            <div class="inner-element">
                Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed ut risus dapibus purus blandit tristique non vel purus. Nam bibendum elementum justo, rutrum tristique massa faucibus id. Integer ut metus justo. Etiam vitae congue risus. Nulla quis libero vel est fermentum efficitur. Cras mollis aliquet metus id rhoncus. Proin gravida, leo quis rhoncus lacinia, erat nulla consequat magna, at elementum dui tellus facilisis leo. Ut nec ex eleifend, scelerisque lorem nec, bibendum quam. Fusce quis sapien ut sapien lacinia congue.
            </div>
        </div>
    </div>
    <div class="grid-item grid-item--onethird">
        <!-- Case 3 -->
        <div class="container">
            <div class="inner-element">
                1
            </div>
            <div class="inner-element">
                Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed ut risus dapibus purus blandit tristique non vel purus. Nam bibendum elementum justo, rutrum tristique massa faucibus id. Integer ut metus justo. Etiam vitae congue risus. Nulla quis libero vel est fermentum efficitur. Cras mollis aliquet metus id rhoncus. Proin gravida, leo quis rhoncus lacinia, erat nulla consequat magna, at elementum dui tellus facilisis leo. Ut nec ex eleifend, scelerisque lorem nec, bibendum quam. Fusce quis sapien ut sapien lacinia congue.
            </div>
        </div>
    </div>
</div>

Upvotes: 1

Related Questions