In CSS Flexbox, why are there no "justify-items" and "justify-self" properties?
Asked Answered
O

5

1099

Consider the main axis and cross axis of a flex container:

An illustration of the various directions and sizing terms as applied to a row flex container Source: W3C

To align flex items along the main axis there is one property:

To align flex items along the cross axis there are three properties:

In the image above, the main axis is horizontal and the cross axis is vertical. These are the default directions of a flex container.

However, these directions can be easily interchanged with the flex-direction property.

/* main axis is horizontal, cross axis is vertical */
flex-direction: row;
flex-direction: row-reverse;

/* main axis is vertical, cross axis is horizontal */    
flex-direction: column;
flex-direction: column-reverse;

(The cross axis is always perpendicular to the main axis.)

My point in describing how the axes' work is that there doesn't seem to be anything special about either direction. Main axis, cross axis, they're both equal in terms of importance and flex-direction makes it easy to switch back and forth.

So why does the cross axis get two additional alignment properties?

Why are align-content and align-items consolidated into one property for the main axis?

Why does the main axis not get a justify-self property?


Scenarios where these properties would be useful:

  • placing a flex item in the corner of the flex container
    #box3 { align-self: flex-end; justify-self: flex-end; }

  • making a group of flex items align-right (justify-content: flex-end) but have the first item align left (justify-self: flex-start)

Consider a header section with a group of nav items and a logo. With justify-self the logo could be aligned left while the nav items stay far right, and the whole thing adjusts smoothly ("flexes") to different screen sizes.

  • in a row of three flex items, affix the middle item to the center of the container (justify-content: center) and align the adjacent items to the container edges (justify-self: flex-start and justify-self: flex-end).

Note that values space-around and space-between on justify-content property will not keep the middle item centered about the container if the adjacent items have different widths.

#container {
  display: flex;
  justify-content: space-between;
  background-color: lightyellow;
}
.box {
  height: 50px;
  width: 75px;
  background-color: springgreen;
}
.box1 {
  width: 100px;
}
.box3 {
  width: 200px;
}
#center {
  text-align: center;
  margin-bottom: 5px;
}
#center > span {
  background-color: aqua;
  padding: 2px;
}
<div id="center">
  <span>TRUE CENTER</span>
</div>

<div id="container">
  <div class="box box1"></div>
  <div class="box box2"></div>
  <div class="box box3"></div>
</div>

<p>note that the middlebox will only be truly centered if adjacent boxes are equal width</p>

jsFiddle version


As of this writing, there is no mention of justify-self or justify-items in the flexbox spec.

However, in the CSS Box Alignment Module, which is the W3C's unfinished proposal to establish a common set of alignment properties for use across all box models, there is this:

enter image description here                                                                                                                                                    Source: W3C

You'll notice that justify-self and justify-items are being considered... but not for flexbox.


I'll end by reiterating the main question:

Why are there no "justify-items" and "justify-self" properties?

Octo answered 13/9, 2015 at 15:30 Comment(6)
How would you expect justify-self to work for a flex item? Suppose you have items a,b,c,d with extra space to distribute around them, and the flex container has justify-content: space-between, so they end up like |a b c d|. What would it mean to add e.g. justify-self: center or 'justify-self: flex-end` just to item 'b' there? Where would you expect it to go? (I see some demos in one of the answers here, but I don't see a clear way that it would work in general.)Macymad
(Alternately: suppose we have justify-content: flex-start, so the items are crowded at the beginning like |abcd |. What would you expect it to do, if you put justify-self: [anything] on item 'b' there?)Macymad
@dholbert, you wrote: How would you expect justify-self to work for a flex item? I would say not so differently than auto margins already work on flex items. In your second example, justify-self: flex-end on item d would move it to the far edge. That in itself would be a great feature, which auto margins can already do. I posted an answer with a demonstration.Octo
I'm mostly seeing more use-cases here, and use-cases are great -- but the tricky bit is how to shoehorn this into the actual way that justify-content and justify-self are specified, so that cases with conflicts (like the scenarios I asked about) are clearly & sensibly defined. As I noted in my answer here, {justify|align}-selfare about aligning items within a larger box which is sized independently of the {justify|align}-self value -- and there is no such box, in the main axis, for a flex item to be aligned into.Macymad
RE "no different from auto margins" - I was actually asking about how you imagine justify-self and justify-content would interact, in cases where they conflict (like the scenarios I laid out). Auto margins simply do not interact with justify-content at all - they steal all of the packing space before justify-content gets a chance to use it. So, auto margins aren't really a good analog for how this would work.Macymad
Because that would be consistent and would break with the long CSS tradition of inconsistency.Thacker
O
1918

