I have a flex container (the blue square) with the following properties:

display: flex;
justify-content: center;
align-items: center;
flex-wrap: nowrap;

Therefore, its children (the light blue squares) arrange themselves as you see below. However, I'd like to add another child (the green square) out of the normal flow and position it relative to its parent. To position it as you see below, I'd ideally write something like bottom: 20px; and margin: auto;.

I tried to play around with z-index to no avail. How should I approach this? Should I resort to creating another parent element?

Solution 1

Below are five options for achieving this layout:

  1. CSS Positioning
  2. Flexbox with Invisible DOM Element
  3. Flexbox with Invisible Pseudo-Element
  4. Flexbox with flex: 1
  5. CSS Grid Layout

Method #1: CSS Positioning Properties

Apply position: relative to the flex container.

Apply position: absolute to the green flex item.

Now the green square is absolutely positioned within the flex container.

More specifically, the green square is removed from the document flow but stays within the bounds of the nearest positioned ancestor.

Use the CSS offset properties top, bottom, left and right to move the green square around.

One caveat: Some browsers may not completely remove an absolutely-positioned flex item from the normal flow. This changes the alignment in a non-standard, unexpected way. More details: Absolutely positioned flex item is not removed from normal flow in Firefox & IE11

Method #2: Flex Auto Margins & Invisible Flex Item (DOM element)

With a combination of auto margins and a new, invisible flex item the layout can be achieved.

The new flex item is identical to the bottom item and is placed at the opposite end (the top).

More specifically, because flex alignment is based on the distribution of free space, the new item is a necessary counterbalance to keep the three blue boxes vertically centered. The new item must be the same height as the existing green item, or the blue boxes won't be precisely centered.

The new item is removed from view with visibility: hidden.

In short:

  • Create a duplicate of the green box.
  • Place it at the beginning of the list.
  • Use flex auto margins to keep the blue boxes centered, with both green boxes creating equal balance from both ends.
  • Apply visibility: hidden to the duplicate green box.

Method #3: Flex Auto Margins & Invisible Flex Item (pseudo-element)

This method is similar to #2, except it's cleaner semantically and the height of the green box must be known.

  • Create a pseudo-element with the same height as the existing green box.
  • Place it at the start of the container with ::before.
  • Use flex auto margins to keep the blue boxes centered, with the green pseudo and DOM elements creating equal balance from both ends.

Method #4: Add flex: 1 to top and bottom items

Starting with Method #2 or #3 above, instead of worrying about equal height for the top and bottom items to maintain equal balance, just give each one flex: 1. This will force them both to consume available space, thus centering the middle item.

You can then add display: flex to the bottom item in order to align the content.

Method #5: CSS Grid Layout

This may be the cleanest and most efficient method. There is no need for absolute positioning, fake elements or other hackery.

Simply create a grid with three rows. Then center-align the items in the second and third rows. The first row can remain empty.

Solution 2

let the container with position: relative and the green square with position:absolute;

body {
  margin: 0;  

#container {
  display: flex;
  justify-content: center;
  align-items: center;
  flex-wrap: nowrap;
  width: 192px;
  height: 192px;
  border: 4px solid indigo;
  position: relative;
  background: lavender;

.blue {
  margin: 10px;
  width: 30px;
  height: 30px;
  outline: 4px solid skyblue;
  background: honeydew;

#green {
  position: absolute;
  width: 30px;
  height: 30px;
  left: 0;
  right: 0;
  margin: auto;
  bottom: 20px;
  outline: 4px solid yellowgreen;
  background: greenyellow;
<div id=container>
<div class=blue></div><div class=blue></div><div class=blue></div>
<div id=green></div>

Solution 3

you can use a pseudo to move down one row the first three containers then applie a margin:auto to last one

div {
  border:#0066FD solid;;
  /* show me box center */
  background:linear-gradient(to top,rgba(0,0,0,0.2) 50%, transparent 50%),linear-gradient(to left,rgba(0,0,0,0.2) 50%, transparent 50%)

span, div:before {
  border:solid #01CDFF;
  margin:0 auto 0;
span:last-of-type , div:before{
  margin: 12px auto;
  border:solid  #01FE43;
div:before {

span {
   /* show me box center */
  background:linear-gradient(45deg,rgba(0,0,0,0.1) 50%, transparent 50%),linear-gradient(-45deg,rgba(0,0,0,0.1) 50%, transparent 50%)