Graduate Program KB

CSS for Javascript Module 4 - Flexbox


  • Flexbox is one of many layout modes (like Flow or Positioned layout).
  • It is most useful when we have a set of things and we want to control their distribution along the primary axis (either horizontally or vertically).
  • It is still relevant, even with CSS Grid having wide browser support. CSS Grid works best for two-dimensional layouts, whereas Flexbox offers more flexibility for working with a single dimension.
  • When we apply display: flex to an element, we toggle the 'flexbox' layout for the element's children. The parent element will still use flow layout.

Directions and Alignment

To display elements in an inline direction, whilst vertically stretched we can use the following code:

.wrapper {
  display: flex;
  flex-direction: row;
  justify-content: flex-start;
  align-items: stretch;
}
  • Flex direction determines if elements are vertically or horizontally displayed (takes row or column as values)
  • Align Items is used to align items in the opposite axis that the elements are displayed in (opposite of flex-direction). Takes stretch, flex-start, flex-end, center or baseline as values.
  • Justify Content 'pushes' items away from each other. They can be spaced, grouped together etc. Takes flex-start, flex-end, center, space-between, space-around and space-evenly.

To center an element, we can use the following code:

.wrapper {
  display: flex;
  justify-content: center;
  align-items: center;
}

However we have to set the height to 100% on it's parent containers, then the wrapper height will be based off the parent container's height, else the container will be so small that the element will not look to be centred.

Alignment Tricks

If we had a navigation bar with our webpage title, then slightly smaller elements to the right of it on the remains of the navigation bar, we would want these to be perfectly aligned.

ul {
  display: flex;
  justify-content: space-evenly;
  align-items: baseline;
}

Here we use baseline instead of center, as now the bottoms of each character will be aligned, rather than to the middle of the char (which wouldn't look right due to the different sizes).

Align-Self

What if we want specific children to have specific alignments? Using align-self we can override the default alignment provided by a parent. It takes in the same values as align-items. This only works along the secondary axis.

Growing and Shrinking

  • When dealing with flexbox, the minimum content size and hypothetical size are important to consider
  • The minimum content size is the smallest an item can get without its contents overflowing
  • Setting width in a flex row (or height in a flex column) sets the hypothetical size. It isn't a guarantee, more of a suggestion
  • flex-basis has the same effect as width in a flex row (or height in a column). You can use them interchangeably, but flex-basis will win if there is a conflict
  • flex-basis can't scale an element below its minimum content size, but width can
  • flex-grow will allow a child to consume any excess space in the container. It has no effect if there isn't any excess space
  • flex-shrink will pick which item to consume space from, if the container is too small. It has no effect if there is any excess space
  • flex-shrink can't shrink an item below its minimum content size

Ratios

When using flex-grow/shrink etc, we use unitless values. These signify a ratio of the available space. For example, 2 elements within a parent div, one has a flex-grow of 1, and the other of 3. The value of three means we want that component to take up 3 times as much room as the other element.

The 'flex' shorthand

  • flex takes 3 individual values:
    • flex-grow
    • flex-shrink
    • flex-basis
  • By default, flex-grow will distribute any extra space that isn't taken up by the elements
  • flex: 1 will assign flex-grow: 1, but it will also set flex-basis: 0. It won't affect the default value for flex-shrink which is 1
  • Since flex-basis is a synonym for width in the flex-row, we're effectively shrinking each child to have a 'hypothetical width' of 0px, and then distributing all of the space between each child

Constraints

What if we want to use properties like flex-grow, shrink and basis, but set hard limits rather than ratios. To do this, we can utilise min/max-width and min/man-height. We are effectively changing the minimum content size to be a hardcoded value, rather than relying on the size of the element's children.

Shorthand Gotchas

  • When we use the flex shorthand, we set flex-basis: 0.
  • This value will override any width you set.
  • To prevent unwanted surprises, we should instead use flex-basis, and if we need to set either flex-grow or shrink we could use this shorthand:
.item {
  flex: 1 1 200px;
}

Wrapping

  • We know that inline elements in Flow have a super power, they can line-wrap. Flexbox's flex-wrap property is a similar concept to this.
  • We can set flex-wrap: wrap. And now, instead of overflow, the child is pushed to the next line.
main {
  display: flex;
  flex-wrap: wrap;
}
article {
  flex: 1 1 250px;
  mad-width: 250px;
}
article img {
  width: 100%;
}

Flex-wrap allows us to being using two-dimensional layouts. However, CSS Grid is typically better for this.

Groups and Gaps

  • Remember that we can use margin to center, or greedily take up lot's of space
  • For example, margin-right: auto, will greedily take up all the space to the right
const Wrapper = styled.header`
  display: flex;
  gap: 70px;
`

const Logo = styled.a`
  font-size: 1.5rem;
  margin-right: auto;
`
  • We also use the gap property on the wrapper which adds a small space between child elements, but only between, not on the ends

Ordering

  • By default flexbox arranges items based on their DOM order
  • Flexbox also gives us overrides to tweak that order

Flipping Flex-Direction

  • We know of flex-direction property
  • We can also use row-reverse and column-reverse as values
    • This flips the order so they stack from first to last
  • Has the side-effect that things will appear right-aligned instead of left-aligned
    • This is because we change the direction of the axis

If we want to flip children order without changing alignment, we can use justify-content.

.row {
  flex-direction: row-reverse;
  justify-content: flex-end;
}

Order There are two other mechanisms to control order:

  1. The order property on individual children
  • Like a z-index, lower number indicates it will show up first
  1. flex-wrap: wrap-reverse
    • Causes elements to wrap upwards rather than downwards

Flexbox Interactions

.row {
  display: flex;
}

.help-btn {
  /* Assume this is a child of row */
  flex: 1;
  position: fixed;
  right: 0;
  bottom: 0;
}

When there is a conflict between layout modes, positioned layout will always win. In this example, our help button will be fixed to the bottom-right corner of the viewport, and the row Flex container will ignore it, and act as if it were not a child. Relative positioning is the only exception.