37

I'm trying to style a text input with a value, text input with a placeholder, and a span, identically in Chrome. Specifically, I would like to control the line-height independently of the font size.

However, there seems to be some sort of minimum line-height (or something causing a similar affect) on the input value, that seems to push the text down somehow that prevents the identical styling.

Example HTML:

<div>
  <input type="text" value="Text">
  <input type="text" placeholder="Text">
  <span>Text</span>
</div>

CSS:

div {
  line-height: 50px;
  font-family: Arial;
}

input,
span {
  font-size: 50px;
  line-height: 50px;
  height: 50px;
  width: 100px;
  padding: 0;
  min-height: 0;
  display: inline-block;
  font-family: inherit;
  border: 2px solid red;
  overflow: hidden;
  vertical-align: top;
}

And the results can be seen at

http://plnkr.co/edit/oHbhKDSPTha8ShWVOC7N?p=preview and in the following screen shot from Chrome 44.0.2403.155 (64-bit) on Linux:

Text input with value, text input with placeholder, and span

Strangely, the placeholder seems to be styled with the desired line-height, while the text value of the input is positioned differently. I'm not concerned with the colour of the placeholder at this point.

How can I style all 3 elements so the text is in the same position, where I'm using a custom line-height?

I understand I can just set the line-height to normal or 1.2, or reduce the font size, to make the elements appear identically, but they would not have the visual appearance I'm looking for.

Michal Charemza
  • 25,940
  • 14
  • 98
  • 165
  • 1
    The issue seems to stem from the `line-height` somehow – try `line-height:56px`, and it is gone, whereas a `line-height:26px` for example significantly increases it … might be that interferes with other properties – i tried to look through all the `-webkit-*` values in “computed” tab, but so far I wasn’t able to spot any significant differences. – CBroe Oct 17 '15 at 10:33
  • 1
    One additional thing I notice with your original plunkr example – when you click into the first text field, so that the caret cursor appears between the letters, and then move the caret f.e. via the left/right keys, _then_ the text moves up by a little bit – can you confirm that? – CBroe Oct 17 '15 at 10:36
  • 1
    @CBroe Yes, it then moves up a pixel or two – Michal Charemza Oct 17 '15 at 10:37
  • 1
    If you increase the `line-height` significantly, say to `66px` – then that effect (when moving the caret) becomes even stronger. Looks like some kind of “auto-centering” might be performed …? – CBroe Oct 17 '15 at 10:38
  • 1
    Do you specially need to set the line-height?? Why can't you just leave out the line-height and replace them with padding? @MichalCharemza With the padding you creating the same effect for every object: [Plunker](http://plnkr.co/edit/JeCYWGdc5Y94QQoW1XpZ?p=preview) – Rotan075 Oct 20 '15 at 11:57
  • 1
    @Rotan075 If I want the input to be bigger than the default, yes, adding padding (or increasing the line height) is an option. However, I want the input to be smaller than the default line height makes it. Adding padding I'm pretty sure won't make it smaller! – Michal Charemza Oct 20 '15 at 12:02

8 Answers8

24

I think I've done it!!!

In my testing it seems that line-height must be at least ~115% of font-size, so if you want 50px high element you must have ~43px for things to all line up:

Fig 1. Font-size 86% of 50px line-height.

Fig 1. Font-size 86% of 50px line-height. Things line up but are not honouring the 50px font size requested by OP.

input, span {
    border: 2px solid red;
    display: inline-block;
    font: 43px Arial;
    line-height: 50px;
    padding: 0;
    vertical-align: middle;
 width: 100px;
    outline-style:none;
    box-shadow:none;
    overflow:hidden;
    /* optional - to include the borders in the element size: 
    box-sizing:border-box;
    */
}
<input type="text" value="Text">
<input type="text" placeholder="Text">
<span>Text</span>

If you increase the font size to the desired 50px then the minimum line-height respected by the input box is ~58px. Any attempt to offset this with vertical alignment had no affect in the input but we can fix the element height and hide the overflow to give a consistent (albeit not entirely respectable) appearance:

Fig 2. 50px text forcing a line height

Fig 2. 50px text forcing a line height of 58px which is clipped with overflow hidden.