Methods for Aligning Flex Items along the Main Axis

As stated in the question:

To align flex items along the main axis there is one property: justify-content

To align flex items along the cross axis there are three properties: align-content, align-items and align-self.

The question then asks:

Why are there no justify-items and justify-self properties?

One answer may be: Because they're not necessary.

The flexbox specification provides two methods for aligning flex items along the main axis:

  1. The justify-content keyword property, and
  2. auto margins

justify-content

The justify-content property aligns flex items along the main axis of the flex container.

It is applied to the flex container but only affects flex items.

There are five alignment options:

  • flex-start ~ Flex items are packed toward the start of the line.

    enter image description here

  • flex-end ~ Flex items are packed toward the end of the line.

    enter image description here

  • center ~ Flex items are packed toward the center of the line.

    enter image description here

  • space-between ~ Flex items are evenly spaced, with the first item aligned to one edge of the container and the last item aligned to the opposite edge. The edges used by the first and last items depends on flex-direction and writing mode (ltr or rtl).

    enter image description here

  • space-around ~ Same as space-between except with half-size spaces on both ends.

    enter image description here


Auto Margins

With auto margins, flex items can be centered, spaced away or packed into sub-groups.

Unlike justify-content, which is applied to the flex container, auto margins go on flex items.

They work by consuming all free space in the specified direction.


Align group of flex items to the right, but first item to the left

Scenario from the question:

  • making a group of flex items align-right (justify-content: flex-end) but have the first item align left (justify-self: flex-start)

    Consider a header section with a group of nav items and a logo. With justify-self the logo could be aligned left while the nav items stay far right, and the whole thing adjusts smoothly ("flexes") to different screen sizes.

enter image description here

enter image description here


Other useful scenarios:

enter image description here

enter image description here

enter image description here


Place a flex item in the corner

Scenario from the question:

  • placing a flex item in a corner .box { align-self: flex-end; justify-self: flex-end; }

enter image description here


Center a flex item vertically and horizontally

enter image description here

margin: auto is an alternative to justify-content: center and align-items: center.

Instead of this code on the flex container:

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

You can use this on the flex item:

.box56 {
    margin: auto;
}

This alternative is useful when centering a flex item that overflows the container.


Center a flex item, and center a second flex item between the first and the edge

A flex container aligns flex items by distributing free space.

Hence, in order to create equal balance, so that a middle item can be centered in the container with a single item alongside, a counterbalance must be introduced.

In the examples below, invisible third flex items (boxes 61 & 68) are introduced to balance out the "real" items (box 63 & 66).

enter image description here

enter image description here

Of course, this method is nothing great in terms of semantics.

Alternatively, you can use a pseudo-element instead of an actual DOM element. Or you can use absolute positioning. All three methods are covered here: Center and bottom-align flex items

NOTE: The examples above will only work – in terms of true centering – when the outermost items are equal height/width. When flex items are different lengths, see next example.


Center a flex item when adjacent items vary in size

Scenario from the question:

  • in a row of three flex items, affix the middle item to the center of the container (justify-content: center) and align the adjacent items to the container edges (justify-self: flex-start and justify-self: flex-end).

    Note that values space-around and space-between on justify-content property will not keep the middle item centered in relation to the container if the adjacent items have different widths (see demo).

As noted, unless all flex items are of equal width or height (depending on flex-direction), the middle item cannot be truly centered. This problem makes a strong case for a justify-self property (designed to handle the task, of course).

