87

I'm using flexbox to align my child elements. What I'd like to do is center one element and leave the other aligned to the very left. Normally I would just set the left element using margin-right: auto. The problem is that pushes the center element off center. Is this possible without using absolute positioning?

HTML & CSS

#parent {
  align-items: center;
  border: 1px solid black;
  display: flex;
  justify-content: center;
  margin: 0 auto;
  width: 500px;
}
#left {
  margin-right: auto;
}
#center {
  margin: auto;
}
<div id="parent">
  <span id="left">Left</span>
  <span id="center">Center</span>
</div>
Carl Edwards
  • 13,826
  • 11
  • 57
  • 119
  • 1
    Check this site for reference to flexbox: http://css-tricks.com/snippets/css/a-guide-to-flexbox/ – Zefiryn Feb 24 '15 at 16:18
  • 4
    I didn't see anything there that addressed my issue. – Carl Edwards Feb 24 '15 at 16:20
  • I put this link as a reference for most accurate and thorough description of flexbox. If you can't find an answer there then it may not be possible. One thing you may try without absolute positioning is to use two containers. One will align first button to the left, the second will align to the center. Then push second up with negative top margin. – Zefiryn Feb 24 '15 at 16:26
  • Yes, it's possible without absolute positioning. Create a third element in the HTML (`#right`). Make it identical to `#left`, except on the other end of the container. Apply the following CSS to `#right`: `visibility: hidden` and `margin-left: auto`. Now the `margin-right: auto` on `#left` will work as desired. More details here: http://stackoverflow.com/q/35250367/3597276 – Michael Benjamin May 13 '16 at 02:43

9 Answers9

127

Add third empty element:

<div class="parent">
  <div class="left">Left</div>
  <div class="center">Center</div>
  <div class="right"></div>
</div>

And the following style:

.parent {
  display: flex;
}
.left, .right {
  flex: 1;
}

Only left and right are set to grow and thanks to the facts that...

  • there are only two growing elements (doesn't matter if empty) and
  • that both get same widths (they'll evenly distribute the available space)

...center element will always be perfectly centered.

This is much better than accepted answer in my opinion because you do not have to copy left content to right and hide it to get same width for both sides, it just magically happens (flexbox is magical).


In action:

.parent {
  display: flex;
}

.left,
.right {
  flex: 1;
}


/* Styles for demonstration */
.parent {
  padding: 5px;
  border: 2px solid #000;
}
.left,
.right {
  padding: 3px;
  border: 2px solid red;
}
.center {
  margin: 0 3px;
  padding: 3px;
  border: 2px solid blue;
}
<div class="parent">
  <div class="left">Left</div>
  <div class="center">Center</div>
  <div class="right"></div>
</div>
Solo
  • 6,687
  • 7
  • 35
  • 67
  • Thank you, this is exactly what I needed to make a modal window's title bar. – Domino Jul 11 '17 at 17:19
  • 24
    You can also use a pseudo-element of the parent instead of an empty element, e.g. `.parent::after{content: ''; flex: 1}` – Smasty Aug 26 '17 at 13:36
  • This is the neatest way! Thank you. – Soli Jan 03 '18 at 08:34
  • How can I use this method to do the opposite? I.e. Center one item, and put another item on the right? – Benisburgers Nov 13 '18 at 11:30
  • @Benisburgers Just put your content to div with class `right` and leave div with class `left` empty. – Solo Nov 13 '18 at 11:41
  • @Solo. Thanks for your reply. Whenever I do that, 'right' moves to the center and sticks right next to the center item. – Benisburgers Nov 13 '18 at 11:44
  • 1
    @Benisburgers Nothing moves anywhere, content is aligned left and it seems like it "moves to center", [like this](https://codepen.io/anon/pen/xQgqpV). Add `text-align: right;` to class `.right`. – Solo Nov 13 '18 at 11:51
33

EDIT: See Solo's answer below, it is the better solution.


The idea behind flexbox is to provide a framework for easily aligning elements with variable dimensions within a container. As such, it makes little sense to provide a layout where the width of one element is totally ignored. In essence, that is exactly what absolute positioning is for, as it takes the element out of the normal flow.

As far as I know, there is no nice way of doing this without using position: absolute;, so I would suggest using it... but If you REALLY don't want to, or can't use absolute positioning then I suppose you could use one of the following workarounds.


If you know the exact width of the "Left" div, then you could change justify-content to flex-start (left) and then align the "Center" div like this:

#center {
    position: relative;
    margin: auto;
    left: -{half width of left div}px;
}

If you do not know the width, then you could duplicate "Left" on the right side, use justify-content: space-between;, and hide the new right element: Just to be clear, this is really, really ugly... better to use absolute positioning than to duplicate content. :-)

#parent {
  align-items: center;
  border: 1px solid black;
  display: flex;
  justify-content: space-between;
  margin: 0 auto;
  width: 500px;
}
#right {
    opacity: 0;
}
<div id="parent">
  <span id="left">Left</span>
  <span id="center">Center</span>
  <span id="right">Left</span>
