107

Consider the following code:

HTML:

<div>
    <label for='name'>Name:</label>
    <input type='text' id='name' />
</div>

CSS:

div {
    height: 50px;
    border: 1px solid blue;
}

What would be the easiest method to put the label and the input in the middle of the div (vertically) ?

Marc-François
  • 3,900
  • 3
  • 28
  • 47
Misha Moroshko
  • 166,356
  • 226
  • 505
  • 746
  • 1
    To my knowledge, the bottom line is "you can't", and the laziest way around it is to use a simple `` and apply `valign='middle'` to its `
    ` s.
    – BeemerGuy Dec 17 '10 at 00:07

7 Answers7

108

div {
    display: table-cell;
    vertical-align: middle;
    height: 50px;
    border: 1px solid red;
}
<div>
    <label for='name'>Name:</label>
    <input type='text' id='name' />
</div>

The advantages of this method is that you can change the height of the div, change the height of the text field and change the font size and everything will always stay in the middle.

http://jsfiddle.net/53ALd/6/

Basj
  • 41,386
  • 99
  • 383
  • 673
Marc-François
  • 3,900
  • 3
  • 28
  • 47
  • 1
    looks elegant :) does anyone know how browser compatible this method is? – Zaven Nahapetyan Dec 17 '10 at 00:25
  • 1
    For IE, I think it only works on IE8 or better. For the other web browsers it's fine. – Marc-François Dec 17 '10 at 00:34
  • 1
    I didn't know about the `display: table-cell`. Is that supported on certain browsers? – BeemerGuy Dec 17 '10 at 00:41
  • Unfortunately, this method does not work if the `input` / `label` absolutely positioned: http://jsfiddle.net/53ALd/7/ Any ideas how to handle this ? – Misha Moroshko Dec 17 '10 at 00:57
  • 7
    @Misha you should have specified the fact that your input / label were absolutely positioned. That totally changes the circumstances of the question. I am giving Marc a +1. Great answer. – jessegavin Dec 17 '10 at 01:16
  • 2
    I'm fairly certain the point jenson was trying to make (and should have articulated) is that using `display: table-cell` makes divs behave in ways they aren't expected to behave in, such as subsequent divs rendering on the same line/etc. – taswyn Nov 01 '13 at 20:36
  • Note that this solution will not work if you have set your label to `float:left` because `label` becomes a `block` element with that attribute. – Askable Sep 13 '16 at 19:42
  • Use Flexbox instead – Vincent Wasteels Oct 13 '16 at 07:01
  • i have a problem with this solution: I'm already in a `div` which is `display:inline-block` (which I can't change) and creating another `div` inside it which is `display:table-cell` appears to do nothing to provide vertical alignment. – Michael May 03 '17 at 17:46
  • the problem is not with the solution, it is with the markup you are stuck with. i know that doesn't help, so to clarify, i am not being snarky here. that solution as is works fine. your constraints wouldn't lead to this desired solution, etc. – albert May 21 '17 at 20:38
  • this would not work with float property on Div, it's better to user line height in that case. – Sheelpriy Nov 17 '17 at 10:16
  • This doesn't work when you have two or more divs following each other. They will be placed horizontally rather than vertically. – neoxic Aug 30 '23 at 06:50
90

A more modern approach would be to use CSS flexbox:

div {
  height: 50px;
  background: grey;
  display: flex;
  align-items: center
}
<div>
  <label for='name'>Name:</label>
  <input type='text' id='name' />
</div>

A more complex example: If you have multiple elements in the flex flow, you can use align-self to align single elements differently to the specified align.

div {
  display: flex;
  align-items: center
}

* {
  margin: 10px
}

label {
  align-self: flex-start
}
<div>
  <img src="https://de.gravatar.com/userimage/95932142/195b7f5651ad2d4662c3c0e0dccd003b.png?size=50" />
  <label>Text</label>
  <input placeholder="Text" type="text" />
</div>

It's also super easy to center horizontally and vertically:

div {
  position:absolute;
  top:0;left:0;right:0;bottom:0;
  background: grey;
  display: flex;
  align-items: center;
  justify-content:center
}
<div>
  <label for='name'>Name:</label>
  <input type='text' id='name' />
</div>
Matthias Braun
  • 32,039
  • 22
  • 142
  • 171
Holger Will
  • 7,228
  • 1
  • 31
  • 39
15

This works cross-browser, provides more accessibility and comes with less markup. ditch the div. Wrap the label

label{
     display: block; 
     height: 35px; 
     line-height: 35px; 
     border: 1px solid #000; 
}

input{margin-top:15px; height:20px}

<label for="name">Name: <input type="text" id="name" /></label>
vascowhite
  • 18,120
  • 9
  • 61
  • 77
albert
  • 8,112
  • 3
  • 47
  • 63
  • 3
    This obviously won't work for a two line label. And if you are sure that label is always single line, than there are millions of other alternatives. – Lashae Apr 18 '13 at 07:33
  • 18
    the question was in regards to a single line label, and i answered accordingly. not sure about your point(s) or intentions here, but if x is so obvious you should go make a million examples of it. at the very least so you can gloat under my answer and feel the power of your million victories. bravo. – albert Apr 18 '13 at 08:23
  • 2
    This is the best answer for single line labels. The specification says: "If the for attribute is not specified, but the label element has a labelable form-associated element descendant, then the first such descendant in tree order is the label element's labeled control." Therefore this is the only approach where you can omit the `for` and `id` attributes for maximum simplicity. – parliament Apr 09 '16 at 01:28
8

I'm aware this question was asked over two years ago, but for any recent viewers, here's an alternative solution, which has a few advantages over Marc-François's solution:

div {
    height: 50px;
    border: 1px solid blue;
    line-height: 50px;
}

Here we simply only add a line-height equal to that of the height of the div. The advantage being you can now change the display property of the div as you see fit, to inline-block for instance, and it's contents will remain vertically centered. The accepted solution requires you treat the div as a table cell. This should work perfectly, cross-browser.

The only other advantage being it's just one more CSS rule instead of two :)

Cheers!

MusikAnimal
  • 2,286
  • 2
  • 22
  • 28
7

Use padding on the div (top and bottom) and vertical-align:middle on the label and input.

example at http://jsfiddle.net/VLFeV/1/

Gabriele Petrioli
  • 191,379
  • 34
  • 261
  • 317
  • That doesn't work on the jsfiddle. I changed the height of the `div` and the content inside didn't move at all. Am I missing something? – BeemerGuy Dec 17 '10 at 00:39
  • In my opinion, layouts shouldn't have fixed pixel heights… Layouts should flow fluidly around the content. However, I come from a day and time when browsers scaled text sizes when zooming in and out. Recent browsers actually scale the whole page, so setting pixel heights works a little better. However, there are whole new reasons to avoid setting pixel heights… for example, responsive layout techniques. That's why this would be my preferred method. – thirdender Jun 26 '12 at 17:55
3

Wrap the label and input in another div with a defined height. This may not work in IE versions lower than 8.

position:absolute; 
top:0; bottom:0; left:0; right:0;
margin:auto;
Trevor
  • 11,269
  • 2
  • 33
  • 40
0

You can use display: table-cell property as in the following code:

div {
     height: 100%;
     display: table-cell; 
     vertical-align: middle;
    }
Luca Detomi
  • 5,564
  • 7
  • 52
  • 77
abahet
  • 10,355
  • 4
  • 32
  • 23