#container {
  display: flex;
  justify-content: space-between;
  background-color: lightyellow;
}
.box {
  height: 50px;
  width: 75px;
  background-color: springgreen;
}
.box1 {
  width: 100px;
}
.box3 {
  width: 200px;
}
#center {
  text-align: center;
  margin-bottom: 5px;
}
#center > span {
  background-color: aqua;
  padding: 2px;
}
<div id="center">
  <span>TRUE CENTER</span>
</div>

<div id="container">
  <div class="box box1"></div>
  <div class="box box2"></div>
  <div class="box box3"></div>
</div>

<p>The middle box will be truly centered only if adjacent boxes are equal width.</p>

Here are two methods for solving this problem:

Solution #1: Absolute Positioning

The flexbox spec allows for absolute positioning of flex items. This allows for the middle item to be perfectly centered regardless of the size of its siblings.

Just keep in mind that, like all absolutely positioned elements, the items are removed from the document flow. This means they don't take up space in the container and can overlap their siblings.

In the examples below, the middle item is centered with absolute positioning and the outer items remain in-flow. But the same layout can be achieved in reverse fashion: Center the middle item with justify-content: center and absolutely position the outer items.

enter image description here

Solution #2: Nested Flex Containers (no absolute positioning)

.container {
  display: flex;
}
.box {
  flex: 1;
  display: flex;
  justify-content: center;
}
.box71 > span { margin-right: auto; }
.box73 > span { margin-left: auto;  }

/* non-essential */
.box {
  align-items: center;
  border: 1px solid #ccc;
  background-color: lightgreen;
  height: 40px;
}
<div class="container">
  <div class="box box71"><span>71 short</span></div>
  <div class="box box72"><span>72 centered</span></div>
  <div class="box box73"><span>73 loooooooooooooooong</span></div>
</div>

Here's how it works:

  • The top-level div (.container) is a flex container.
  • Each child div (.box) is now a flex item.
  • Each .box item is given flex: 1 in order to distribute container space equally.
  • Now the items are consuming all space in the row and are equal width.
  • Make each item a (nested) flex container and add justify-content: center.
  • Now each span element is a centered flex item.
  • Use flex auto margins to shift the outer spans left and right.

You could also forgo justify-content and use auto margins exclusively.

But justify-content can work here because auto margins always have priority. From the spec:

8.1. Aligning with auto margins

Prior to alignment via justify-content and align-self, any positive free space is distributed to auto margins in that dimension.


justify-content: space-same (concept)

Going back to justify-content for a minute, here's an idea for one more option.

  • space-same ~ A hybrid of space-between and space-around. Flex items are evenly spaced (like space-between), except instead of half-size spaces on both ends (like space-around), there are full-size spaces on both ends.

This layout can be achieved with ::before and ::after pseudo-elements on the flex container.

enter image description here

(credit: @oriol for the code, and @crl for the label)

UPDATE: Browsers have begun implementing space-evenly, which accomplishes the above. See this post for details: Equal space between flex items


PLAYGROUND (includes code for all examples above)