input, span {
    border: 2px solid red;
    display: inline-block;
    font: 50px Arial;
    line-height: 58px;
    padding: 0;  
    height:50px;
    vertical-align: top;
    width: 100px;
    outline-style:none;
    box-shadow:none;
    overflow:hidden;
    /* optional - to include the borders in the element size: 
    box-sizing:border-box;
    */
}
<input type="text" value="Text">
<input type="text" placeholder="Text">
<span>Text</span>

Close, but no cigar. But that got me thinking - perhaps a pseudo element might be less restrictive? I found that that you can style the input::first-line pseudo even within an input and that this will respect the height, font size, line-height and vertical alignment!

Thus voilà!

First-line pseudo element

Fig 3. First-line pseudo element for the win!

input, span {
    border: 2px solid red;
    display: inline-block;
    font: 50px Arial;
    line-height: 50px;
    height: 50px;
    padding: 0;
    vertical-align: middle;
    width: 100px;
    outline-style:none;
    box-shadow:none;
    overflow:hidden;
    /* optional - to include the borders in the element size: 
    box-sizing:border-box;
    */
}
input::first-line, span::first-line {
    vertical-align: middle;
}
/* weirdly the placeholder goes black so we have to recolour the first-line */
input::-webkit-input-placeholder::first-line {
    color:grey;
}
<input type="text" value="Text">
<input type="text" placeholder="Text">
<span>Text</span>

Here's a jsFiddle of the lot so you can see my working out. ;)

https://jsfiddle.net/romz58cc/4/

