How to align checkboxes and their labels consistently cross-browsers

55

Solution 1

Warning! This answer is too old and doesn't work on modern browsers.

I'm not the poster of this answer, but at the time of writing this, this is the most voted answer by far in both positive and negative votes (+1035 -17), and it's still marked as accepted answer (probably because the original poster of the question is the one who wrote this answer).

As already noted many times in the comments, this answer does not work on most browsers anymore (and seems to be failing to do that since 2013).


After over an hour of tweaking, testing, and trying different styles of markup, I think I may have a decent solution. The requirements for this particular project were:

  1. Inputs must be on their own line.
  2. Checkbox inputs need to align vertically with the label text similarly (if not identically) across all browsers.
  3. If the label text wraps, it needs to be indented (so no wrapping down underneath the checkbox).

Before I get into any explanation, I'll just give you the code:

label {
  display: block;
  padding-left: 15px;
  text-indent: -15px;
}
input {
  width: 13px;
  height: 13px;
  padding: 0;
  margin:0;
  vertical-align: bottom;
  position: relative;
  top: -1px;
  *overflow: hidden;
}
<form>
  <div>
    <label><input type="checkbox" /> Label text</label>
  </div>
</form>

Here is the working example in JSFiddle.

This code assumes that you're using a reset like Eric Meyer's that doesn't override form input margins and padding (hence putting margin and padding resets in the input CSS). Obviously in a live environment you'll probably be nesting/overriding stuff to support other input elements, but I wanted to keep things simple.

Things to note:

  • The *overflow declaration is an inline IE hack (the star-property hack). Both IE 6 and 7 will notice it, but Safari and Firefox will properly ignore it. I think it might be valid CSS, but you're still better off with conditional comments; just used it for simplicity.
  • As best I can tell, the only vertical-align statement that was consistent across browsers was vertical-align: bottom. Setting this and then relatively positioning upwards behaved almost identically in Safari, Firefox and IE with only a pixel or two of discrepancy.
  • The major problem in working with alignment is that IE sticks a bunch of mysterious space around input elements. It isn't padding or margin, and it's damned persistent. Setting a width and height on the checkbox and then overflow: hidden for some reason cuts off the extra space and allows IE's positioning to act very similarly to Safari and Firefox.
  • Depending on your text sizing, you'll no doubt need to adjust the relative positioning, width, height, and so forth to get things looking right.

Hope this helps someone else! I haven't tried this specific technique on any projects other than the one I was working on this morning, so definitely pipe up if you find something that works more consistently.


Warning! This answer is too old and doesn't work on modern browsers.

Solution 2

Sometimes vertical-align needs two inline (span, label, input, etc...) elements next to each other to work properly. The following checkboxes are properly vertically centered in IE, Safari, FF, and Chrome, even if the text size is very small or large.

They all float next to each other on the same line, but the nowrap means that the whole label text always stays next to the checkbox.

The downside is the extra meaningless SPAN tags.

.checkboxes label {
  display: inline-block;
  padding-right: 10px;
  white-space: nowrap;
}
.checkboxes input {
  vertical-align: middle;
}
.checkboxes label span {
  vertical-align: middle;
}
<form>
  <div class="checkboxes">
    <label><input type="checkbox"> <span>Label text x</span></label>
    <label><input type="checkbox"> <span>Label text y</span></label>
    <label><input type="checkbox"> <span>Label text z</span></label>
  </div>
</form>

Now, if you had a very long label text that needed to wrap without wrapping under the checkbox, you'd use padding and negative text indent on the label elements:

.checkboxes label {
  display: block;
  padding-right: 10px;
  padding-left: 22px;
  text-indent: -22px;
}
.checkboxes input {
  vertical-align: middle;
}
.checkboxes label span {
  vertical-align: middle;
}
<form>
  <div class="checkboxes">
    <label><input type="checkbox"> <span>Label text x so long that it will probably wrap so let's see how it goes with the proposed CSS (expected: two lines are aligned nicely)</span></label>
    <label><input type="checkbox"> <span>Label text y</span></label>
    <label><input type="checkbox"> <span>Label text z</span></label>
  </div>
</form>

Solution 3

Working off of One Crayon's solution, I have something that works for me and is simpler:

.font2 {font-family:Arial; font-size:32px} /* Sample font */

input[type=checkbox], input[type=radio] {
  vertical-align: middle;
  position: relative;
  bottom: 1px;
}

input[type=radio] { 
  bottom: 2px; 
} 
<label><input type="checkbox" /> Label text</label>
<p class="font2">
  <label><input type="checkbox"/> Label text</label>
</p>

Renders pixel-for-pixel the same in Safari (whose baseline I trust) and both Firefox and IE7 check out as good. It also works for various label font sizes, big and small. Now, for fixing IE's baseline on selects and inputs...


Update: (Third-Party Edit)

The proper bottom position depends on font-family and font-size! I found using bottom: .08em; for checkbox & radio elements is a good general value. I tested it in Chrome/Firefox/IE11 in windows with Arial & Calibri fonts using several small/mid/large font-sizes.

.font2, .font2 input {font-family:Arial; font-size:32px} /* Sample font */

input[type=checkbox], input[type=radio] {
  vertical-align: middle; 
  position: relative;
  bottom: .08em; /* this is a better value for different fonts! */
}
<label><input type="checkbox" /> Label text</label> 

<p class="font2">
  <label><input type="checkbox"/> Label text</label>
</p>

Solution 4

One easy thing that seems to work well is to apply a adjust the vertical position of the checkbox with vertical-align. It will still be vary across browsers, but the solution is uncomplicated.

input {
    vertical-align: -2px;
}

Reference

Solution 5

