HTML input alignment

Viewed 177

Busy on a game involving buttons. Having 2 questions about problems I stumbled upon.

Code:

input {
  background-color: #e7e7e7;
  border: solid;
  border-width: 1px;
  text-align: center;
  height: 50px;
  width: 50px;
  padding: 0px;
  margin: 0px;
}
<html>
  <head>
  </head>
  <body>

    <input type="button"  value="foo">
    <input type="button"  value="">
    <input type="button"  value="">
      <br/>
    <input type="button"  value="">
    <input type="button"  value="">
    <input type="button"  value="">
      <br/>
    <input type="button"  value="">
    <input type="button"  value="">
    <input type="button"  value="">

  </body>
</html>

Questions:

  1. Why do the button misalign when I put in a value in the the button? Dev tools also says it still the same size (50px 50px) so why does it change position?

  2. How can I style the CSS to have zero distance bewteen the buttons (in other words: the borders of the buttons touch). I already tried to set padding/margin of html/body/input but none of these seems to work.

3 Answers

Why are the buttons with text being pushed down?

So there's a bit at play here. Text and inline elements vertically-align to the baseline by default. The baseline is a value determined by the line-height of the element, though an element without a line-height will determine a "reasonable" value[1] - in the case of an empty element, this will be 0. However when you add text, the element is then given a line-height and moved down by that amount.[2]

A simple solution is to force the inputs to render with the same alignment, text or not, by applying vertical-align: top.


Why is there space between the buttons?

Inline elements (and inline-block elements like your inputs) will naturally align side-by-side, however they behave similarly to text[3]. Much like if you were to put a line-break between two letters in your HTML, a line-break between inline elements will add a single space between them.

Hypothetically, if you were to put all of your inputs on one line (without spaces), it would solve your issue:

<input type="button" value="these" /><input type="button" value="are" /><input type="button" value="touching" />

<br><br>

<input type="button" value="these" />
<input type="button" value="are" />
<input type="button" value="not" />

Though I don't suggest that method - it's merely for demonstration purposes.


So what's the solution?

Well, you have some options. Choose the one that you think would work best for you.

Solution 1: Wrap the inputs in a container and apply font-size: 0 to it. The spaces will still be there, but the font-size: 0 ensures they aren't visible.

input {
  background-color: #e7e7e7;
  border: solid;
  border-width: 1px;
  text-align: center;
  height: 50px;
  width: 50px;
  padding: 0px;
  margin: 0px;
  vertical-align: top;
  font-size: 12px;
}

.container {
font-size: 0;
}
<div class="container">
  <input type="button" value="foo">
  <input type="button" value="">
  <input type="button" value="">
  <br/>
  <input type="button" value="">
  <input type="button" value="">
  <input type="button" value="">
  <br/>
  <input type="button" value="">
  <input type="button" value="">
  <input type="button" value="">
</div>

Solution 2: Bypass the triviality of inline elements and make use of display: block with float.

input {
  background-color: #e7e7e7;
  border: solid;
  border-width: 1px;
  text-align: center;
  height: 50px;
  width: 50px;
  padding: 0px;
  margin: 0px;
  font-size: 12px;
  float: left;
  display: block;
}

.row {display: block;}

.row::after {
  display: block;
  content: '';
  clear: both;
}
<div class="row">
  <input type="button" value="foo">
  <input type="button" value="">
  <input type="button" value="">
</div>
<div class="row">
  <input type="button" value="">
  <input type="button" value="">
  <input type="button" value="">
</div>
<div class="row">
  <input type="button" value="">
  <input type="button" value="">
  <input type="button" value="">
</div>

Solution 3: Use a more modern approach, like flexbox.

input {
  background-color: #e7e7e7;
  border: solid;
  border-width: 1px;
  text-align: center;
  height: 50px;
  width: 50px;
  padding: 0px;
  margin: 0px;
  vertical-align: top;
  font-size: 12px;
}

.container {
  display: flex;
  flex-wrap: wrap;
  width: 150px;
}
<div class="container">
  <input type="button" value="foo">
  <input type="button" value="">
  <input type="button" value="">
  <input type="button" value="">
  <input type="button" value="">
  <input type="button" value="">
  <input type="button" value="">
  <input type="button" value="">
  <input type="button" value="">
</div>


Sources

1: "normal: Tells user agents to set the computed value to a "reasonable" value"

2: "For inline non-replaced elements, the box used for alignment is the box whose height is the 'line-height'.

3: "Inline-level elements generate inline-level boxes, which are boxes that participate in an inline formatting context."

"Why do the button misalign when I put in a value in the the button?"

The default value for elements with text content vertical-align is a baseline, so you need to specify it (in my case I use vertical-align: middle).

"How can I style the CSS to have zero distance bewteen the buttons (in other words: the borders of the buttons touch)"

I followed a little hacky way and set a negative margin-left value to get buttons without space between them. I have selected specific items using input:nth-child(2n) and input:nth-child(4n - 1) selectors and gave margin-left: -4px; to them.

Here is my solution:

* {
  margin: 0;
  padding: 0;
}

input {
  background-color: #e7e7e7;
  border: solid;
  border-width: 1px;
  text-align: center;
  height:50px;
  width:50px;
  vertical-align: middle
}

input:nth-child(2n) {
  margin-left: -4px;
}

input:nth-child(4n - 1) {
  margin-left: -4px;
}
<html>
  <head>
  </head>
  <body>

  <input type="button"  value="foo">
  <input type="button"  value="">
  <input type="button"  value="">
    <br/>
  <input type="button"  value="">
  <input type="button"  value="">
  <input type="button"  value="">
    <br/>
  <input type="button"  value="">
  <input type="button"  value="">
  <input type="button"  value="">

  </body>
</html>

Feel free to ask, if anything isn't clear!

For question two, you can try the border-spacing method.

For example:

input {
    border-collapse: separate;
    border-spacing: 0px 0px;
}
Related