Moob
  • 14,420
  • 1
  • 34
  • 47
  • 1
    Latest answer looks good... To tidy it up a bit, is it ok if you remove the previous ones? Of course, feel free to post them as separate answers if you feel as though they would be helpful to others. – Michal Charemza Oct 20 '15 at 17:54
  • 1
    @MichalCharemza thanks. I've tidied my answer up as suggested. – Moob Oct 20 '15 at 20:44
  • 1
    All looks good, thanks. I have noticed that this works as long as the line-height it as least the font-size. If the line height is smaller, the text value in the input seems to be cropped and in a different position compared to the placeholder and span cases https://jsfiddle.net/romz58cc/6/ . (I have to admit, I have no use-case for a line-height in an input that is smaller than the font-size, so that is just a curiosity really) – Michal Charemza Oct 21 '15 at 07:48
  • Given that the height of the caret cannot be controlled vertically aligning the text itself is a great idea! You've got my vote. – Hidden Hobbes Oct 26 '15 at 10:00
  • While I'm testing/running code snippet, I noticed that the placeholder of the textbox is at the top after typing a text then deleting it. But if you click to anything out of it(or you did not focus on it), it goes back to its current position. Why is that? – newbieguy Oct 26 '15 at 10:17
  • 1
    "Fig 3. First-line pseudo element for the win!" How very fitting that a bug that's unique to Chrome is fixed by exploiting something else that's also unique to Chrome. This is right up there with [float: left; display: inline for IE6](http://www.positioniseverything.net/explorer/doubled-margin.html). – BoltClock Mar 15 '17 at 02:18
8

Why is this happening?

This misalignment is being caused by the caret and as such I don't think you will find a way to align the text if the font-size and line-height are the same.

Why is the caret at fault?

The caret has a height greater than the text which is causing the alignment to be skewed.

There are a few things which support this:

1. You can see the size of the caret

  • Click into the input and hold the left mouse button. Drag up and down and you will see that the text will move
  • Remove height: 50px; from input, span. The size of the input will now increase to the height of the caret

div {
  line-height: 50px;
  font-family: Arial;
}
input, span {
  font-size: 45px;
  line-height: 50px;
  width: 100px;
  padding: 0;
  min-height: 0;
  display: inline-block;
  font-family: inherit;
  border: 2px solid red;
  overflow: hidden;
  vertical-align: top;
}
<div>
  <input type="text" value="Text">
  <input type="text" placeholder="Text">
  <span>Text</span>
</div>

2. The placeholder text is correctly aligned

  • The placeholder text is not effected by the caret so is correctly aligned
  • As soon as text is added to the input the alignment is thrown off

The result of the caret having a greater height is that the line-height is being artificially increased causing the text to be out of line.

This can be proven by:

  • Changing line-height to 58px. The alignment of the placeholder text and span will be the same as the input

div {
  line-height: 50px;
  font-family: Arial;
}
input, span {
  font-size: 50px;
  line-height: 58px;
  height: 50px;
  width: 100px;
  padding: 0;
  min-height: 0;
  display: inline-block;
  font-family: inherit;
  border: 2px solid red;
  overflow: hidden;
  vertical-align: top;
}
<div>
  <input type="text" value="Text">
  <input type="text" placeholder="Text">
  <span>Text</span>
</div>
  • Changing font-size to 45px. The caret will now fit in the 50px height

div {
  line-height: 50px;
  font-family: Arial;
}
input, span {
  font-size: 45px;
  line-height: 50px;
  height: 50px;
  width: 100px;
  padding: 0;
  min-height: 0;
  display: inline-block;
  font-family: inherit;
  border: 2px solid red;
  overflow: hidden;
  vertical-align: top;
}
<div>
  <input type="text" value="Text">
  <input type="text" placeholder="Text">
  <span>Text</span>
</div>

What can be done?

As there is no way to style the caret itself (to make it smaller) the most efficient way of ensuring the text is aligned would be to use a font-size which is smaller than the line-height. This will in turn make the caret smaller and stop it from artificially increasing the line-height of the input.

div {
  line-height: 50px;
  font-family: Arial;
}
input, span {
  font-size: 45px;
  line-height: 50px;
  height: 50px;
  width: 100px;
  padding: 0;
  min-height: 0;
  display: inline-block;
  font-family: inherit;
  border: 2px solid red;
  overflow: hidden;
  vertical-align: top;
}
<div>
  <input type="text" value="Text">
  <input type="text" placeholder="Text">
  <span>Text</span>
</div>

Alternatively you could remove height and just specify a line-height equal to the height of the caret:

div {
  line-height: 50px;
  font-family: Arial;
}
input, span {
  font-size: 50px;
  line-height: 58px;
  width: 100px;
  padding: 0;
  min-height: 0;
  display: inline-block;
  font-family: inherit;
  border: 2px solid red;
  overflow: hidden;
  vertical-align: top;
}
<div>
  <input type="text" value="Text">
  <input type="text" placeholder="Text">
  <span>Text</span>
</div>
Hidden Hobbes
  • 13,893
  • 3
  • 38
  • 64
2

I've done a bit of experimenting with line-heights within input boxes and think I've come to some sort of conclusion.

It appears that if the size of the font in an input box equals or exceeds the line height, then the box changes size and its content (but not placeholder) changes also to fit. This is obvious if you remove the heights from your example.

  input, span {
    padding: 0;
    margin: 0;
    width: 100px;
    padding: 0;
    min-height: 0;
    display: inline-block;
    font-family: inherit;
    border: 2px solid red;
    vertical-align: middle;
  }

  input, input::-webkit-input-placeholder, span {
    line-height: 50px;
    font-size: 50px;
  }
  

<input type="text" value="Text">
<input type="text" placeholder="Text">
<span>Text</span>

If you set the font-size to smaller than the line height, you no longer see the weird line-height effect and all the text sits on the same line:

  input, span {
    padding: 0;
    margin: 0;
    width: 100px;
    padding: 0;
    min-height: 0;
    display: inline-block;
    font-family: inherit;
    border: 2px solid red;
    vertical-align: middle;
  }

  input, input::-webkit-input-placeholder, span {
    line-height: 50px;
    font-size: 45px;
  }
   
  

<input type="text" value="Text">
<input type="text" placeholder="Text">
<span>Text</span>

Here's a side-by-side example: http://codepen.io/Jivings/pen/OyOKOV

I hope this helps, and at least brings you closer to a solution in your own CSS!

Jivings
  • 22,834
  • 6
  • 60
  • 101
  • 2
    I see the same problem in both examples... :/ – Victor Oct 19 '15 at 16:18
  • 1
    @Victor Hm, I changed to different screen size and it doesn't work again. However, if I reduce the text size further then everything is okay again. Maybe I wasn't spot on with my diagnosis. It does appear that there is some weird vertical aligning in the text-box – Jivings Oct 19 '15 at 16:55
1

Try like this

As per the link:Firefox line-height issue with input fields

line-height on input won't change unless you change the font-size

so reduce the font-size:50px to 45px it will look fine.

Code Below

   div { 
line-height: 50px; 
font-family: Arial; 
} 

span,input[type="text"],input[placeholder]{ 
height: 50px; 
width: 100px; 
padding: 0; 
min-height: 0; 
display: inline-block; 
font-family: inherit; 
border: 2px solid red; 
overflow: hidden; 
vertical-align: top; 
font-size:45px; 

} 

::-webkit-input-placeholder { 
color:#000000; 

}
Community
  • 1
  • 1
soorapadman
  • 4,451
  • 7
  • 35
  • 47
  • 1
    That doesn't seem to fix the position of the text in the input element with a value http://plnkr.co/edit/lcbOZskQ2lAaj57JRtyx?p=preview . Note: I'm not asking about the colour of the placeholder. – Michal Charemza Oct 17 '15 at 10:21
  • 1
    This seems to try to style the span to match the input. I would like it the other way around: style the input to match the span. – Michal Charemza Oct 17 '15 at 11:16
  • 1
    ok i will also try other way so far i tried this only i got.if any other way i will update? – soorapadman Oct 17 '15 at 11:24
  • 1
    If you're asking for my permission to try to answer the question, you have it :-) – Michal Charemza Oct 17 '15 at 11:27
  • 1
    if you reduce the font-size it will look fine. can you change font-size: 50px; to font-size:40px? – soorapadman Oct 17 '15 at 11:39
  • 1
    Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/92573/discussion-between-soorapadman-and-michal-charemza). – soorapadman Oct 17 '15 at 11:40
