user3230660
user3230660

Reputation:

Using flexbox, how to overlay an image and expand to fill parent container

In the following html I want the txt-box div to be centered in the container, overlay the image, and expand to fill the container. It should have a margin of equal width on all sides allowing part of the image to show like a thick border.

The html shown is passable for what I want except the vertical vs. horizontal margins are always slightly different as the browser window is resized.

I feel like what I have here is a hack and that I am using flex-grow incorrectly. I understand flex-grow works to allow the txt-box div to expand since it is the only element with a grow value. If I can get that resolved I should be able to simply set a margin on txt-box and it should work.

What am I not understanding about flex-grow?

.container {
  display: flex;
  align-items: center;
  justify-content: center;
  border: solid 2px red;
  position: relative;
}

.container img {
  width: 100%;
  flex-grow: 0;
  flex-shrink: 0;
}

.txt-box {
  background-color: white;
  display: flex;
  padding: 5px;
  border: solid 2px blue;
  flex-grow: 1;
  position: absolute;
  width: 90%;
  height: 80%;
}
<div class="container">
  <img src="blocks.png" />
  <div class="txt-box">
    hello world
  </div>
</div>

Upvotes: 1

Views: 1796

Answers (2)

user3230660
user3230660

Reputation:

Thanks to Michael Benjamin for putting me on the path to enlightenment. I finally got it figured out. My original question was actually a portion of what I was trying to accomplish. The answers are to use background-image:url('...') and make sure the table and row elements are display:flex.

JSFiddle

<html>
<head>
    <style>

        .flex-table {
            flex-flow:column;
        }

        .flex-row {
            flex-flow:row;
        }

        .container {
            align-items: center;
            justify-content: center;
            padding: 20px;
            border: solid 2px red;
            background-image:url('https://i.imgur.com/BF3ty6o.jpg');
            background-size:cover;
            background-repeat:no-repeat;
            max-width:500px;
        }

        .txt-box {
            justify-self:stretch;
            align-self:stretch;
            border: solid 2px blue;
            background-color: rgba(192,192,192,0.5);
        }


        body, .flex-table, .flex-row, .container, .txt-box  {
            display:flex;
            flex-grow:1;
        }

        @media (max-width: 768px) {
            .flex-row {
                flex-flow:column;
            }
        }

    </style>

</head>
<body>

<div class="flex-table">
    <div class="flex-row">
        <div class="container">
            <div class="txt-box">
                hello world 1
            </div>
        </div>

        <div class="container">
            <div class="txt-box">
                hello world 2
            </div>
        </div>

        <div class="container">
            <div class="txt-box">
                hello world 3
            </div>
        </div>
    </div>


    <div class="flex-row">
        <div class="container">
            <div class="txt-box">
                hello world 4
            </div>
        </div>

        <div class="container">
            <div class="txt-box">
                hello world 5
            </div>
        </div>

        <div class="container">
            <div class="txt-box">
                hello world 6
            </div>
        </div>
    </div>
</div>
</body>

</html>

Upvotes: 1

Michael Benjamin
Michael Benjamin

Reputation: 371271

What am I not understanding about flex-grow?

Flex properties don't work on absolutely positioned children of a flex container.

§ 4.1. Absolutely-Positioned Flex Children

As it is out-of-flow, an absolutely-positioned child of a flex container does not participate in flex layout.

Therefore, flex-grow: 1 on txt-box is not doing anything. It's just being ignored.

Considering that you want the image simply laying in the background, while the text box has more requirements, I would suggest absolutely positioning the image and leaving the text box in the normal flow.

Then give the text box full width and height, with equal padding on the primary container to keep uniform "margins" across screen sizes.

Here's a demo, with a few extra features to help illustrate the concepts involved.

 body {
   height: 100vh;   
   display: flex;
   margin: 0;
   padding: 10px;
 }
 
 .container {
   flex-grow: 1;
   display: flex;
   align-items: center;
   justify-content: center;
   padding: 20px;
   position: relative;
   border: solid 2px red;
 }
 
 img {
   position: absolute;
   height: 100%;
   width: 100%;
   object-fit: contain; /* also try 'cover' for demo */
 }

 .txt-box {
   z-index: 1;
   width: 100%;
   height: 100%;
   border: solid 2px blue;
   background-color: rgba(192,192,192,0.5);
 }
  
 * {
   box-sizing: border-box;
 }
<div class="container">
  <img src="http://i.imgur.com/60PVLis.png">
  <div class="txt-box">hello world</div>
</div>

jsFiddle demo

Upvotes: 0

Related Questions