skip to Main Content

I want to create a simple webpage with a header and image below it. It needs to meet the following specifications:

  • The sum of the header height and image height should total to the viewport height.
  • The image should maintain its aspect ratio and should not be cropped.
  • If the width of image is less than the viewport width, the image and header should be centered vertically.

Here is an example of how I want it formatted

Below is my attempt to accomplish this:

html,body,#root {
  height: 100vh;
  padding: 0;
  margin: 0;
}

.top-container {
  display: flex;
  justify-content: center;
  height: 100%;
}

.container {
  display: flex;
  flex-direction: column;
  align-items: start;
}

.header {
  display: flex;
  background-color: yellow;
}

.header-item {
  width: 30px;
  height: 30px;
  background-color: green;
  margin: 10px;
}

.image-container {
  display: flex;
  min-height: 0;
  justify-content: flex-start;
  background-color: blue;
}

.image {
  max-width: 100%;
  min-height: 0;
  max-height: 100vh;
}
  <div class="top-container">
    <div class="container">
      <div class="header">
        <div class="header-item"></div>
        <div class="header-item"></div>
        <div class="header-item"></div>
      </div>
      <div class="image-container">
        <img class="image" src="https://wallpapers.com/images/hd/lake-side-trees-live-desktop-jwhxpov3u0jdebb0.jpg"></img>
      </div>
    </div>
  </div>

CodePen

This does everything I wanted except the image-container is wider than the image it contains. This prevents me from centering container correctly.

I suspect this is an issue with how flex containers calculate their width when they contain an image but I could be wrong. Any suggestions or insight would be appreciated.

2

Answers


  1. To do that, I’ll first grab the content container, that’s the one that wraps around everything and set its display to flex. This creates a flexible box that flexes based on the intrinsic size of its elements. And as a result we get horizontal scrolling because these images are huge.

    Login or Signup to reply.
  2. Removing height: 100vh; from the html, body, #root CSS ruleset in your example code seems to solve this issue.

    html,body,#root {
      /* height: 100vh; */
      padding: 0;
      margin: 0;
    }
    

    Run this update and you will see the blue background is no longer visible on your image.

    SNIPPET:

    html,body,#root {
      height: 100vh;
      padding: 0;
      margin: 0;
    }
    
    .top-container {
      display: flex;
      justify-content: center;
      height: 100%;
    }
    
    .container {
      display: flex;
      flex-direction: column;
      align-items: start;
    }
    
    .header {
      display: flex;
      background-color: yellow;
    }
    
    .header-item {
      width: 30px;
      height: 30px;
      background-color: green;
      margin: 10px;
    }
    
    .image-container {
      display: flex;
      min-height: 0;
      justify-content: center;
      background-color: blue;
    }
    
    .image {
      max-width: 100vw;
      height: auto;
    }
    <div class="top-container">
        <div class="container">
          <div class="header">
            <div class="header-item"></div>
            <div class="header-item"></div>
            <div class="header-item"></div>
          </div>
          <div class="image-container">
            <img class="image" src="https://wallpapers.com/images/hd/lake-side-trees-live-desktop-jwhxpov3u0jdebb0.jpg"></img>
          </div>
        </div>
      </div>

    Further details:

    The cause is justify-content: flex-start; which is aligning the image to the start of the container (left hand side) so if you set this to justify-content: center; the blue bordering will be visible on both sides.

    The container box size still exceeds the image size because you’re giving the image it’s maximum width (but no default width) and a maximum height but the size ratio of the container is different from the image. You should probably look into some sort of cover/overflow aspect such as in this Q&A:

    .image {
       width:100%; /*change this to remove max- */
       object-fit:cover; /* Add this */
    }
    

    Snippet 2:

    retaining the #root rules:

    html,body,#root {
      height: 100vh;
      padding: 0;
      margin: 0;
    }
    
    .top-container {
      display: flex;
      justify-content: center;
      height: 100%;
    }
    
    .container {
      display: flex;
      flex-direction: column;
      align-items: start;
    }
    
    .header {
      display: flex;
      background-color: yellow;
    }
    
    .header-item {
      width: 30px;
      height: 30px;
      background-color: green;
      margin: 10px;
    }
    
    .image-container {
      display: flex;
      min-height: 0;
      justify-content: center;
      background-color: blue;
    }
    
    .image {
      width: 100%;
      object-fit:cover;
    }
    <div class="top-container">
        <div class="container">
          <div class="header">
            <div class="header-item"></div>
            <div class="header-item"></div>
            <div class="header-item"></div>
          </div>
          <div class="image-container">
            <img class="image" src="https://wallpapers.com/images/hd/lake-side-trees-live-desktop-jwhxpov3u0jdebb0.jpg"></img>
          </div>
        </div>
      </div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search