CSS checkboxes & radio buttons when input is inside label?

36,065

Solution 1

If you can edit the markup to wrap the actual label text, for example:

<label>
    <input type="checkbox">
    <span>One</span>
</label>
<label>
    <input type="checkbox">
    <span>Two</span>
</label>
<label>
    <input type="checkbox" disabled>
    <span>Three</span>
</label>

You can pull off some tricks with CSS:

label {
    position:relative;   
    cursor:pointer;
}
label [type="checkbox"] {
    display:none; /* use your custom sprites instead as background on the span */
}
[type="checkbox"] + span {
    display:inline-block;
    padding:1em;
}
:checked + span {
    background:#0f0;
}
[type="checkbox"][disabled] + span {
    background:#f00;  
}​

Demo:

label {
  position: relative;
  cursor: pointer;
}

label [type="checkbox"] {
  display: none;
}

[type="checkbox"]+span {
  display: inline-block;
  padding: 1em;
}

:checked+span {
  background: #0f0;
  display: inline-block;
}

[type="checkbox"][disabled]+span {
  background: #f00;
}
<label>
    <input type="checkbox">
    <span>One</span>
</label>
<label>
    <input type="checkbox">
    <span>Two</span>
</label>
<label>
    <input type="checkbox" disabled>
    <span>Three</span>
</label>

http://jsfiddle.net/dMhDM/1/

Keep in mind that this will fail if the browser doesn't support :checked.

This is basically the same as the other solution, but the stying is done on the span rather than the label.

Solution 2

IMHO best way to do this without messing up with html by PURE CSS is

 input[type="checkbox"] {
     position: relative;
     cursor: pointer;
     padding: 0;
     margin-right: 10px;
}
 input[type="checkbox"]:before {
     content: '';
     margin-right: 10px;
     display: inline-block;
     margin-top: -2px;
     width: 20px;
     height: 20px;
     background: #fcfcfc;
     border: 1px solid #aaa;
     border-radius: 2px;
}
 input[type="checkbox"]:hover:before {
     background: #f5821f;
}
 input[type="checkbox"]:focus:before {
     box-shadow: 0 0 0 3px rgba(0, 0, 0, 0.12);
}
 input[type="checkbox"]:checked:before {
     background: #f5821f;
     border-color: #f5821f;
}
 input[type="checkbox"]:disabled {
     color: #b8b8b8;
     cursor: auto;
}
 input[type="checkbox"]:disabled:before {
     box-shadow: none;
     background: #ddd;
}
 input[type="checkbox"]:checked:after {
     content: '';
     position: absolute;
     left: 5px;
     top: 8px;
     background: white;
     width: 2px;
     height: 2px;
     box-shadow: 2px 0 0 white, 4px 0 0 white, 4px -2px 0 white, 4px -4px 0 white, 4px -6px 0 white, 4px -8px 0 white;
     transform: rotate(45deg);
}

Solution 3

Unfortunately CSS doesn't allow the styling of parent elements based on child elements which would be the easy way example:

div.a < div { border: solid 3px red; }

The opposite of selecting a child based on parent:

div.a > div { border: solid 3px red; }

What you are wanting to do can be achieved using jQuery.

Check out this post.

Solution 4

Very interesting question. Truth be told, I'm pretty sure that's just not possible with CSS alone.

If there's some sort of pattern to the label's for attribute (ctrl_enable_rte), there's hope for you. For example, if all checkbox labels end with rte, you could use

label[for$=rte] { ... }

If there is no such pattern, and the checkbox IDs are chosen arbitrarily, you'll have to resort to JavaScript.

Share:
36,065
Bob Loblaw
Author by

Bob Loblaw

Updated on October 20, 2021

