Andreas Gohr
Andreas Gohr

Reputation: 4935

Minimal CSS for form elements and links to have same height

A problem that seems to pop up again and again in my projects is styling form elements and links to have the same height.

Here's an simple example (fiddle):

HTML:

<select><option>one</option></select>
<input type="text">
<button>foo</button>
<a href="foo">test</a>

CSS:

select,
input,
button,
a {
  padding: 0.5rem;
  margin: 0.25rem;
  border: 1px solid red;
}

All elements receive the exact same styling with a padding, a margin and a border. But they all differ slightly in height and I don't really understand why.

Can someone

  1. explain where the difference comes from? Chrome inspector tells me that the actual inner element of each has different sizes - shouldn't it be the same?
  2. tell me what minimal changes I need to do to my CSS to achieve what I want without styling each of the elements slightly different? My goal is to pick the padding, margin and border sizes freely (using variables) and still have consistent heights.

Updated fiddle with solution

Upvotes: 5

Views: 493

Answers (3)

Stickers
Stickers

Reputation: 78686

The minimal version:

You'll need to add the additional rules like below:

select,
input,
button,
a {
  padding: 0.5rem;
  margin: 0.25rem;
  border: 1px solid red;
  display: inline-block; /*new*/
  font: inherit;         /*new*/
}

But that will still not guarantee they receive the same height for certain input types in certain browsers. You can also reset the appearance but I would not recommend to do it globally, unless it's required by design.

-webkit-appearance: none;
appearance: none;

The non-minimal version:

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

::-moz-focus-inner {
  border-style: none;
  padding: 0;
}

::-webkit-file-upload-button {
  font: inherit;
  -webkit-appearance: button;
}

::-webkit-inner-spin-button,
::-webkit-outer-spin-button {
  height: auto;
}

::-webkit-search-cancel-button,
::-webkit-search-decoration {
  -webkit-appearance: none;
}

button,
input,
optgroup,
select,
textarea {
  font-family: inherit;
  font-size: 1rem;
  line-height: 1.15;
  margin: 0;
}

button,
input {
  overflow: visible;
}

button,
select {
  text-transform: none;
}

[type="checkbox"],
[type="radio"] {
  padding: 0;
}

[type="search"] {
  outline-offset: -2px;
  -webkit-appearance: textfield;
}

[type="color"],
[type="date"],
[type="datetime"],
[type="datetime-local"],
[type="email"],
[type="month"],
[type="number"],
[type="password"],
[type="search"],
[type="tel"],
[type="text"],
[type="time"],
[type="url"],
[type="week"],
select,
textarea,
button,
[type="button"],
[type="reset"],
[type="submit"] {
  display: inline-block;
  vertical-align: middle;
  height: calc(2.25rem + 2px);
  color: #333;
  border: 1px solid #ccc;
  border-radius: 3px;
}

[type="color"],
[type="date"],
[type="datetime"],
[type="datetime-local"],
[type="email"],
[type="month"],
[type="number"],
[type="password"],
[type="search"],
[type="tel"],
[type="text"],
[type="time"],
[type="url"],
[type="week"],
select,
textarea {
  max-width: 100%;
  padding: 0.5rem;
  background-clip: padding-box;
  background-color: #fff;
  box-shadow: inset 1px 1px 2px rgba(0, 0, 0, 0.1);
}

[type="color"]:focus,
[type="date"]:focus,
[type="datetime"]:focus,
[type="datetime-local"]:focus,
[type="email"]:focus,
[type="month"]:focus,
[type="number"]:focus,
[type="password"]:focus,
[type="search"]:focus,
[type="tel"]:focus,
[type="text"]:focus,
[type="time"]:focus,
[type="url"]:focus,
[type="week"]:focus,
select:focus,
textarea:focus {
  border-color: rgb(30, 144, 255);
  box-shadow: 0 0 2px rgba(30, 144, 255, 0.8);
  outline: 0;
}

button,
[type="button"],
[type="reset"],
[type="submit"] {
  padding: 0.5rem 0.75rem;
  background-color: #f7f7f7;
  box-shadow: 0 1px 0 #ccc;
  cursor: pointer;
  -webkit-appearance: button;
}

button:hover,
[type="button"]:hover,
[type="reset"]:hover,
[type="submit"]:hover {
  background-color: #fafafa;
  border-color: #999;
}

