9

I am trying to center two div elements side by side in a row with flexbox (display:flex).

The first div element, on the left, just has an image.

The second div element, on the right, has left-aligned inline text of unspecified length.

When the line of text is short enough to fit on one line, both divs are aligned and justified to the center as I expect.

When the line of text is long enough to wrap onto two lines, the second div element does not wrap itself around the content as I expect. Instead, it leaves a large white space on the right side of the div.

I mocked up an example here: http://codepen.io/anon/pen/NGqYQX?editors=110. Vary your browser window's width to see what I mean.

enter image description here

How can I set the second div element to shrink itself to fit the text, so that both div elements appear centered?

.flexbox-container {
  display: flex;
  justify-content: center;
  align-items: center;
}

.div1 {
  margin-right: 30px;
}

.div2 {
  font-size: 48px;
  line-height: 48px;
  text-align: left;
}
<div class="flexbox-container">
  <div class="div1">
    <img src="http://dreamatico.com/data_images/kitten/kitten-2.jpg" width="150px">
  </div>
  <div class="div2">
    This is an example of a line of text.
  </div>
</div>
<br>
<div class="flexbox-container">
  <div class="div1">
    <img src="http://dreamatico.com/data_images/kitten/kitten-2.jpg" width="150px">
  </div>
  <div class="div2">
    This is an example of a much loooooooooooooonger line of text.
  </div>
</div>

Here is a Photoshop mockup showing what I am trying to do:

enter image description here

Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
MattSidor
  • 2,599
  • 4
  • 21
  • 32
  • that is very baffling...wish i knew the answer! i'd like to know what's causing that as well – cocoa Sep 08 '15 at 19:37
  • I'm not seeing what effect you are after. What is this supposed to look like? That's how text wrapping works, flexbox isn't going to change that, – Paulie_D Sep 08 '15 at 20:23
  • @Paulie_D, I edited my question to add a Photoshop mockup to try and show what effect I am after. If this can be accomplished without `flexbox`, I'm totally open to new suggestions to accomplish this effect. – MattSidor Sep 08 '15 at 21:05
  • 1
    It is known that flexbox ignores the reduced width when a longer word gets moved to another line—and therefore expands to fill up the whole row, acting as if the word has not been wrapped. It is a known rendering issue, and the only fix is a JS-based one for now: http://stackoverflow.com/questions/32183933/flexbox-parent-to-extend-width-if-the-child-contains-a-really-long-word. This problem is more widespread than I thought: also seen [here](http://stackoverflow.com/questions/23919777/css-flex-box-trim-box-containing-long-text). – Terry Sep 08 '15 at 21:20
  • 1
    I wrote the answer below nearly two years ago as I was beginning to learn flexbox. I don't think I would have provided the same answer today. I think the duplicate post offers a better explanation and solutions. If you disagree let me know and I'll re-open. – Michael Benjamin Jul 11 '17 at 19:45

1 Answers1

7

In order to achieve your goal (as specified in your second image) we need to make a few adjustments to your HTML and CSS. Everything can be done with flexbox.

HTML

<div id="flex-container-main">

    <div class="flex-container-child">
        <figure>
            <img src="http://dreamatico.com/data_images/kitten/kitten-2.jpg" width="150px">
        </figure>
        <p>This is an example of a line of text.</p> 
    </div>

    <div class="flex-container-child">
        <figure>
            <img src="http://dreamatico.com/data_images/kitten/kitten-2.jpg" width="150px">
        </figure>
        <p>This is an example of a much loooooooooooooonger line of text.</p>
    </div>

</div><!-- end #flex-container-main -->

CSS

#flex-container-main {
    display: flex;
    flex-direction: column;
    align-items: center;
}

.flex-container-child {
    display: flex;
    align-items: center;
    min-height: 127px;
    width: 75%;
    margin: 10px;
}

figure {
    margin: 0 20px 0 0;
    }

img {
    width: 150px;
    height: 127px;
    vertical-align: bottom;
} 

p { 
    font-size: 48px;
    margin: 0;
}

Revised Codepen Demo


Here's what's happening...

Your question asks:

Keeping flexbox centered when text wraps to 2 or more lines

I am trying to center two div elements side by side in a row with flexbox (display:flex).

Let's quickly go over your two images.

Image 1

enter image description here

Image 2

enter image description here

In image 1 all flex items are actually centered. The blue highlight from Chrome Dev Tools emphasizes this point. Each item is perfectly centered on the screen.

Yes, it does get a bit clunky as you re-size the screen smaller – mostly because of the large font size – but the flex items remain centered nonetheless.

In image 2, the flex items are not evenly centered. What you've created in your mock-up is more like a column containing both flexboxes, and the column is centered. But individually only the first row is centered on the screen.

A couple of notes about your code:

  1. With justify-content declared on the flex containers, you are centering the flex items. The flex container itself is not centered.
  2. Since both flexboxes are direct children of the <body>, and <body> has no defined width, the flexboxes align themselves in relation to the viewport.

So to achieve the effect you want we can wrap all your existing mark-up in a new flex container (#flex-container-main). This converts the original flex containers into flex items, which can then be evenly centered as a group.

The new flex items (now classed as .flex-container-child) are given a width to create space and a minimum height based on the height of the image. Each flex item is also declared a flex parent (display: flex) which allows us to use flex properties on child elements. In particular, this is useful for vertically centering the text (as shown in your images).

(Note that my use of HTML semantic elements is not necessary for the code to work. If you prefer the original div tags just swap them back. The important adjustment is the new parent container.)

Lastly (and this may not be important to your layout but just in case), browsers normally give images a small gap of whitespace under their bottom border. This is used to accommodate descenders. With vertical-align: bottom, this space is removed. (For more details see my answer about descenders.)

Community
  • 1
  • 1
Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
  • 3
    thank you so much for this thorough explanation. This makes a lot of sense to me. I also appreciate that you cleaned up and simplified my HTML markup. – MattSidor Sep 09 '15 at 16:54
  • 4
    This is one of the best SO answers I have read in a long time. A+ – darethas Jun 13 '16 at 03:28
  • I am not sure if browser behavior changed since this answer was posted, but today in Chrome, the content is not horizontally centered like in OP's image mock-up. For example, when the browser is ~1570px wide, the content is shifted far to the left. – mattsoave Sep 29 '22 at 20:56