csscross-browser

Text input shifts text down 1px


A div and an input type="text" with identical CSS styling position their contents differently. The input has the text 1px lower on Firefox, Chrome and Safari (on macOS at least).

Try clicking toggle in the snippet below for an example. Notice that the elements are positioned the same, just the text within shifts by 1px.

As it's consistently offset across browsers, I'm wondering if there's something I'm missing. How can I reliably avoid this 1px shift?

const button = document.getElementById('toggle');

const a = document.getElementById('a');
const b = document.getElementById('b');

let state = false;
toggle();

button.onclick = toggle;

function toggle() {
  a.style.display = state ? 'none' : '';
  b.style.display = state ? '' : 'none';
  state = !state;
}
body {
  font: 13px Arial, sans-serif;
}

input,
div {
  position: absolute;
  outline: 0;
  border: 0;
  padding: 0;
  margin: 0;
  appearance: none;
  vertical-align: baseline;
  width: 200px;
  height: 22px;
  font: inherit;
  line-height: 21px;
  display: block;
  background-color: #eee;
}
<button id="toggle">toggle</button>

<input type="text" value="abcdefghijklmnopqrstuvwxyz" id="a" />
<div id="b">abcdefghijklmnopqrstuvwxyz</div>

And on JsFiddle here.


Solution

  • The vertical centering in the input is less effected by the line-height (the text is vertically centered). However, the height: 22px and the line-height: 21px cause the text to be centered differently in the div. Change the line height to 22px.

    Note: I've added a red right border to the div to show that the items are still toggled.

    const button = document.getElementById('toggle');
    
    const a = document.getElementById('a');
    const b = document.getElementById('b');
    
    let state = false;
    toggle();
    
    button.onclick = toggle;
    
    function toggle() {
      a.style.display = state ? 'none' : '';
      b.style.display = state ? '' : 'none';
      state = !state;
    }
    body {
      font: 13px Arial, sans-serif;
    }
    
    input,
    div {
      position: absolute;
      outline: 0;
      border: 0;
      padding: 0;
      margin: 0;
      appearance: none;
      width: 200px;
      height: 22px;
      font: inherit;
      line-height: 22px;
      display: block;
      background-color: #eee;
    }
    
    div {
      border-right: 3px solid red;
    }
    <button id="toggle">toggle</button>
    
    <input type="text" value="abcdefghijklmnopqrstuvwxyz" id="a" />
    <div id="b">abcdefghijklmnopqrstuvwxyz</div>