button:focus,
[type="button"]:focus,
[type="reset"]:focus,
[type="submit"]:focus {
  border-color: rgb(30, 144, 255);
  box-shadow: 0 0 2px rgba(30, 144, 255, 0.8);
  outline: 0;
}

button:active,
[type="button"]:active,
[type="reset"]:active,
[type="submit"]:active {
  background-color: #eee;
  border-color: #999;
  box-shadow: inset 0 2px 5px -3px rgba(0, 0, 0, 0.5);
}

button:disabled,
[type="button"]:disabled,
[type="reset"]:disabled,
[type="submit"]:disabled {
  background-color: #f7f7f7;
  color: #a0a5aa;
  border-color: #ddd;
  box-shadow: none;
  text-shadow: 0 1px 0 #fff;
  cursor: default;
}

select {
  -moz-appearance: textfield;
  -webkit-appearance: textfield;
}

select::-ms-expand {
  display: none;
}

select[multiple],
select[size]:not([size="1"]) {
  height: auto;
  padding: 0;
}

select[multiple] option,
select[size]:not([size="1"]) option {
  padding: 0.5rem;
}

select:not([multiple]):not([size]),
select:not([multiple])[size="1"] {
  padding-right: 2rem;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath d='M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6 1.41-1.41z'/%3E%3Cpath fill='none' d='M0 0h24v24H0V0z'/%3E%3C/svg%3E") right 0.25rem center no-repeat;
}

textarea {
  height: auto;
  overflow: auto;
}
<select>
  <option>one</option>
</select>
<input type="text" placeholder="text">
<button>foo</button>

Most of the code above doesn't answer the question directly or even unrelated, and it doesn't include the <a> tag. But in a real web application, it's likely end up having more or less the same amount of CSS.

Upvotes: 3

Quentin
Quentin

Reputation: 3289

(Tested with Chrome only)

explain where the difference comes from?

It comes from user agent stylesheet which apply different style as default for each tag.
Those styles change according to the browser.


tell me what minimal changes I need to do to my CSS

input, select and button tags have a default font size which doesn't inherit from your body font-size declaration. Set their font-size value to inherit.

input, select, button { 
  font-size: inherit; 
}

a tag is inline by default. Set its value to inline-block.
Also, set its box-sizing value to border-box.

a { 
  display: inline-block; 
  box-sizing: border-box;
}

select has a biggest height content because of its the dropdown icon.
You could fix it by removing its default appearance, but I wouldn't recommend it.

select {
  -webkit-appearance: none;
}

Demo

body {
  font-size: 16px
}

select,
input,
button,
a {
  padding: 0.5rem;
  margin: 0.25rem;
  border: 1px solid red;
  vertical-align: top;
}

input,
select,
button {
  font-size: inherit;
}

a {
  display: inline-block;
  box-sizing: border-box;
}

/* Bad practice */
select {
  -webkit-appearance: none;
}
<select>
  <option>Select</option> 
</select>
<input type="text" value="Input">
<button>Button</button>
<a href="#">Link</a>


An other solution would be to use height + line-height properties for centering your elements and give them the same height.

body {
  font-size: 16px
}

select,
input,
button,
a {
  height: 40px;
  line-height: 40px;
  display: inline-block;
  vertical-align: top;
  margin: 0.25rem;
  padding: 0 0.5rem;
  border: 1px solid red;
  font-size: inherit;
  box-sizing: border-box;
}
<select>
  <option>Select</option> 
</select>
<input type="text" value="Input">
<button>Button</button>
<a href="#">Link</a>

Upvotes: 1

wtitus
wtitus

Reputation: 129

1. From what I understand, the CSS specification for form elements is very loose, so it can be difficult to apply styles at the same time to many different kinds of form elements. Because of this, these different elements all apply your style rules differently.

2. I was able to make the elements all have the same height with one more CSS rule inside the second set of selectors for your form elements:

body {
font-size: 16px;
}

select,
input,
button,
a {
padding: 0.5rem;
margin: 0.25rem;
border: 1px solid red;
font: 1rem "Helvetica", sans-serif;
}

You could change this font to whatever you like and it should still work. What this style primarily accomplishes is to "normalize" everything, especially the "a" element. The "a" element appears to want to keep its initial font-family and some form of its initial font-size. So, with the font style, you can make sure every element is inheriting the body's font size with the 1rem and that each element has a consistent font.

Upvotes: 0

Related Questions