Both determine how the content is aligned.
1. justify-content:
along main axis
(sets horizontal alignment/spacing if flex-direction is row or vertical alignment/spacing if flex-direction is column)
For example, when flex-direction is row (the default):
flex-start;
Align children horizontally to the left
flex-end;
Align children horizontally to the right
center;
Align children horizontally in the center (impressive!)
space-between;
Distribute children horizontally evenly across the full width
space-around;
Distribute children horizontally evenly across the full width (with space on the edges)
2. align-items:
along cross axis
(sets vertical alignment if flex-direction is row or horizontal alignment if flex-direction is column)
For example, when flex-direction is row (the default):
flex-start;
Align children vertically at the top
flex-end;
Align children vertically at the bottom
center;
Align children vertically in the center (impressive!)
baseline;
Align children vertically so their baselines align (not very effective)
stretch;
Make children the height of the container (ideal for columns)
See it in action:
http://codepen.io/enxaneta/full/adLPwv/
In my opinion:
These could have been named:
flex-x:
alignment/spacing on the main axis
flex-y:
alignment on the cross axis
But alas, with HTML, we can never have nice things. Never.