scader
scader

Reputation: 525

Use Calc with Max Height

I need an absolute-positioned container that is only as big as it's contents (in order to interact with what is behind the container as much as possible), but never exceeds max height (height of the window).

The contents has three child DIVs, the top two are static height, the bottom takes the remaining space with a scrollbar if it exceeds parent's max-height by content that would hide or show. This works fine if the container has a static height, but if the container only has a max-height it seems the child's calc doesn't function and the content is merely cropped.

Edit: Need to support IE 9+.

Fiddle: https://jsfiddle.net/z87cnmr2/1/

#container {
  position: absolute;
  top: 0;
  left: 0;
  max-height: 100%;
  /* uncomment this static height to see it work */
  /* height: 100%; */
  width: 100px;
  overflow: hidden;
}
#tip {
  background: #ff0;
  height:20px;
}
#top {
  background: #f00;
  height:20px;
}
#btm {
  background: #0f0;
  max-height: calc(100% - 40px);
  overflow-y: auto;
}
html, body {
  padding: 0;
  margin: 0;
  height:100%;
  width:100%;
}
<div id="container">
  <div id="tip">Tips</div>
  <div id="top">Tops</div>
  <div id="btm">
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br> 
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
  </div>
</div>

Upvotes: 1

Views: 37981

Answers (2)

fredrivett
fredrivett

Reputation: 6574

The issue here is that your child (#btm) has a percentage height set, whilst the parent hasn't got an explicit height set.

For some reason in CSS when the child has a percentage height set but the parent only has a max-height or min-height, the child percentage height can't base itself off of this. It needs an explicit height to base itself off of.

In this case, if you can use flexbox (it seems you can, as you're using calc and flexbox has greater support) then I would advise doing something like this:

<div id="container">
  <div id="tip">Tip</div>
  <div id="top">Top</div>
  <div id="btm">
    Btm1<br>
    Btm2<br>
    Btm3<br>
  </div>
</div>

CSS:

#container {
  display: flex;
  flex-direction: column;
  max-height: 100%;
}

#tip { height:20px; }
#top { height:20px; }
#btm { overflow-y: auto; }

I've forked your jsfiddle and implemented the full answer here too.


Edit:

For IE9 support you can use viewport units:

#btm {
  max-height: calc(100vh - 40px);
}

See IE9 updated fiddle.

Note the flex option is preferable if IE9 support is dropped, as it doesn't rely on any "magic numbers" that just work (e.g. the 40px hardcoded here). Magic numbers make your code fragile to breaking with change, but if IE9 support is required this is the option I'd go with.

Upvotes: 9

Jonathan
Jonathan

Reputation: 6537

You can use display:flex to accomplish that, as long as you don't have to support older browsers (< IE11, if I remember correctly).

#container {
  position: absolute;
  top: 0;
  left: 0;
  max-height: 100%;
  /* uncomment this static height to see it work */
  /* height: 100%; */
  width: 100px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}
#tip {
  background: #ff0;
  height:20px;
}
#top {
  background: #f00;
  height:20px;
}
#btm {
  background: #0f0;
  max-height: calc(100% - 40px);
  overflow-y: auto;
}
html, body {
  padding: 0;
  margin: 0;
  height:100%;
  width:100%;
}
<div id="container">
  <div id="tip">Tip</div>
  <div id="top">Top</div>
  <div id="btm">
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br> 
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
    Btm<br>
  </div>
</div>

https://jsfiddle.net/z87cnmr2/4/

If you want to support older versions of IE (>= IE 9), you can use vh since you are basing this off the height of the window:

#container {
  position: absolute;
  top: 0px;
  left: 0px;
  width: 100px;
  max-height: 100%;
  overflow: hidden;
}
#tip {
  background: #ff0;
  height:20px;
}
#top {
  background: #f00;
  height:20px;
}
#btm {
  background: #0f0;
  overflow-y: auto;
  max-height: calc(100vh - 40px);
}

html, body {
  padding: 0;
  margin: 0;
  height:100%;
  width:100%;
}
<div id="container">
    <div id="tip">Tip</div>
    <div id="top">Top</div>
    <div id="btm">
      Btm<br>
      Btm<br>
      Btm<br>
      Btm<br>
      Btm<br>
      Btm<br>
      Btm<br>
      Btm<br>
      Btm<br>
      Btm<br>
      Btm<br>
      Btm<br>
      Btm<br>
      Btm<br>
      Btm<br>
      Btm<br>
      Btm<br>
      Btm<br>
      Btm<br>
      Btm<br>
    </div>
</div>

Fiddle: https://jsfiddle.net/z87cnmr2/6/

Upvotes: 3

Related Questions