1

Line height to 1.2 value (that's 120% of font size) works perfectly in chrome

http://plnkr.co/edit/rJmXLRrGFpi46Vv5THm5?p=preview

  div, input, span {
      line-height: 1.2;
  }

The only change that I make it's change the two line heights of 50 pixels to 1.2. It doesn't breaks the layout and the three elements are aligned fine.

So your original code works fine in firefox.

Marcos Pérez Gude
  • 21,869
  • 4
  • 38
  • 69
1

SO Question - 33185205

OP

DEMO

FORK

Explination: <input> is a replaced element so it's content does not get rendered by the user agent.

For details refer to: HTML5: Non-replaced vs. replaced element?

Solution:

See FORK or Snippet

html {
  height: 100vh;
  width: 100vw;
  font: 400 10px'Arial';
}
body {
  height: 100%;
  width: 100%;
  background-color: grey;
  color: #111;
}
#form {
  display: inline-table;
}
.box {
  display: table-row;
}
span,
input {
  font: inherit;
  font-size: 40px;
  /* */
  height: 50px;
  /* */
  line-height: 50px;
  /* */
  width: 100px;
  display: table-cell;
  outline: 2px solid red;
  border: 5px solid transparent;
  /* */
  padding: 0;
}
<!DOCTYPE html>
<html>

<head>
  <link rel="stylesheet" href="style.css">

</head>

<body>
  <form id="form">
    <div class="box">
      <input id="in1" type="text" placeholder="Text" value="Text">
      <input id="in2" type="text" placeholder="Text" value="">
      <span>Text</span>
    </div>
  </form>
</body>

</html>
  1. Set the height, and line-height of <input>s equally. (e.g. 50px)

  2. Set the font-size to a size less than height and line-height. (e.g. 40px)

  3. Set either top and bottom of padding or border to the difference of the previous values divided by 2. (e.g. ((50px - 40px) / 2) = 5px)

Community
  • 1
  • 1
zer00ne
  • 41,936
  • 6
  • 41
  • 68
  • 1
    @klaar Would you be so kind as to explain why? The Fork: http://plnkr.co/edit/fFm4nWajybHtLdMRQuFa?p=preview is the solution (snippet is a duplicate), not the Demo. – zer00ne Oct 20 '15 at 19:30
  • 1
    If font-size equals line-height, then weird things happen and either the input changes its height or the text inside the input gets pushed down. I'm seeing this in Fx 41 on Windows and in Android AOSP browser. – klaar Oct 20 '15 at 20:38
  • 1
    @klaar On step 2. *Set the `font-size` to a size **less** than `height` and `line-height`. * When do I suggest `font-size` should **equal** `line-height`? – zer00ne Oct 21 '15 at 11:17
  • 1
    Ah yes, but it was my understanding that OP requested font-size to be as large as line-height, not less. – klaar Oct 21 '15 at 11:29
  • 1
    @klaar The OP: *How can I style all 3 elements so the text is in the same position, where I'm using a custom line-height?* If the simple formula is followed, `line-height` can be anything OP desires. – zer00ne Oct 22 '15 at 03:13
