I have been wrestling with a particular frustrating aspect of styling HTML, and that is
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>
vertical-align property, when used in this context, aligns the contents of the
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
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
inputbox 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.
input to a value calculated as: half the height of the container element MINUS half the height of the
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.
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
display:table-cellfor Opera and Firefox, and use
<input style="line-height:100px"...in IE
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