Josh Bowe
Josh Bowe

Reputation: 413

Vertically centering text within an inline-block

I'm trying to create some buttons for a website using styled hyperlinks. I have managed to get the button looking how I want, bar one slight issue. I can't get the text ('Link' in the source code below) to vertically center.

Unfortunately there may be more than one line of text as demonstrated with the second button so I can't use line-height to vertically center it.

My initial solution was to use display: table-cell; rather than inline-block, and that sorts the issue in Chrome, Firefox and Safari but not in Internet Explorer so I'm thinking I need to stick to inline-block.

How would I go about vertically centering the link text within the 57px x 100px inline-block, and have it cater to multiple lines of text? Thanks in advance.

.button {
    background-image:url(/images/categorybutton-off.gif);
    color:#000;
    display:inline-block;
    height:57px;
    width:100px;
    font-family:Verdana, Geneva, sans-serif;
    font-size:10px;
    font-weight:bold;
    text-align:center;
    text-decoration:none;
    vertical-align:middle;
}
.button:hover {
    background-image:url(/images/categorybutton-on.gif);
}
.button:before {
    content:"Click Here For\A";
    font-style:italic;
    font-weight:normal !important;
    white-space:pre;
}

     
<a href="/" class="button">Link</a>
<a href="/" class="button">Link<br />More Details</a>

Upvotes: 41

Views: 49808

Answers (4)

Jason C
Jason C

Reputation: 40315

You do not need to create any wrapper elements or anything for this... just use inline flex (or grid, but I'll describe flex) and center stuff, like this (it's just the same as doing it with non-inline flex, but with an added vertical-align to set a sane baseline for the element):

    .button { 
      display: inline-flex; 
      flex-direction: column;
      justify-content: center;
      text-align: center;
      vertical-align: middle;
    }
    <a href="/" class="button">Link</a>
    <a href="/" class="button">Link<br />More Details</a>

This will also work for dynamic height content.


Going through each of those; so first there's the obvious one:

display: inline-flex;

Next, since ::before is being used, there are two child items (the ::before and the text). Since I guess we want them vertically stacked, we'll need to set the direction (because default is "row"):

flex-direction: column;     /* PS: this defines the "main" axis */

Then, since we want the elements packed and centered along the vertical aka column aka main axis (if you use the "row" flex direction, you'd use align-content here instead):

justify-content: center;

And since we want to center the text, with each line individually centered (remember that each item defaults to filling the cross aka horizontal axis, so they're already full width):

text-align: center;

Technically this is enough, except since this is an inline element the baselines will be all over the place (based on content), so we can set them to something consistent and reasonable:

vertical-align: middle;   /* align *this* element in the *parent*! */

And that's it; just applied directly to the element. No inner divs or wrappers or anything needed.

If you've only got one child element (e.g. no ::before or whatever) then it doesn't really matter what the flex direction is, so you can shorten the CSS a bit by using the defaults:

/* if there's just one child, or you want to */
/* arrange children horizontally: */
.button {
    display: flex;
    align-content: center;
    text-align: center;
    vertical-align: middle;
}

You can also drop vertical-align if the element's container is positioning it acceptably and you don't need to tweak the baseline.


By the way, the same can be done with an inline grid layout if you prefer -- a single-row/column grid has a lot of functional overlap with flex:

/* using grid instead: */
.button { 
  display: inline-grid;
  grid: max-content / auto; 
  align-content: center;
  text-align: center;
  vertical-align: middle;
}

/* this is the important bit: */
/* ------------------------------------------------------*/

.button { 
  display: inline-flex; 
  flex-direction: column;
  justify-content: center;
  text-align: center;
  vertical-align: middle;
}

/* ------------------------------------------------------*/




/* other styling from OP; not relevant to the centering. */
/* important props removed & displayed above instead.    */    

.button {
    background-image:url(/images/categorybutton-off.gif);
    color:#000;
    /*display:inline-block;*/
    height:57px;
    width:100px;
    font-family:Verdana, Geneva, sans-serif;
    font-size:10px;
    font-weight:bold;
    /*text-align:center;*/
    text-decoration:none;
    /*vertical-align:middle;*/
}
.button:hover {
    background-image:url(/images/categorybutton-on.gif);
}
.button:before {
    content:"Click Here For\A";
    font-style:italic;
    font-weight:normal !important;
    white-space:pre;
}
/* placeholders for missing images: */
.button { background-color: #AAA; }
.button:hover { background-color: #DDD; }
this <a href="/" class="button">Link</a> is
<a href="/" class="button">Link<br />More Details</a> text

<br/><br/>
<a href="/" class="button" style="width:unset;height:unset;padding:1em;">......... fixed sizes ........</a>
<a href="/" class="button" style="width:unset;height:unset;padding:1em;">are<br/><br/><br/>not<br/><br/><br/>required</a>

Upvotes: 7

Vivek Gani
Vivek Gani

Reputation: 1313

Riffing off the other answers, in case anyone's designing a button and seeking this page one can combine:

  • the button design with display:inline-flex
  • a button-content div nested within with display:inline-block
  • a button-text span to define things like text-decoration overrides (necessary for buttons not to have underlined text in pages where parent elements define it - notably on chrome & safari)

demo example

Upvotes: 0

avrahamcool
avrahamcool

Reputation: 14094

Wrap your text with a span (Centered), and write another empty span just before it(Centerer) like this.

HTML:

<a href="..." class="button">
  <span class="Centerer"></span>
  <span class='Centered'>Link</span>
</a>

CSS

.Centered
{
    vertical-align: middle;
    display: inline-block;
}

.Centerer
{
    display: inline-block;
    height: 100%;
    vertical-align: middle;
}

Take a look here: http://jsfiddle.net/xVnQ6/

Upvotes: 26

Rafal Gałka
Rafal Gałka

Reputation: 1030

Many thanks @avrahamcool, works like a charm!

I have a little upgrade. You can replace redundant .Centerer span with css

.button:before {
  content: '';
  display: inline-block;
  vertical-align: middle;
  height: 100%;
}

See demo here: http://jsfiddle.net/modernweb/bXD2V/

NOTE: This will not work with text in "content" attribute.

Upvotes: 38

Related Questions