Octo answered 22/11, 2015 at 15:37 Comment(17)
The answer above covers the main-axis, justify-content and auto margins. For the other side of the coin -- the cross-axis, align-items, align-self and align-content -- see this post: https://mcmap.net/q/36648/-how-does-flex-wrap-work-with-align-self-align-items-and-align-content/3597276Octo
Good examples, but the centering aspect is still non-trivial. How would you adjust Solution #2: Nested Flex Containers when there is an uneven number of items surrounding the middle item? See this example, where the container approach leads to the center item being slightly misaligned from absolute center if we have two items to the right. As you note, the absolute positioning has the disadvantage that it is removed from the document flow, which is not ideal either.Goddess
@MarkW, you're making the case for the justify-self property... auto margins are helpful, but justify-self: center would be ideal. The way to solve the problem you presented would be to create invisible duplicate items on the opposite side. See my answer here: https://mcmap.net/q/36656/-center-one-and-right-left-align-other-flexbox-element/3597276Octo
Your space-same concept is a real thing now. It's called space-evenly, but it's only supported by Firefox at the moment: developer.mozilla.org/en-US/docs/Web/CSS/justify-contentRecluse
@benface, Yes, you're right. Thanks for pointing that out. I've actually been writing about space-evenly in other answers: https://mcmap.net/q/36654/-equal-space-between-flex-items/3597276Octo
In fact, space-evenly was supported in Chrome 57-60, but only for Grid layout. It was a bug that has been fixed, and since Chrome 61 it is supported there for Flexbox as well. Also, there is the way to emulate it without pseudo-elements: .item { margin-right: auto } .item:first-child { margin-left: auto }.Dichromate
Soon time for an update :) ... developer.mozilla.org/en-US/docs/Web/CSS/justify-selfBunin
@LGSon, on that MDN page, click on the link to the spec. You'll find that justify-self does not (and will not) apply to flex items. They even have a section covering this issue: drafts.csswg.org/css-align/#justify-flexOcto
Interesting, as on the MDN page, in the Syntax/Value section, the value flex-start explicit states ...the alignment container depending on the flex container's main-start or cross-start sideBunin
@LGSon, yes, I saw that. As good as MDN is, it's still second-hand information (and, as you can see, subject to human error). It's always safer to refer to the original source: The W3C. Browser makers don't refer to MDN. They use the specs.Octo
Should any and all flex-box questions be closed as duplicates to this? This question was closed as a duplicate. Clearly, this post covers it all. Just wondering if we should be closing flex questions with a general "here's everything you need to know", rather than answering specific questions with "here's where you went wrong".Scratchy
@MatthewJohnson, in reference to your linked question, this answer is not a "general" solution. In fact, it gives a specific solution to the problem described, and an explanation. But if you don't agree, you can vote to reopen.Octo
I really hope the people at CSS Consortium (or how they call themselves) will take the idea of justify-self into regard... I sometimes find it ridiculous how complicated workarounds you sometimes have to do to achieve problem solutions... as if anybody really knows about those "tricks" that you mentioned above ;)Schlueter
If it helps anyone, margin: auto isn't just an alternative to justify-content: center and align-items: center. If the item extends past the parent boundaries, the parent's overflow will allow the full item to be viewed with scrollbars with auto. This isn't the case when it's centered by flex, it goes off the edges and the scrollbar does nothing.Steffens
What if I need to set block alignment along main axis with styles of that block, while it's parent has justify-content set? Is it possible?Thetic
I think there is still one use-case that would be perfect for justify-self – it's when you want item to be stretched as soon as it's wrapped, in that case you could write justify-self: stretch, currently it's not possible with justify-content and auto marginsPettigrew
@MichaelBenjamin you said because it's not needed for main axis, but it is not needed for cross axis as well, right? you can use the same technicsLavinalavine
W
236

I know this is not an answer, but I'd like to contribute to this matter for what it's worth. It would be great if they could release justify-self for flexbox to make it truly flexible.

It's my belief that when there are multiple items on the axis, the most logical way for justify-self to behave is to align itself to its nearest neighbours (or edge) as demonstrated below.

I truly hope, W3C takes notice of this and will at least consider it. =)

enter image description here

This way you can have an item that is truly centered regardless of the size of the left and right box. When one of the boxes reaches the point of the center box it will simply push it until there is no more space to distribute.

enter image description here

The ease of making awesome layouts are endless, take a look at this "complex" example.

enter image description here

Wavy answered 15/9, 2015 at 10:18 Comment(3)
@Wavy this is amazing! Thank you for taking the time to draft this. I hope you don’t mind but I’ve submitted it here: discourse.wicg.io/t/flexbox-justify-self-property/1146Thayer
Hi Mark, @Zaqx, I posted an answer that may cover some of the use-cases mentioned in this answer. I've discovered that a lot can still be done in the main axis without needing justify-self and justify-items.Octo
Regarding centering something in between two other items I recently had to do the same and came up with using css grid and grid-template-columns: minmax(50px, 1fr) 1200px minmax(100px, 1fr) for centering something inside fixed margins. As the page expands the 1st and 3rd column end up the same size (once the page width is greater than 1200+50+100) which means the 2nd column is dead center. I used this for 'springy' margins but the 1st and 3rd column could equally contain actual content and then you'd probably use min-content.Tyrocidine
M
32