try vertical-align: middle

also your code seems like it should be:

<form>
    <div>
        <input id="blah" type="checkbox"><label for="blah">Label text</label>
    </div>
</form>
Share:
55
html_programmer
Author by

html_programmer

Updated on November 18, 2021

Comments

  • html_programmer
    html_programmer over 2 years

    I have multiple routes, split into different files (my app consists of different "modules", which I maintain in separate folders. For each folder, there is an index.js file in which I manage the routes per module, and I require these in the app.js file).
    For every route, I will require to check the auth, and pass the loggedIn status to the header of every page:

    //Default variables for the ejs template 
    var options = { 
        loggedIn: true
    }; 
    
    res.render("home/home", options);  
    

    If the logged in status is true, then the user's name will be displayed. If not, the login / signup labels are displayed.

    What is the best way to centralise this, so that I don't need to require the auth script in every of these index.js (route) files?
    I need to be able to pass the auth status to the view via the options object (see example).

    • volume one
      volume one over 10 years
      Put each checkbox and label within an <li> element. Add overflow:hidden to the <li> and float the label and checkbox left. Then they all align perfectly fine. Don't put the checkbox within the label element obviously.
    • TheGr8_Nik
      TheGr8_Nik over 9 years
      I have acieved it by using height and line-height attributes, give a look to jsfiddle.net/wepw5o57/3
    • Profesor08
      Profesor08 about 8 years
      Manipulation with position and top will solve this problem Example: jsfiddle.net/ynkjc22s
    • dieter
      dieter about 5 years
      2019. still the same issue. still need some hacks to get it work :(
    • YakovL
      YakovL almost 5 years
      @dieter see my answer, I've explained why hacks are needed and what approach is not hacky: stackoverflow.com/a/56558431/3995261
  • perimosocordiae
    perimosocordiae over 15 years
    Not exactly true: The Label-for will allow users to click the label in order to check the checkbox, in addition to simply clicking the checkbox itself. It's quite handy for tying the two elements together.
  • Verlet64
    Verlet64 over 15 years
    As I've said to previous posters who recommended that: I don't like it because it requires unnecessary markup. Also, I tried that markup but it was difficult to prevent the label from wrapping beneath the input (while still having label/input group each on their own lines).
  • Robert C. Barth
    Robert C. Barth over 15 years
    So, instead of "unecessary" markup (used by probably almost everyone), you'd rather have unecessary CSS?
  • Verlet64
    Verlet64 over 15 years
    The problem with wrapping stands. But in general, yes I'd rather have extraneous CSS than markup since the CSS is cached, but the markup may have to be loaded anew for every new page.
  • IDisposable
    IDisposable over 15 years
    bless you for using ems instead of pxs.
  • Verlet64
    Verlet64 about 15 years
    Just a note for others: this won't work in IE6 because it doesn't support the [type=checkbox] CSS targeting.
  • William Gross
    William Gross over 13 years
    Thanks! The "vertical-align: middle" on both the input and the span worked great for me.
  • Greg
    Greg over 12 years
    Compare: 1 instance of extra CSS -vs- many instances of extra markup.
  • maxspan
    maxspan about 10 years
    also need to add vertical-align:top or vertical-align:bottom. Depends.. on the position where it needs to get aligned
  • Mariano Desanze
    Mariano Desanze over 9 years
    Nice! But you should consider copying the HTML and CSS code in here. Answers that depends so much on an external link are discouraged. The link is still valuable to see the results, but I think showing the code in here will help you get more up votes.
  • JonSnow
    JonSnow about 9 years
    the question is: does it work well in all browsers? ;-)
  • robsch
    robsch over 5 years
    Seems to work as long as the font size is not too large.
  • YakovL
    YakovL almost 5 years
    hm, this does look well when the label starts with a lowercase letter, but if it starts with a capital one, it's much worse. Could you add a snippet here?
  • YakovL
    YakovL almost 5 years
    nope, they don't (compare in FireFox and in Chrome, in Chrome the checkboxes are above the baseline), I've explained why
  • YakovL
    YakovL over 4 years
    Why, you claim the thing that's unsupported even with screenshots from both browsers. It is your job to provide proofs for a claim when you make one, not others' to disprove it. I did compare those and would add the screenshots, but comments don't support adding pictures; you can take a look at pictures in my answer though. This however may differ with browser versions, so providing screenshots with annotations containing browser versions would be helpful.
  • Vladimir Kornea
    Vladimir Kornea over 4 years
    Visit the page I linked to in different browsers.
  • YakovL
    YakovL over 4 years
    So I did that, did you? :) Don't you see the difference? imagebin.ca/v/50stCZZGl7Ug imagebin.ca/v/50stNBiv29Ks While in FireFox they are perfectly aligned, in Chrome the checkbox is about the baseline (by the way, you can use mentions via @ if you are interested in quicker replies)
  • Vladimir Kornea
    Vladimir Kornea over 4 years
    It's not often people disagree about what they see. I looked at your images at the pixel level, and they are indeed identically aligned. The only difference is that Chrome's checkbox appears to be one pixel shorter because its bottom row of pixels is lighter than the row above it (ie, what the eye sees as the bottom "border" of the checkbox is actually the second to-bottom row of pixels).
  • mustaccio
    mustaccio almost 4 years
    You might want to add an explanation of how this answer is different from the other 47 answers.
  • Adrian Lynch
    Adrian Lynch almost 3 years
    Why the need for flex: none?
  • YakovL
    YakovL over 2 years
    since the answer is outdated and the question is community wiki anyway, let me promote my answer where I'm considering the source of the problem instead of trying to provide some CSS that works only in certain browsers: stackoverflow.com/a/56558431/3995261