Contents
0 - About the vertical-align:middle property
1 - What happens if I just set the input height?
2 - What if I set the line-height to the height of the input?
3 - What if I set the top padding?
5 - A Table Cell - vertical-align:middle
6 - display:table-cell / vertical-aign:middle;
Introduction
I have been wrestling with a particular frustrating aspect of styling HTML, and that is vertical alignment
.
For some reason, I wanted to set the height on an <input type="text">
and have the text aligned in the middle (between top and bottom).
I have been playing with Opera 9.5, Firefox 2, and IE 7.
The following sets out my explorations so far.
If you have any other bright ideas, or I have made any glaring errors here, please let me know.
0 - About the vertical-align:middle property
At the outset it is important to understand that this, and its limits. It is quite complex, and the following is an incomplete attempt to summarise:-
(a) If used on td
elements and elements set to display:table-cell
, it aligns the contents of the element relative to the element's box.
(b) If used on inline
elements it aligns the contents of the element relative to the line of text of which that inline element forms part, but only if the element is an img
or has display:inline-block
set. To quote the spec: "This property affects the vertical positioning inside a line box of the boxes generated by an inline-level element."
In fact, browsers very wildly in how they implement (b) - try the following on each:-
<div style="height: 100px; width:200px; border:1px solid gray;">Normal Text
<span style="vertical-align:text-bottom; display:inline-block;">Aligned Text</span>
</div>
(c) In any other case, it has no effect.
1 - What happens if I just set the input height?
- Opera - YES - Middle by default
- Firefox - NO - Top by default
- IE - NO - Top by default
<input style="height:100px" value="Some text">
2 - What if I set the line-height to the height of the input?
- Opera - YES
- Firefox - NO - Stubborn as a mule
- IE - YES
<input style="height:100px; line-height:100px;" value="Some text">
3 - What if I set the top padding?
This will work, if I know in advance the pixel height of my input's font.
I then set the top padding as 50 - (pixel height / 2)
I have come accross this conversion table (Reed Design), but something tells me that this could get messy.
Points Pixels Ems Percent
6pt 8px 0.5em 50%
7pt 9px 0.55em 55%
7.5pt 10px 0.625em 62.5%
8pt 11px 0.7em 70%
9pt 12px 0.75em 75%
10pt 13px 0.8em 80%
10.5pt 14px 0.875em 87.5%
11pt 15px 0.95em 95%
12pt 16px 1em 100%
13pt 17px 1.05em 105%
13.5pt 18px 1.125em 112.5%
14pt 19px 1.2em 120%
14.5pt 20px 1.25em 125%
15pt 21px 1.3em 130%
16pt 22px 1.4em 140%
17pt 23px 1.45em 145%
18pt 24px 1.5em 150%
20pt 26px 1.6em 160%
22pt 29px 1.8em 180%
24pt 32px 2em 200%
26pt 35px 2.2em 220%
27pt 36px 2.25em 225%
28pt 37px 2.3em 230%
29pt 38px 2.35em 235%
30pt 40px 2.45em 245%
32pt 42px 2.55em 255%
34pt 45px 2.75em 275%
36pt 48px 3em 300%
Also similar here
Although this has been said of this chart: "That chart is total bunk. There is no relationship between px and pt." Source.
4 - Regroup
OK I thought, it was not going to be possible to do it for all browsers, within the input.
What if I simulated the desired result, by leaving the height of the input to itself, and looking at aligning the input within a 100px high container.
5 - A Table Cell - vertical-align:middle
- Opera - YES
- Firefox - YES
- IE - YES
<table style="table-layout:fixed; border:0;" cellspacing=0 cellpadding=0>
<tr><td style="height: 100px; width:200px; border:1px solid gray; vertical-align:middle;" onclick="alert(this.offsetHeight + ' ' + this.offsetWidth);">
<input style="border-width:0px;" value="Some text">
<tr><td>
</table>
The vertical-align
property, when used in this context, aligns the contents of the td
.
Yes, this would be the best solution; but I thought I would plough on to see if CSS had any other alternatives to this.
6 - display:table-cell / vertical-aign:middle;
- Opera - YES - Unless position is absolute
- Firefox - YES - Unless position is absolute
- IE - NO - Not supported
<div style="height: 100px; width:200px; border:1px solid gray; display:table-cell; vertical-align:middle;" onclick="alert(this.offsetHeight + ' ' + this.offsetWidth);">
<input style="border-width:0px;" value="Some text">
</div>
This makes the div
behave like a table cell, though I would say that it can throw up some unexpected problems in practice when you are reading height,width,borderWidth and other properties.
Note that you cannot use the vertical-align
property to align the contents of a block-level
element unless that element is a td
or is set to display:table-cell
.
7 - line-height on container element
I then tried simply setting the line-height on the container element to the container element's height.
- Opera - NO
- Firefox - NO
- IE - NO
<div style="height: 100px; width:200px; border:1px solid gray; line-height:100px;">
<input style="border-width:0px; " value="Some text">
</div>
However, if I introduced some actual text, it worked, almost:-
- Opera - YES
- Firefox - YES
- IE - NOT REALLY - The text alone will align to the middle, but when you introduce the
input
box you get very unpredictable behaviour, it either doesn't work, or it vanishes, or aligns to the bottom, or something else entirely.
<div style="height: 100px; width:200px; border:1px solid gray; line-height:100px;">
My Input: <input style="border-width:0px; display:inline " value="Some text">
</div>
This is presumably because the text establishes a line (a strut) against which the input can be positioned.
However, if you try to hide the My input
text in any way (e.g. wrap it in a zero width span
or hide it off screen with a negative margin) Opera and Firefox start to fail in different ways, again presumably related to a failure to establish a line.
So all in all, this was not feasible.
8 - Hard core JavaScript
The last resort was to use JavaScript, which involved either setting padding on a container element or positioning the top of input
to a value calculated as: half the height of the container element MINUS half the height of the input
.
This is only useful if you give the input
a fixed height font. If you use em
then problems will arise if the user changes the font size, because the input
will get bigger, and so its position will need to be re-calculated.
Conclusion
There is no intrinsic property of an input
element that allows you to do align its content to the middle of its height, and the HTML specification does not (I think) have anything to say on the matter.
Line-height might have done it, but Firefox lets us down this time.
The alternative is to mimic the desired look, by aligning the input in the middle of a container element that has the desired hight. Unfortunately, there is is no cross-browser way to achieve this through HTML and CSS, other than using a table.
Accordingly, in the end, it was either:-
- Succumb to tables and align the
input
within atd
element withvertical-align:middle
. - Use
display:table-cell
for Opera and Firefox, and use<input style="line-height:100px"...
in IE - Throw JavaScript at the problem in a big way.
Indeed it was surprising how poorly browsers handle vertical alignment outside a table. Every time I thought I had found a solution, one of the browsers would play up; and don't even get me started on the odd extra margins that IE inserts for its implementation of the input
control.
Sorry, comments have been suspended. Too much offensive comment spam is causing the site to be blocked by firewalls (which ironically therefore defeats the point of posting spam in the first place!). I don't get that many comments anyway, so I am going to look at a better way of managing the comment spam before reinstating the comments.