</div>
pschueller
  • 4,362
  • 2
  • 27
  • 50
  • 4
    I can't agree that the second method is "uglier". It's actually better than the first since Flexbox children won't overlap when there is not enough of horizontal space. – Neurotransmitter Jan 26 '17 at 08:12
16

I have another solution. In my opinion, adding an empty block to the center element is fine, but code-wise it bit ugly.

.parent {
  display: flex;
}

.left {
  flex: 1;
}

.parent::after {
  flex: 1;
  content: '';
}
<div class="parent">
  <div class="left">Left</div>
  <div>Center</div>
</div>
isherwood
  • 58,414
  • 16
  • 114
  • 157
5

Since this is 4 years old I figured I'd update this with a much easier CSS Grid solution.

#parent {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  border: 1px solid black;
  margin: 0 auto;
  width: 500px;
}
#center {
  text-align: center;
}
<div id="parent">
  <span id="left">Left</span>
  <span id="center">Center</span>
</div>
cfx
  • 3,311
  • 2
  • 35
  • 45
2

If you don't want to rely on positioning, the only way I've found that makes it truly centered is to use a combination of auto margin and negative margin prevent the centered element to getting pushed over by the left aligned element. This requires that you know the exact width of the left aligned element though.

.container {
  height: 100px;
  border: solid 10px skyblue;
  
  display: flex;
  justify-content: center;
}

.block {
  width: 120px;
  background: tomato;
}

.justify-start {
  margin-right: auto;
}

.justify-center {
  margin-right: auto;
  margin-left: -120px;
}
<div class="container">
  <div class="block justify-start"></div>
  <div class="block justify-center"></div>
</div>
Martin
  • 1,916
  • 2
  • 25
  • 37
1

As far as I know this is possible with the following code.

https://jsfiddle.net/u5gonp0a/

.box {
    display: flex;
    justify-content: center;
    background-color: green;
    text-align: left;
}

.left {
    padding: 10px;
    background-color: pink;
}

.center {
    padding: 10px;
    background-color: yellow;
    margin: 0 auto;
}
<div class="box">
    <div class="left">left</div>
    <div class="center">center</div>
</div>
Stuiterbal
  • 457
  • 4
  • 11
1

Try this no hacks :)

CSS

.container{
  width: 500px;
  margin: 0 auto;
}
.box{
  display: flex;
  align-items: center;/* just in case*/
  justify-content: space-between;
}
.box p:nth-child(2){
  text-align: center;
  background-color: lime;
  flex: 1 1 0px;
}

HTML

<div class="container">
  <div class="box">
    <p>One</p>
    <p>Two</p>
  </div>
</div>

http://codepen.io/whisher/pen/XpGaEZ

Whisher
  • 31,320
  • 32
  • 120
  • 201
1

Solution 1: give 50% width to center element and use justify-content:space-between

#parent {
  display: flex;
  justify-content: space-between;
}

#center {
  flex-basis: 50%;
}
<div id="parent">
  <span id="left">Left</span>
  <span id="center">Center</span>
</div>

Solution 2: Add one dummy element and hide it.

#parent {
  display: flex;
  justify-content: space-between;
}

#right {
 visibility:hidden;
}
<div id="parent">
  <span id="left">Left</span>
  <span id="center">Center</span>
  <span id="right">Right</span>
</div>
pathe.kiran
  • 2,444
  • 1
  • 21
  • 27
0

If you have a grid system you can use it to do what you want without "extra" css.

Below with bootstrap (V 4.X)
Note: It uses flex under the hood

<div class="row">
  <div class="col text-left">left</col>
  <div class="col text-center">center</col>
  <div class="col text-right">right</col>
</div>

Doc bootstrap: https://getbootstrap.com/docs/4.6/layout/grid/

Et voilà ! :)

rdhainaut
  • 2,659
  • 1
  • 24
  • 34