1

Updated base on comments below

In order to use the same line-height for each of the elements I updated the CSS to this:

*,
*:before,
*:after {
  -moz-box-sizing: border-box;
  -webkit-box-sizing: border-box;
  box-sizing: border-box;
}

div {
  line-height: 50px;
  font-family: Arial;
}

input, span {
    border: 2px solid red;
    display: inline-block;
    font: 50px Arial;
    height: 60px;
    line-height: 60px;
    padding: 0;
    vertical-align: middle;
    width: 100px;
}
input {
    padding-top: 3px;
}

Basically you if use the same contain height and line-height the text will show correctly next to each other even if you change the font sizes. The font size must be at least 10px or so bigger than the height and line-height otherwise it will become skewed again.

You can see my updated JS.Fiddle here. Hope that helps.

crazymatt
  • 3,266
  • 1
  • 25
  • 41
  • 1
    I suspect that the reason it looks better in your example is that you don't have a custom line height on the input or the span. If you put that back, setting the line-height to the font-size, as in https://jsfiddle.net/q3g4n8ef/1/ , then the text positions are off. This is true even if keeping the `box-sizing` of `border-box`. – Michal Charemza Oct 19 '15 at 20:09
  • 1
    @MichalCharemza true. If you use a line-hight of 58px they will show correctly. The problem tho is if you want to use any other line height you will have to re-calculate all the properties to get them to show correctly. – crazymatt Oct 19 '15 at 21:02
1

Because diacritics are not part of the traditional definition of font size, you can't ever have line height = font size. Even ASCII includes some diacritics (for example U0060). Diacritics can be applied to capitalized letters too, you don't even need obscure unicode extensions, latin1 is sufficient (U00C0 for example).

When a font is correctly designed and includes the box drawing block this can be easily checked – box drawing lines are supposed to be jointive so U2502 for example will give you the actual exact maximum height used by the font. Its height will be more than A or one of the other latin caps usually used to define font size. (unfortunately because horizontal lines are also supposed to be jointive the box drawing block can only be found in monospace fonts).

After allocating font height the text stack still has to reserve some place where to put diacritics (there are metadata in font formats that define how much a particular font will consume in addition to font size for diacritics). Usually this place overlaps with line spacing. When there is a single line, it shows up as line height > font size

Computing the exact minimal line height for a font size requires deep knowledge of the font used (via a specific lib, something like opentype.js) and the characteristics of the text engine used to render each element. Depending on the advancement of this text engine it will use more (or less) of the tricks permitted by the opentype spec to minimize space wastage in complex international situations.

For example unless a text stack implements handling of the opentype base table opentype spec the actual added spacing can grow to huge values (more than the 15/20% typical of western latin and given in other answers) as soon as one uses a font with support for Vietnamese, or other scripts that like to stack many diacritics on top of one other (even if your browser manages to render this page with a generic font it will probably compress diacritics vertically compared to when a vietnamese font is installed)

Likewise the text stack knows whether the text you put on a page includes or not complex diacritics. But for an input element it has no such information, that depends on what the user will type. So it needs to be conservative and reserve the worst-case line height for the scripts supported by the font you chose.

Broken web site designs where vertical input height has been under-allocated are very common, because web site/js lib/browser authors live in a 96dpi no-diacritics latin world, and think minimizing vertical height is beautiful. That breaks as soon as the site is viewed in another language, with slightly more complex unicode glyphs, slightly different fonts, or slightly different text zoom levels (due to hidpi or just user near-sightness). Normal text is usually fine since the designer didn't try to force it inside an undersized fixed-pixel box.

It is also common for input field sizing to be broken, when it uses monospace fonts for one reason or another, and the web designer assumed some ratio between sans serif and monospace and tried to "fix" it (usually by enlarging monospace since some browsers ship with a small default monospace for obscure legacy reasons, even though it is not a general rule).

nim
  • 2,345
  • 14
  • 13