2

I have a simple layout requirement where I want to display a header and a logo as normal, and vertically center the content on the page.

To my understanding this should be easily achievable via flexbox using the align-self property.

Here is my code:

html,
body {
  height: 100%;
}
.base {
  display: flex;
  align-content: flex-start;
  flex-wrap: wrap;
  min-height: 100%;
  background: blue;
}
.header {
  flex-grow: 1;
  flex-basis: 100%;
  height: 30px;
  background: yellow;
}
.logo {
  flex-grow: 1;
  flex-basis: 100%;
  height: 50px;
  background: orange;
}
.content {
  flex-grow: 1;
  flex-basis: 100%;
  align-self: center; /* <<< DOESN"T SEEM TO WORK */
  background: green;
}
<div class="base">
  <div class="header">HEADER</div>
  <div class="logo">LOGO</div>
  <div class="content">CONTENT</div>
</div>

jsFiddle

Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
Ilja
  • 44,142
  • 92
  • 275
  • 498

2 Answers2

4

The align-self property is closely related to align-items. One is designed to override the other. Hence, they both function together.

However, align-self and align-items are meant primarily for use in a single-line flex container (i.e., flex-wrap: nowrap).

When you're working in a multi-line flex container (i.e., flex-wrap: wrap) – like in the question – the property to use is align-content.

But when align-content is in effect, both align-items and align-self are overridden.

Therefore, the align-self rule applied to your .content element is being ignored because there are multiple lines in your flex container.

One possible solution to the problem is to switch the container from row to column, then use auto margins on .content:

html, body {
  height: 100%;
}
.base {
  display: flex;
  flex-direction: column;
  min-height: 100%;
  background: blue;
}
base > * {
  width: 100%;
}
.header {
  height: 30px;
  background: yellow;
}
.logo {
  height: 50px;
  background: orange;
}
.content {
  margin: auto 0;
  background: green;
}
<div class="base">
  <div class="header">HEADER</div>
  <div class="logo">LOGO</div>
  <div class="content">CONTENT</div>
</div>

revised fiddle

Just note that the solution above vertically centers the content element in the remaining space, not the total space in the container.

To center the element in the total space, see this post: Center and bottom-align flex items

For more about auto margins, see this post: In CSS Flexbox, why are there no "justify-items" and "justify-self" properties?

Community
  • 1
  • 1
Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
0

Align self works respect the current line where the flex item is.

So, if you want the element to be centered in the flex-container, there must be only one line (in your case, only one row)

The snippet shows how this works, even though it's not a solution to your problem:

html, body {
  height: 100%;
}

.base { 
  display: flex;
  align-content: flex-start;
  flex-wrap: wrap;
  min-height: 100%;
  background: blue;
}

.header {
  flex-grow: 1;
  flex-basis: 30%;
  height: 30px;
  background: yellow;
}

.logo {
  flex-grow: 1;
  flex-basis: 30%;
  height: 50px;
  background: orange;
}

.content {
  flex-grow: 1;
  flex-basis: 30%;
  align-self: center; /* <<< DOESN"T SEEM TO WORK */
  background: green;
}
<div class="base">
  <div class="header">HEADER</div>
  <div class="logo">LOGO</div>
  <div class="content">CONTENT</div>
</div>
vals
  • 61,425
  • 11
  • 89
  • 138