14

I'm using flex box to align two items to left and right of the container, while vertically centre-aligning them. Here's a very simple example of what I'm trying to achieve.

HTML:

<div class="container">
    <div class="first"></div>
    <div class="second"></div>
</div>

CSS:

.container {
    width:100%;
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    justify-content: space-between;
    align-items: center;
}

.first {
    background-color: yellow;
    width: 200px;
    height: 100px;
}

.second {
    background-color: blue;
    width: 200px;
    height: 100px;
}

Here's the jsfiddle of the example.

This works perfectly well if the screen is wide enough to fit both internal divs on one row. However when the screen size is small (e.g. a mobile phone) and the divs wrap onto the second line, the second one also becomes aligned to the left side (i.e. flex-start). How can I force the second div to always be aligned against the right border, regardless of whether it's on the first row or wrapped onto the second one?

EDIT: In the example, I assigned fixed width to the two child elements - this is for simplicity only. In the real life application, all widths are dynamically changing based on the content read from the database at run-time. Hence, any solution that's based on fixed sizes will not work.

Aleks G
  • 56,435
  • 29
  • 168
  • 265
  • I think you're confused with what `align-self` does. The property refers to how items are aligned along the cross axis (since you're using row as the `flex-direction`, the cross axis refers to the vertical axis). There is so far no `justify-self` attribute as of yet. See: http://css-tricks.com/snippets/css/a-guide-to-flexbox/ – Terry Nov 17 '14 at 23:20
  • @Terry You're right, I got confused. I updated my question accordingly. Nonetheless, I still have the problem of having to align the second div to the right, regardless of whether it's on the first row on wraps. – Aleks G Nov 17 '14 at 23:25

2 Answers2

35

You can try adding some left margin to push your .second element to the right:

.second {
    margin-left: auto;
}

.container {
  width:100%;
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
}
.first {
  background-color: yellow;
  width: 200px;
  height: 100px;
}
.second {
  background-color: blue;
  width: 200px;
  height: 100px;
  margin-left: auto;
}
<div class="container">
  <div class="first"></div>
  <div class="second"></div>
</div>

Or, similarly, justify all elements to the right but push .first element to the left:

.container {
    justify-content: flex-end;
}
.first {
    margin-right: auto;
}

.container {
  width:100%;
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  justify-content: flex-end;
  align-items: center;
}
.first {
  background-color: yellow;
  width: 200px;
  height: 100px;
  margin-right: auto;
}
.second {
  background-color: blue;
  width: 200px;
  height: 100px;
}
<div class="container">
  <div class="first"></div>
  <div class="second"></div>
</div>
Oriol
  • 274,082
  • 63
  • 437
  • 513
  • Is this a generally accepted way to self justify content in a flexbox? I see there is a `justify-self` thing but it does not seem to have any effect on chrome for instance – George Pligoropoulos May 08 '15 at 15:40
  • 1
    @GeorgePligor There is no `justify-self`. There is [`justify-content`](//developer.mozilla.org/docs/Web/CSS/justify-content), which applies to flex containers and defines how to distribute space between and around flex items along the main-axis. There is [`align-items`](//developer.mozilla.org/docs/Web/CSS/align-items), which applies to flex containers and sets the alignment of flex items of the same way as `justify-content` but in the perpendicular direction. And there is [`align-self`](//developer.mozilla.org/docs/Web/CSS/align-self), which applies to flex items and overrides `align-items`. – Oriol May 08 '15 at 23:07
  • Thank you for explaining. I was confused by Webstorm IDE which provides a `justify-content` property with autocomplete. So in order to achieve justification as **[XXX X]** or **[XX XXX]** or **[X XXX X]** etc. the trick is in your answer with `margin-left` or `margin-right` set to `auto` accordingly? – George Pligoropoulos May 09 '15 at 08:20
  • 1
    @GeorgePligor Yes. Auto margins absorb extra space in the corresponding dimension and can be used for alignment and to push adjacent flex items apart ([spec](http://www.w3.org/TR/css-flexbox-1/#item-margins)). – Oriol May 09 '15 at 14:00
1

I found a solution but it is rather "hacky" in nature (see demo here, explanation later), in the sense that it requires you to explicitly know the width of the parent container which will trigger a layout change based on @media.

The reason why your code is not working is because of the confusion over how align-self works. In the flexbox model, "align" refers to alignment along the cross-axis (i.e. in a conventional sense of a "row" layout direction, that will refer to vertical alignment), while "justify" refers to alignment along the main axis (i.e. the row). To better explain my point, I hereby attach an image made by Chris Coyier from his flexbox guide:

align-self description

Therefore, align-self: flex-start means telling the .first to align to the top of the container, and align-self: flex-end means telling .second to align to the bottom of the container. In this case, since you have not declared an explicit height for the parent, the parent will take on the height of its tallest child. Since both .first and .second are 100px tall, the parent will also have a computed height of 100px, therefore making no difference in the alignment (because both with be flush with the start and end of the cross axis).

A hack would be switching the flex-direction to row, with the following restrictions: You know how wide your container will be, or the explicit widths of its children. In this case the breakpoint will be at 400px, where .first and .second will intersect each other.

.container {
    width:100%;
    display: flex;
    flex-direction: column;
    flex-wrap: wrap;
    justify-content: space-between;
    height: 100px;
}

.first {
    background-color: yellow;
    width: 200px;
    height: 100px;
    align-self: flex-start;
}

.second {
    background-color: blue;
    width: 200px;
    height: 100px;
    align-self: flex-end;
}

@media screen and (max-width: 400px) {
    .container {
        height: 200px;
    }
}

Then again, here is a proof-of-concept fiddle, modified from your original one: http://jsfiddle.net/teddyrised/cncozfem/2/

Terry
  • 63,248
  • 15
  • 96
  • 118
  • _it requires you to explicitly know the width of the parent container which will trigger a layout change_ - this part makes the solution unworkable, as the size of the child containers is not fixed and is adjusted dynamically based on their content. Hence any solution that's based on any fixed sizes isn't going to work – Aleks G Nov 17 '14 at 23:41
  • Then you're out of luck. Also, it helps to specify that in your original question. You gave your two child elements explicit widths. If the widths are dynamic, why can't you use the good old float? – Terry Nov 17 '14 at 23:44