Search code examples
htmlcssflexboxcentering

Centering elements vertically & horizontally while aligning text horizontally


Our site needs some color swatches for our products and the boss wants them to look exactly as they do in the print catalog. This means a horizontal row of squares, each a different color, and with the name of that color overlaid in its absolute center. Like so:

Catalog's row of swatches

I've tried two different methods for making the swatches on our web site follow this established convention, but it's just not happening for some reason. And, yes, I am still a bit of a newbie, it would seem.

Here's my first attempt, using a display:table/display:table-cell method:

JSFiddle

<p>Standard Ink Colors</p>
<ul class="color-list">
  <li id="thumb-red">
    <p>Red</p>
  </li>
  <li id="thumb-orange">
    <p>Orange</p>
  </li>
  <li id="thumb-athleticgold">
    <p>Athletic Gold</p>
  </li>
</ul>
<p>Be sure to specify Standard ink color above or provide us with your PMS ink number. </p>

enter image description here

Everything lines up along the last baseline of text.

So I tried using Flexbox:

JSFiddle

<p>Standard Ink Colors</p>
<ul class="color-list">
  <li id="thumb-red">Red</li>
  <li id="thumb-orange">Orange</li>
  <li id="thumb-athleticgold">Athletic Gold</li>
</ul>
<p>Be sure to specify Standard ink color above or provide us with your PMS ink number. </p>

enter image description here

Similar problem, only now things line up on the first baseline.

Is there any fix for this?


Solution

  • Make the parent of the individual items a flex container. This will activate several default settings:

    • flex-direction: row - each child element ("flex item") is forced into a single row
    • flex-wrap: nowrap - items will not be able to wrap

    Then make each flex item of the main container double as a (nested) flex container. This will allow you to control the alignment of the child elements (text, in this case).

    With justify-content, align-items and text-align all set to center, the text will always be vertically and horizontally centered.

    .color-list {
       display: flex;
       justify-content: center;
       padding: 0;
    }
    .color-list li {
       display: flex;
       justify-content: center;
       align-items: center;     
       text-align: center;
       width: 4em;
       height: 4em;
    }
    #thumb-red          { background-color: #CE1126; }
    #thumb-orange       { background-color: #FE5000; }
    #thumb-athleticgold { background-color: #FFB81C; }
    <ul class="color-list">
      <li id="thumb-red">Red</li>
      <li id="thumb-orange">Orange</li>
      <li id="thumb-athleticgold">Athletic Gold</li>
    </ul>

    Regarding the misalignment in your original code...

    In a general sense, there's no reason to use display: inline-flex on each item. If, however, this is a requirement you have, then simply add vertical-align: middle or top to each li. Here's the explanation: Why is there a vertical scroll bar if parent and child have the same height?

    Browser support:

    Flexbox is supported by all major browsers, except IE < 10. Some recent browser versions, such as Safari 8 and IE10, require vendor prefixes. For a quick way to add prefixes use Autoprefixer. More details in this answer.