Fill remaining screen height below non-fixed header of unkown size

Viewed 193

I want to achieve the layout of the snippet below:

  • non-fixed navbar at the top with unknown height
  • fill the remaining screen space with the #title div
  • the article continues after the title (not visible on the screen initially, only after scrolling down)

The problem with this snippet is, that it completely breaks the semantic hierarchy of the HTML. The #uglyWrapper splits the article in two parts.

I could use #title { height: calc(100vh - $nav-height) }, but the top bar is a flexbox itself. So $nav-height is unknwon.

Is there a CSS-only solution, that doesn't mess with this HTML structure:

body
    nav
    article
        #title
        text

Snippet demonstrating, how it should look like:

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

#title {
  background-color: lightblue;
  height: 100%;
}

html, body {
  height: 100%;
  margin: 0;
  padding: 0;
}

nav {
  background-color: grey;
}
<body>
  <div id="uglyWrapper">
    <nav>top nav with unknown height, not fixed</nav>
  <!--  article -->
    <div id="title">Full height title image</div>
  </div>
  Article continues <br>
  much text <br>
  much text <br>
  much text
  <!-- /article -->
</body>


Addressing mfluehr's answer:

This approach doesn't fill the remaining space. Instead it fills the entire screen height and gets clipped by the header bar. I left the details about the image intentionally out of the question asking for a div instead. Because there are other elements in that div, that require precise layouting. So covering up an area of unknown size is problematic. Please don't get stuck on the details of the image and use to the minimal example. I can get it working from there.

3 Answers

Apply absolute positioning to the <nav>. Since the title image will use object-fit: cover, it shouldn't matter if a chunk from the top is covered by the navigation.

#title {
  background-color: lightblue;
  height: 100vh;
}

html, body {
  height: 100%;
  margin: 0;
  padding: 0;
}

nav {
  background-color: grey;
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
}
<body>
  <nav>top nav with unknown height, not fixed</nav>
  <article>
    <div id="title">Full height title image</div>
    much text <br>
    much text <br>
    much text
  </article>
</body>

I'm not sure, but try this solution with by adding display: grid on the #uglyWrapper element.

#uglyWrapper {
  height: 100%;
  display: grid; /* new line */
  grid-template-rows: auto 1fr 0%; /* new line */
}

#uglyWrapper {
  height: 100%;
  display: grid; /* new line */
  grid-template-rows: auto 1fr 0%; /* new line */
}

nav {
  background-color: hsl(0 0% 50% / 0.5);
  height: 100%;
}

html,
body {
  height: 100%;
  margin: 0;
  padding: 0;
}

#title {
  background-color: lightblue;
}
<div id="uglyWrapper">
  <nav>top nav with unknown height, not fixed</nav>
  <!--  article -->
  <div id="title">Full height title image</div>
  Article continues <br /> much text <br /> much text <br />
  <!-- /article -->
</div>

I gave ЖнецЪ the bounty, because he gave the first answer, that fulfilled all the criteria.

In the final solution however, die grid-approach did not work for me after adding the <img> into the title. For some screen sizes the image forced the title the be taller than allowed.


So I diverted back to the flexbox and discovered that my original mistake was a missing height: 100% (not in the question). Not giving all the ancestor elements of the image up to the flexbox height: 100% was the problem.

This snippet has the desired HTML structure without the ugglyWrapper and a full screen placeholder image.

body {
  display: flex;
  flex-direction: column;
  /*  This does not work for wide and slim screen sizes */
  /*   display: grid; */
  /*   grid-template-rows: auto 1fr; */
}

nav {
  background-color: gray;
}

html,
body {
  height: 100%;
  margin: 0;
  padding: 0;
}

#title {
  height: 100%;
  background-color: lightblue;
}

article {
  height: 100%;
}

img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
<body>
  <nav>top nav with unknown height, not fixed</nav>
  <article>
    <div id="title">
      <img src="https://i.stack.imgur.com/nyIkU.png">
    </div>
    Article continues <br> much text <br> much text <br>
  </article>
</body>

Related