36

Its a very simple problem but I can't seem to find a suitable solution online. I want to have a list of elements in natural flow with the last element extended to the bottom of the page. So if I have

<div id="top" style="height:50px;"></div>
<div id="bottom" style="background:lightgrey;"></div>

I need element bottom to extend from the bottom of top to the bottom of the page. Any solution that uses only html and css is welcome, and you can add container divs or anything, as long as I can get dynamic resizing of the bottom div

EDIT: I don't want to hard-code any values for bottom, because I want bottom to adjust if top is resized

here's a fiddle for all your fiddling needs: http://jsfiddle.net/8QnLA/

Damjan Pavlica
  • 31,277
  • 10
  • 71
  • 76
woojoo666
  • 7,801
  • 7
  • 45
  • 57

3 Answers3

70

Solution: #1: css tables:

html, body {
  height: 100%;
  width: 100%;
}
body {
  display: table;
  margin: 0;
}
#top, #bottom {
  width: 100%;
  background: yellow;
  display: table-row;
}
#top {
  height: 50px;
}
#bottom {
  background: lightgrey;
  height: 100%;
}

html, body {
  height: 100%;
  width: 100%;
}
body {
  display: table;
  margin: 0;
}
#top, #bottom {
  width: 100%;
  background: yellow;
  display: table-row;
}
#top {
  height: 50px;
}
#bottom {
  background: lightgrey;
  height: 100%;
}
<div id="top" style="height:50px;"><span>A header</span></div>
<div id="bottom" style="background:lightgrey;"><span>The content area - extends to the bottom of the page</span></div>

Codepen #1 (little content)

Codepen #2 (lots of content)

Solution #2: Using calc and viewport units

#top {
  height: 50px;
  background: yellow;
}
#bottom {
  background: lightgrey;
  min-height: calc(100vh - 50px);
}

body {
  margin: 0;
}
#top {
  height: 50px;
  background: yellow;
}
#bottom {
  background: lightgrey;
  min-height: calc(100vh - 50px);
}

Where `min-height: calc(100vh - 50px);` means:

'Let the height of the content div be **at least** 100% of the viewport height minus the 50px height of the header.'
<div id="top" style="height:50px;"><span>A header</span></div>
<div id="bottom" style="background:lightgrey;"><span>The content area - extends to the bottom of the page</span></div>

Codepen #1 (little content)

Codepen #2 (lots of content)

Solution #3 - Flexbox

body {
  margin: 0;
  min-height: 100vh;
}
body {
  display: flex;
  flex-direction: column;
}
#top {
  height: 50px;
  background: yellow;
}
#bottom {
  background: lightgrey;
  flex: 1;
}

body {
  margin: 0;
  min-height: 100vh;
}
body {
  display: flex;
  flex-direction: column;
}
#top {
  height: 50px;
  background: yellow;
}
#bottom {
  background: lightgrey;
  flex: 1;
}
<div id="top" style="height:50px;"><span>A header</span></div>
<div id="bottom" style="background:lightgrey;"><span>The content area - extends to the bottom of the page</span></div>

Codepen #1 - little content

Codepen #2 - lots of content

Danield
  • 121,619
  • 37
  • 226
  • 255
  • 2
    wow thanks for going above and beyond, but the table method was the best for me! – woojoo666 Apr 08 '14 at 11:06
  • Solution 2 will only work if you have content that is visible - if anything extends past the fold - that's where the "#bottom" element will extend to and stop. So it would extend to the bottom of the page from what I understand. – 9_Dave_9 Apr 05 '17 at 13:35
  • Solution 2 doesnt work with safari since it doesnt support calculations involving the viewport-relative units vh and vw. – Thomas Maier Aug 09 '17 at 12:50
  • @user1230795 - thanks for pointing that out - I updated the post using the `min-height` property instead of the `height` property. – Danield Aug 10 '17 at 08:58
  • @ThomasMaier - I updated solution 2 and i just verified that it works in Safari. The problem was that I had used the 'height` property instead of the `min-height` property. – Danield Aug 10 '17 at 09:01
  • @Danield Oh, cool! But I did read also, that Safari doesn't support it. In addition to me trying to use it and cursing Safari. calc + viewport units is the master sword for a lot of responsive design realisation problems. – Thomas Maier Aug 12 '17 at 18:09
3

Set the height of html, body to 100%. Then, you can set the last <div>'s height to 100% and it will be as tall as the window. Since you probably don't want scrolling, you can set overflow: hidden on the html, body as well.

http://jsfiddle.net/GKbzx/

Explosion Pills
  • 188,624
  • 52
  • 326
  • 405
  • @web-tiki it would only hide part of the content if the content extended past the bottom of the page. If it did, a solution like this wouldn't be necessary in the first place – Explosion Pills Apr 08 '14 at 10:38
  • OP seems to need a solution that can adapt to several situations like layout is used on several pages with different content and/or the content is supposed to be updated and/or content displayed on several size viewports. In all these situations content can exeed the bottom of page. – web-tiki Apr 08 '14 at 10:42
  • 1
    -1 Because OP writes that he needs element `bottom` to extend from the bottom of `top` to the bottom of the page; not *beyond* the page. – Frederik Krautwald Apr 23 '15 at 08:08
0

Solution for react or vanilla JS.

const useExpandToPageBottom = () => {
    const ref = useRef<HTMLDivElement | null>(null);
    useEffect(() => {
      if (!ref.current) return;
      const { y } = ref.current.getBoundingClientRect();
      ref.current.style.height = `${window.innerHeight - y}px`;
    });

    return { ref };
};

Use hook like so:

const { ref } = useExpandToBottom()

<div ref={ref}>Div to expand</div>