Comments

  • Bob Loblaw
    Bob Loblaw over 2 years

    I've searched extensively on here for an answer to this but haven't quite come across what I'm looking for. Found this CSS - How to Style a Selected Radio Buttons Label? but the answer involved changing the markup, and that's something I want to avoid which I'll explain below.

    I'm trying to add custom css3 checkboxes and radio buttons to my XenForo forum theme, and all the tutorials I've read on this have the label after the input:

    <input type="checkbox" id="c1" name="cc" />
    <label for="c1">Check Box 1</label>
    

    However in XenForo's markup the input is inside the label:

    <label for="ctrl_enable_rte">
    <input type="checkbox" name="enable_rte" value="1" id="ctrl_enable_rte" {xen:checked "{$visitor.enable_rte}"} />
    {xen:phrase use_rich_text_editor_to_create_and_edit_messages}
    </label>
    

    I looked into why this is, but didn't find anything related to custom css checkboxes/radio buttons when the markup is this way. I want to avoid having to change the markup, because I'm dealing with a forum system here, and that would involve editing a bunch of core templates... which I'd have to then update the markup on each time the forum software put out an update (presuming the templates changed).

    I've tried to create CSS rules that would work with this type of markup, but thus far I've been unsuccessful. I'm not too experienced with CSS, don't have every selector memorized, and pseudo classes are still pretty foreign to me, so I was hoping someone here could shed some light on if this will be possible, and if so, how I might go about it. I already have my sprite ready to go, I just need to figure the CSS out.

    My main issue is I can't figure out how to select the label (only the labels involved with these inputs of course). Usually something like

    input[type="checkbox"] + label
    

    is used, but when the label isn't after the input and instead outside/before it... how do I select it?

  • Bob Loblaw
    Bob Loblaw over 11 years
    Interesting, I'll have to look into this and see if it's a possible solution, thanks! Edit: Seems "ctrl_" is used everywhere checkbox inputs are, however it's also used on labels that don't have checkboxes. Guess this won't work after all and JS is looking more and more like the only outlet here.
  • Bob Loblaw
    Bob Loblaw over 11 years
    While this would involve editing the HTML which I wanted to avoid, it's a method that might be possible with some template mods using regex which would a lot better and seamless during forum updates. The only downside being I'd still have to modify 73 templates and any new templates from future updates or addons. Perhaps I should give up on the pure CSS solution and instead look into making JS work perfectly in all instances. Thank you for taking the time to respond and write up an example, really appreciate it. I'm sure it will help others who aren't in as particular of a situation as myself.
  • Wesley Murch
    Wesley Murch over 11 years
    Or you could simply modify whatever it is that {xen:phrase ...} outputs to wrap it in a span. I'd go with js personally, but my company supports IE7 as a rule - I'm jealous of those who get to actually use CSS3 on a day to day basis.
  • Bob Loblaw
    Bob Loblaw over 11 years
    Ah yeah, didn't think of that. Definitely an alternate possibility though it might cause some funkiness in some areas. Definitely seems like JS is the only way to go here... and it would add in the extra browser compatibility that CSS would lack. I just need to figure out a good JS solution that works for my situation. Thanks again.
  • Wesley Murch
    Wesley Murch over 11 years
    Simple js solution would be adding a class to the wrapper label when the checkbox is checked or unchecked.
  • Bob Loblaw
    Bob Loblaw over 11 years
    Interesting, I'll look into this. After reviewing other answers it seems JS will indeed be the key here and as Wesley Murch said I might be able to pull it off by simply adding a class to the wrapper label. Thanks!
  • Jukka K. Korpela
    Jukka K. Korpela over 11 years
    I don’t see how this could be used to style the label depending on the checked state of a control. The state is dynamix, and the for attribute is static.
  • 3stacks
    3stacks about 7 years
    I know this is old, but, if you're following this example, consider using a visually-hidden on the input as display: none removes it from the DOM flow, therefore disabling keyboard controls and making it less accessible.
  • max4ever
    max4ever over 4 years
    brilliant! jsfiddle.net/ozv467na this doesn't require any special html label <-> input hierarchy
  • orithena
    orithena almost 4 years
    This does not work in Firefox. input[type="checkbox"] has no children in Firefox, so ::before and ::after cannot exist. This works in Chrome, but is based on the point that the W3 specs leave it open whether a self-closing tag can have children.