skip to Main Content

I’m trying to create the following CSS layout using flexbox:

enter image description here

Imagine the layout as a flex row, with one box on the left (the image) and to the right a flex column with all the text stacked on top of each other. The height of the box on the left automatically scaled to the height of the flex column to the right. I have gone up to this point so far, but I have been unable to get it into a square shape (as in the width is the same as the height).

Currently I have the code which produces the following result:

.container {
  background: orange;
  display: flex;
  flex-direction: row;
}

.profile_pic {
  aspect-ratio: 1/1;
  background: blue;
}

.text_container {
  display: flex;
  flex-direction: column;
}
<div class="container">
  <div class="profile_pic"></div>

  <div class="text_container">
    <h1>Name: Toby</h1>
    <h2>Gender: Male</h2>
    <h3>Password: 123</h2>
  </div>
</div>

enter image description here

There is meant to be a square shaped blue box on the left of column which contains the text but it’s not showing for some reason?

If I set a specific width, it does show, but this is not what I want as I wish for the width to be the same as the height (maintain a 1/1 aspect ratio):

enter image description here

My current ‘workaround’ is wrapping the blue box in a flex with align-items set to center, and then making the blue box a hard coded size which roughly matches the height of the box:

enter image description here

I see lots of such similar layouts, for example the YouTube channel thing:

enter image description here

StackOverFlow indicator:

enter image description here

I believe such similar layouts are done by using workarounds such as setting an explicit height for the container or the image itself. This approach isn’t fine as there is always a small margin of error, and if I want to remove a line from the column flex to the right, I will need to manually adjust the sizes (it’s not dynamic).

Alas, I believe it’s quite an interesting issue and I hope that more knowledge can be collectively gained about how such layouts are done in CSS.

Any help would be greatly appreciated.

4

Answers


  1. I don’t think this can be solved with CSS if you want to be as flexible as possible with regard to the height. But a few lines of JavaScript can do the job. First determine the height of the outer container. Then assign the received value as width to the image container.

    It might be an advantage to assign an ID to each element instead of working with classes, but just with the provided code I can’t say that. However, you would then have to use document.getElementById() instead of document.querySelector().

    It should also be mentioned that height can be determined differently, depending on requirements:

    clientHeight – height + padding (currently in use)
    offsetHeight – height + padding + border

    And others, but that would be too much for now.
    Here’s the snippet …

    let containerHeight = document.querySelector('.container').clientHeight;
    let imgContainerWidth = document.querySelector('.profile_pic');
    imgContainerWidth.style.width = containerHeight + 'px';
    .container {
        display: flex;
        flex-direction: row;
        background: orange;
    }
    
    .profile_pic {
        margin-right: 30px;
        background: blue;
    }
    
    .text_container {
        display: flex;
        flex-direction: column;
    }
    <div class="container">
        <div class="profile_pic"></div>
        <div class="text_container">
            <h1>Name: Toby</h1>
            <h2>Gender: Male</h2>
            <h3>Password: 123</h2>
        </div>
    <div>
    Login or Signup to reply.
  2. .container {
      background: orange;
      display: flex;
      flex-direction: row;
      height: 300px;
      align-items: center;
    }
    
    .profile_pic {
      aspect-ratio: 1/1;
      background: blue;
      height: 100%;
    
    }
    
    .text_container {
      display: flex;
      flex-direction: column;
      justify-content: space-evenly;
    height: 100%;
      
    }

    Try this out. In here you have to define a height value in the parent container.

    Login or Signup to reply.
  3. It took me hours for this, I just thought it’s supposed to be simple but I couldn’t find the solution sooner. So after tweaking with flexbox, relative-absolute position, and even table layout, I just realized that we can use grid instead to achieve this. The most important thing in here is the min-height: 100% and height: 0 on the first child. The height must be zero so that it’s prevented from the grid height calculation, and the min-height is so that it’s 100% of row’s height:

    .container {
      background: orange;
      display: grid;
      grid-template-columns: auto 1fr;
    }
    
    .profile_pic {
      min-height: 100%;
      height: 0;
      background: blue;
    }
    
    img {
      max-width: 100%;
      height: 100%;
      aspect-ratio: 1/1;
    }
    
    .text_container {
      display: flex;
      flex-direction: column;
    }
    <div class="container">
      <div class="profile_pic">
        <img src="https://placehold.co/2">
      </div>
    
      <div class="text_container">
        <h1>Name: Toby</h1>
        <h2>Gender: Male</h2>
        <h3>Password: 123</h3>
      </div>
      <div>

    You can change the image to something with a not 1/1 ratio, and you’ll see that it will stay in 1/1 ratio.

    Login or Signup to reply.
  4. Also, as an option, you can set .profile_pic { writing-mode: vertical-lr; }. .container must have display: grid;:

    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }
    
    .container {
      background: orange;
      display: grid;
      grid-template-columns: auto 1fr;
    }
    
    .profile_pic {
      aspect-ratio: 1;
      background: blue;
      writing-mode: vertical-lr;
      position: relative;
    }
    
    .profile_pic img {
      position: absolute;
      inset: 0;
      width: 100%;
      height: 100%;
      object-fit: cover;
    }
    
    .text_container {
      display: flex;
      flex-direction: column;
    }
    <div class="container">
      <div class="profile_pic">
        <img src="https://picsum.photos/300/300">
      </div>
      <div class="text_container">
        <h1>Name: Toby</h1>
        <h2>Gender: Male</h2>
        <h3>Password: 123</h2>
      </div>
    </div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search