This was asked on the www-style list, and Tab Atkins (spec editor) provided an answer explaining why. I'll elaborate on that a bit here.

To start out, let's initially assume our flex container is single-line (flex-wrap: nowrap). In this case, there's clearly an alignment difference between the main axis and the cross axis -- there are multiple items stacked in the main axis, but only one item stacked in the cross axis. So it makes sense to have a customizeable-per-item "align-self" in the cross axis (since each item is aligned separately, on its own), whereas it doesn't make sense in the main axis (since there, the items are aligned collectively).

For multi-line flexbox, the same logic applies to each "flex line". In a given line, items are aligned individually in the cross axis (since there's only one item per line, in the cross axis), vs. collectively in the main axis.


Here's another way of phrasing it: so, all of the *-self and *-content properties are about how to distribute extra space around things. But the key difference is that the *-self versions are for cases where there's only a single thing in that axis, and the *-content versions are for when there are potentially many things in that axis. The one-thing vs. many-things scenarios are different types of problems, and so they have different types of options available -- for example, the space-around / space-between values make sense for *-content, but not for *-self.

SO: In a flexbox's main axis, there are many things to distribute space around. So a *-content property makes sense there, but not a *-self property.

In contrast, in the cross axis, we have both a *-self and a *-content property. One determines how we'll distribute space around the many flex lines (align-content), whereas the other (align-self) determines how to distribute space around individual flex items in the cross axis, within a given flex line.

(I'm ignoring *-items properties here, since they simply establish defaults for *-self.)

Macymad answered 14/9, 2015 at 16:20 Comment(4)
I understand how a justify-self could be a problem on an axis with multiple items as opposed to one item. However I really hope they will look into it further, in a multiple items situation how would justify-self behave, because there are some situations where this could be really useful. For example (#32379453).Wavy
Nice find on that mailing list. Trying to wrap my head around it, as I still see good use case possibilities for justify-self.Octo
I added a bit more clarification, explaining how *-self is about cases where we only have one thing to align whereas *-content is about cases where we have many things to align. Does that make it a bit clearer?Macymad
Yes, it's more clear. I appreciate the explanation. But it seems to all boil down to a simple preference by the spec authors, not a particular need based on logic. From the mailing list you referenced: The *-self properties only work if the child is all alone in that axis. Why? There doesn't seem to be a need for this. It's an arbitrary decision. A preference. In fact, auto margins, also part of the spec, enable *-self alignment with multiple items in the line. No clear reason why keyword properties can't, as well.Octo
B
1

I know this doesn't use flexbox, but for the simple use-case of three items (one at left, one at center, one at right), this can be accomplished easily using display: grid on the parent, grid-area: 1/1/1/1; on the children, and justify-self for positioning of those children.

<div style="border: 1px solid red; display: grid; width: 100px; height: 25px;">
  <div style="border: 1px solid blue; width: 25px; grid-area: 1/1/1/1; justify-self: left;"></div>
  <div style="border: 1px solid blue; width: 25px; grid-area: 1/1/1/1; justify-self: center;"></div>
  <div style="border: 1px solid blue; width: 25px; grid-area: 1/1/1/1; justify-self: right;"></div>
</div>
Boxer answered 20/7, 2019 at 20:45 Comment(1)
Thanks for the answer, but it doesn't really address the question. Also, there's a simpler way to accomplish your layout: jsfiddle.net/fga89m2oOcto
H
1

I just found my own solution to this problem, or at least my problem.
I was using justify-content: space-around instead of justify-content: space-between;.

This way the end elements will stick to the top and bottom, and you could have custom margins if you wanted.

Horary answered 17/4, 2020 at 2:18 Comment(1)
This does not answer the question. Please only provide answers that directly address the question asked by the OP.Thymus

© 2022 - 2024 — McMap. All rights reserved.