4

I'm trying to get one flex item to be centered vertically and horizontally.

I'd like for some text to be fixed to the bottom of the flex container.

margin-top:auto on the text just shoves the inner box to the top. Ideas?

.container {
  background: lightblue;
  width: 300px;
  height: 300px;
  display: flex;
  justify-content: center;
  flex-direction: column;
  align-items: center;
  padding: 10px;
}
.container .box {
  background: goldenrod;
  height: 30px;
  width: 30px;
}
<div class="container">
  <div class="box"></div>
  <span>Text</span>
</div>

Here's the codepen.

Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
lowbelly
  • 103
  • 3
  • 9

3 Answers3

8

Try the below instead:

.box  {
    background:goldenrod;
    height: 30px;
    width: 30px;
    margin: auto;
  }
user6801750
  • 242
  • 3
  • 12
  • That one is a winner, thanks! – lowbelly Sep 07 '16 at 16:00
  • 2
    @lowbelly, just keep in mind that this solution centers the `.box` element in the *remaining space*, not the entire space, of the container. The space being occupied by the text is not factored in. Therefore, the centering is off vertically by a length equal to the height of the text element. – Michael Benjamin Sep 08 '16 at 00:07
3

Since flexbox alignment involves the distribution of free space in the container, margin-top: auto won't work in this case because there's no counterweight on the other side.

Therefore, one method for centering the box and bottom-aligning the text involves creating a duplicate of the text element and placing it on the opposite side of the box. This will create a counterweight.

With equal balance on both ends, flex alignment properties (including auto margins) can work.

In this case, even justify-content: space-between would work.

Of course, you'll need to apply visibility: hidden to the duplicate element.

.container {
  background: lightblue;
  width: 300px;
  height: 300px;
  display: flex;
  justify-content: center;
  flex-direction: column;
  align-items: center;
  padding: 10px;
}
.box {
  background: goldenrod;
  height: 30px;
  width: 30px;
  margin: auto 0;   /* or instead use justify-content: space-between on .container */
}
span:first-child {
  visibility: hidden;
}
<div class="container">
  <span>Text</span>
  <div class="box"></div>
  <span>Text</span>
</div>

OR, instead of a duplicate element, use a pseudo-element.

A less intrusive and more semantically proper method would use a pseudo-element as the duplicate. However, for this method to work, you would need to know the height of the actual element, because you would need to match it precisely.

Something like this will work to create equal balance:

.container::before {
    content: "";
    height: 15px; /* must match actual element's height */
}

.container {
  background: lightblue;
  width: 300px;
  height: 300px;
  display: flex;
  justify-content: space-between;
  flex-direction: column;
  align-items: center;
  padding: 10px;
}
.box {
  background: goldenrod;
  height: 30px;
  width: 30px;
}
span {
  height: 15px;
}
.container::before {
  content: "";
  height: 15px;
}
<div class="container">
  <div class="box"></div>
  <span>Text</span>
</div>
Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
  • Duplicating the text is a gross hack and has SEO and accessibility implications. – coreyward Sep 07 '16 at 01:33
  • 1
    @coreyward, hacks aren't ideal solutions, but they're often useful. Tables/Floats for layout. UL/OL for navigation. Duplicate elements / pseudo-elements for equal balance in a flex container. It's just an idea. The user can choose to implement or ignore. – Michael Benjamin Sep 07 '16 at 01:41
2

Here is one way of doing it.

Add position: relative to your .container CSS rule, and then use absolute positioning on .box to position the span to the bottom of the parent container.

You can center the text by allowing .box to have 100% width and then using text-align: center.

.container {
  background: lightblue;
  width: 300px;
  height: 300px;
  display: flex;
  justify-content: center;
  flex-direction: column;
  align-items: center;
  padding: 10px;
  position: relative;
}
.box {
  background: goldenrod;
  height: 30px;
  width: 30px;
}
span {
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  text-align: center;
}
<div class="container">
  <div class="box"></div>
  <span>Text</span>
</div>
Marc Audet
  • 46,011
  • 11
  • 63
  • 83