How does css checkbox hack work? - html

I just came across the switch toggle button which is created only using css. It known as the checkbox hack.
For those who doesn't know what a checkbox css hack is, Please read it here
https://css-tricks.com/the-checkbox-hack/
I tried it out and it was working perfectly fine. But I didn't understand how this is working because we are not clicking on the checkbox.
So I have 2 questions
How is this working ?
Instead of absolute positioning I tried it with display: none;
It still worked. Does this method have any drawbacks?

The way it works is by using the <label> element. Any input element can (and usually should) have a label. You can tell the browser which label belongs to which label by using a for attribute, referring to the input's name:
<input name="myName" />
<label for="myName">Label</label>
Whenever you click the label, it focuses the input (or in case of checkboxes, toggles it).
The label and checkbox don't have to be near each other. You could add a few hidden checkboxes at the start or end of a document and place the labels anywhere on the page, and they'd still focus the input.
Hiding the checkbox through display: none could cause buggy behavior on certain browsers. Just hiding it from view by a position: absolute is safer.

You can bind labels to checkboxes/radios using the for= attribute. When this is set, clicking on the label toggles the checkbox. This is a standard HTML attribute.
You can hide the checkbox using display: none, but do test it to make sure that its value is still submitted with the form.

CSS is aware of the current checked state of a checkbox input
This awareness, in combination of siblings selectors such as + (immediate next sibling) and ~ (next sibling somewhere) allows styling different styles, for checked/unchecked states, to anything that comes after the input element. The key here is the word "after".
Basic example:
/* styles when checkbox is unchecked */
div{ border:2px solid blue; margin:10px }
div h3{ color:red; }
/* when checkbox is checked */
input:checked ~ div{ background:blue; }
input:checked ~ div h3{ color:gold; }
<input type=checkbox>
<div><h3>very<h3></div>
<div><h3>cool<h3></div>
As others have said (but is not a must) - HTML label element allows to interact with input elements, and in checkbox/radio types' case - it allows to toggle their checked state by clicking the label itself, which is "linked" to a specific input element by the for attribute:
<label for='x`>click</label>
and the id attribute no the linked input:
<input type='checkbox' id='x'>
For the method to work, the input element must to be placed before whatever element(s) it is intended to control via CSS.
In real-word use cases, one would often want to use the CSS-toggling features of a checkbox over next siblings, but to obscure the fact there is a checkbox involved. The best way is by applying the hidden attribute on the input, which only toggles off the rendering of the input, nothing else.
The example below showcase such use case for a simple accordion component:
Practical example: Accordion
.accordion{ width: 300px; border: 1px solid silver; }
.accordion label{ display:block; padding:1em; cursor:pointer; }
.accordion label:hover{ color:red; }
.accordion > div:not(:last-child){ border-bottom:1px solid silver; }
.accordion .more{ max-height:0; transition:.5s; color:green; padding:0 1em; overflow: hidden; }
/* checked toggled */
.accordion input:checked + .content{ background:#EEE; }
.accordion input:checked + .content .more{ max-height:200px; }
<div class='accordion'>
<div>
<input type='checkbox' id='checkbox_item_1' hidden>
<div class='content'>
<label for='checkbox_item_1'>Title 1</label>
<div class='more'>
<p>This is cool<p>
<p>Yes it is</p>
</div>
</div>
</div>
<div>
<input type='checkbox' id='checkbox_item_2' hidden>
<div class='content'>
<label for='checkbox_item_2'>Title 2</label>
<div class='more'>
<p>This is also cool</p>
<p>So much fun</p>
</div>
</div>
</div>
</div>

You can hide the checkbox with visibility: hidden; or opacity: 0; besides display: none; but i'm not sure which one is better.

Related

Label's color changes when you are typing in the login field?

I want to make the same login effect than Twitter.
On twitter.com/login, you see that when you are typing in the text area, the grey color of the label "Phone, email, or username" or "Password" changes to blue.
So I've tried to make input:focus label {color: blue;}
But it doesn't work, I don't know why.
try using the general sibling selector like this
input:focus ~ label{
color: #0000ff;
}
Note that this code assumes input and label are siblings
Your code doesn't work because what you wrote basically says: "if I focus my input, put this css on my label which is a child of input". Now I'm assuming since this wouldn't be valid html, your label is not a child of your input.
The answer #arnavpanwar99 provided is correct, usually your input and label are siblings like this:
<div>
<label>My Label</label>
<input type="text" />
</div>
unfortunately, the sibling selector only works from left to right, meaning that something like this: input:focus ~ label would once again not work, since it goes once again from left to right (and the label is on the left side of your input, therefore the code is not affecting it).
Now if we switch positions, it would work:
div {
margin-bottom: 5px;
}
label {
color: grey;
}
input:focus ~ label {
color: red;
}
<div>
<input type="text" />
<label>My Label</label>
</div>
But unfortunately, now the label is on the wrong side.
The trick is, to use css (in my case I just used float: left but you can basically do everything you want to make it look right) to fix the appearance, while still using the "wrong" html setup:
div {
margin-bottom: 5px;
}
label {
color: grey;
}
input:focus ~ label {
color: red;
}
.pullLeft {
float: left;
}
<div>
<input type="text" />
<label class="pullLeft">My Label</label>
</div>
Set a class on a surrounding div and use :focus-within on that div followed by label to change the color of the label.
The reason why this works is because instead of looking for child elements of input, it checks if something is being focused within the surrounding div.
.input-group:focus-within label {
color: red;
}
<div class="input-group">
<label>My Label</label>
<input type="text" />
</div>
You can read more about focus-within here: https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-within

Button inside a label

I have a label with "for="the pointer to the checkbox input"" and as long as I know, this for can be added only for label. Therefore, I need to add inside of the label a <button>(I need it), but the click event isn't working properly - it doesn't check the checkbox the for is pointing to.
What are the possibilities I can use here if I must place <button> inside the label, with only html+css coding?
some code for example:
<input type="checkbox" id="thecheckbox" name="thecheckbox">
<div for="thecheckbox"><button type="button">Click Me</button></div>
It turns out you can make a <button> operate an input, but only if you put the <label> inside the <button>.
<button type="button">
<label for="my-checkbox">Button go outside the label</label>
</button>
<input type="checkbox" id="my-checkbox">
Although this contravenes the W3C specs:
The interactive element label must not appear as a descendant of the button element.
https://www.w3.org/TR/html-markup/label.html
You can do dis:
<label>
<button></button>
</label>
CSS
label {
cursor: pointer; // not necessary but probably a good idea.
display: block; // depending on your structure.
}
button {
pointer-events: none;
}
The display: block on label will only be necessary so that the bounding box of the label fully encapsulates it's children (the button in this case).
You can use transparent pseudo element that overlays the checkbox and the button itself that will catch mouse events.
Here's an example:
html:
<label>
<input type="checkbox">
<button class="disable">button</button>
</label>
css:
.disable{pointer-events:fill}
label{position:relative}
label:after{
position: absolute;
content: "";
width: 100%;
height: 100%;
background: transparent;
top:0;
left:0;
right:0;
bottom:0;
}
HTML:
<label for="whatev"
onclick="onClickHandler">
<button>Imma button, I prevent things</button>
</label>
JS:
const onClickHandler = (e) => {
if(e.target!==e.currentTarget) e.currentTarget.click()
}
Target is the click target, currentTarget is the label in this case.
Without the if statement the event is fired twice if clicked outside of the event preventing area.
Not cross browser tested.
The best solution is to style is like a button.
If you're using a CSS framework, like bootstrap, you can give the label classes such as btn and btn-default. This will style it like a button. You may need to adjust the css property of the line-height manually like so:
label.btn {
line-height: 1.75em;
}
Then, to get the on click styles as a button, add these styles:
input[type=radio]:checked ~ label.btn {
background-color: #e6e6e6;
border-color: #adadad;
color: #333;
}
This will take the input that is checked and give the next label element in the dom that has the class btn, bootstrap btn-default button clicked styles. Adjust colors as fit.

Change checkbox label css property with checkbox checked

I have the following html:
<label>
<input type="checkbox" value="cb_val" name="cb_name">
my checkbox text
</label>
With CSS I added a background-color to the <label> tag.
label { background-color:#333; color:#FFF; }
Now I'd liked to change the background color of the label when the checkbox is checked.
I know how to do it with javascript, but is there a way to to it just using CSS?
I have seen some solutions, but they use the adjacent sibling selector and only work when the label appears after the checkbox.
I still hope to fix this without javascript, does anyone have a clue?
UPDATE:
As I was afraid of, it cannot be done this way, so i must do it with JS, or achieve the same visual effect with a different HTML structure.
I want to set the background color of the label and the textbox in one go, so I can go with a solution where the checkbox is placed absolute on top of the label. Good point PlantTheldea!
Or I can apply the background color to the label and the checkbox both.
Thanks everyone!
You can achieve this with pure css like so,
<input type="checkbox" id="cb_1" value="cb_val" name="cb_name">
<label for="cb_1">
my checkbox text
</label>
With this css,
label { background-color:#333; color:#FFF; }
input[type="checkbox"]:checked + label {
background: brown;
}
JSFIDDLE
Keep in mind
The label has to be after the checkbox so you will need to style it around more to keep the same look you had.
Here is an option of styling it more to have the same appearance as you wanted, New fiddle. THIS DOES NOT involve positioning anything absolute, just some trickery.
You can't style the label itself directly via only CSS when the label is checked, but you can style a sibling of the checkbox.
http://jsfiddle.net/QdDpL/
HTML
<label>
<input class="check" type="checkbox" />
<span class="label-text">Checkbox</span>
</label>
CSS
label {
background: yellow;
}
label .label-text {
background: cyan;
}
label input.check:checked + .label-text {
background: lime;
}
You may also be able to fiddle with floats and padding to make the checkbox appear as if it was inside the .label-text span.
See the following links for browser support on the sibling selector:
http://caniuse.com/css-sel2
Alternately as another answer said, you can style the label if it is a sibling of the checkbox - but then just like my answer still would not contain the checkbox in the label.

Input placeholder using CSS only

I know there are lot's of questions regarding this query here but none of them provide the solution for me.
HTML
<input id="tb1" type="text" class="note" />
<br>
<p class="note1"> This is not done.</p>
CSS
p.note1:before{
content: "Note:";
}
tb1.note:before{
content: "Enter your number";
}
I am trying with above code and the variation as found on the web but none seems to work for input tag. It's working for p tag.
EDIT: I can't add value attribute to input tag and manage css for the desired result. It's the limitation of the system.
EDIT2: Forget about my css, is there any way that placeholder text is possible without using placeholder attribute and just with plain css for input type="text"
:before creates a pseudo-element that is the first child of the element matched.
The selected element MUST be a container tag. An empty tag like <input> doesn't have any children element.
If you can't edit your HTML code manually, you're still able to that by using JavaScript:
document.getElementById("tb1").setAttribute("placeholder", "Enter your number");
Update
If you want to achieve this by using CSS only, you need to have a container element wrapping your <input> (or come after it).
BUT It doesn't work correctly as placeholder do. You'll not able to check the value of <input> by CSS. If you write something inside the <input>, after blur event, the generated placeholder will be displayed over the <input> again.
HTML:
<label>
<input id="tb1" type="text" class="note">
</label>
CSS:
label {
position: relative;
}
label:after {
content: 'Enter your number';
position: absolute;
left: 5px;
top: 0;
color: #bbb;
}
#tb1 {
position: relative;
}
#tb1:focus {
z-index: 10;
}
JSBin Demo
It doesn't work for the simple fact that this:
<input id="tb1" type="text" class="note"></input>
is not valid. <input /> elements are not containers. As the spec notes, endtags are forbidden (and essentially ignored by the browser): http://www.w3.org/TR/html401/interact/forms.html#h-17.4
If you cant manipulate the html and use placeholder="". Use javascript to manipulate the placeholder. Every css approach is hack-isch anyway.
E.g. with jQuery:
$('#myFieldId').attr('placeholder', 'Search for Stuff');
I have found this method but not supported by all browsers:
#tb1.note:empty:before{
content: "Enter your number";
}
Note: you have forgot to place an id selector # tb1.note
see this link
EDIT:
Try this for starters: (Note: you'll need some js to detect if text has been entered in the input)
Apart from this - I don't think this there is a css solution for placeholder text on an input element without using the placeholder attribute.
FIDDLE
Markup
<div class="container">
<input />
<div class="fakePlaceholder">Some placeholder text</div>
</div>
css
.container
{
position: relative;
}
input
{
background: transparent;
}
input:focus + .fakePlaceholder
{
display: none;
}
.fakePlaceholder
{
color:gray;
position:absolute;
top: 3px;
left: 5px;
z-index: -1;
}
You can't use pseudo elements on an input tag - or any other non-container elements for that matter
From the Pseudo-Elements tag info:
you cannot use them (pseudo elements) with replaced elements (see
below) which do not have actual content. This is because the generated
content resides within the element.
...
Replaced Elements
Any element whose appearance and/or dimensions are determined by some
external resource is considered to be a replaced element. Some
pseudo-elements cannot be applied to replaced elements because they
have no "content" or get replaced with something (such as user
interface controls). Replaced elements include images (<img>), inline
frames (<iframe>), line breaks (<br>), horizontal rules (<hr>),
plugins (<object>), form elements (<button>, <textarea>, <input>, and
<select>), videos (<video>), audio sounds (<audio>), and canvases
(<canvas>). Any other element is considered to be a non-replaced
element.
Another way this can be accomplished, and have not really seen any others give it as an option, is to instead use an anchor as a container around your input and label, and handle the removal of the label via some color trickory, the #hashtag, and the css a:visited. (jsfiddle at the bottom)
Your HTML would look like this:
<a id="Trickory" href="#OnlyHappensOnce">
<input type="text" value="" id="email1" class="inputfield_ui" />
<label>Email address 1</label>
</a>
And your CSS, something like this:
html, body {margin:0px}
a#Trickory {color: #CCC;} /* Actual Label Color */
a#Trickory:visited {color: #FFF;} /* Fake "Turn Off" Label */
a#Trickory:visited input {border-color: rgb(238, 238, 238);} /* Make Sure We Dont Mess With The Border Of Our Input */
a#Trickory input:focus + label {display: none;} /* "Turn Off" Label On Focus */
a#Trickory input {
width:95%;
z-index:3;
position:relative;
background-color:transparent;
}
a#Trickory label {
position:absolute;
display:block;
top:3px;
left:4px;
z-index:1;
}
You can see this working over at jsfiddle, note that this solution only allows the user to select the field once, before it removes the label for good. Maybe not the solution you want, but definitely an available solution out there that I have not seen others mention. If you want to experiment multiple times, just change your #hashtag to a new 'non-visited' tag.
http://jsfiddle.net/childerskc/M6R7K/

toggling styles on label (active/focus) for input field with css only

Wondering whether if there is a css-only way to perform to toggle styles on the corresponding label on input's focus.
So far I have:
$(document).on('focus active', 'input',function(){
$('label[for='+$(this).attr('id')+']').addClass('active');
});
$(document).on('blur', 'input',function(){
$('label[for='+$(this).attr('id')+']').removeClass('active');
});
HTML:
<div class="row">
<label for="contact_form_mail">Email</label>
<input id="contact_form_mail" name="contact_form_mail" type="email" placeholder="Your e-mail address...">
</div>
And CSS:
.active{ color:red; }
Edit: I am surely aware of the child and sibling selectors "workarounds", but rearranging clean markup for the pure sake of styling seems not right, so if there is another pure css way this answer wins!
http://jsfiddle.net/fchWj/3/
Try this way:- Place your label after input and float it left. And apply siblings.
Html
<div class="row">
<input id="contact_form_mail" name="contact_form_mail" type="email" placeholder="Your e-mail address...">
<label for="contact_form_mail">Email</label>
</div>
CSS
label {
float:left;
}
input:focus + label {
color:red;
}
Demo
This is a hack to get the adjacent sibling selector work as it applies only on the following element and not the preceding one. ~ will select all the adjascent siblings after this element. So if you are having different .row for each section of inputs then use +.
If you are willing to switch elements, than here you go
Demo
<div>
<input type="text" />
<label for="e_mail">E-Mail</label>
</div>
label {
float: left;
margin-right: 5px;
}
input[type=text]:focus + label {
color: red;
}
Explanation: We are using + adjacent selector here, so when the textbox is focused, we select the label tag and apply color red
Note: Don't forget to clear floats ;)
It's possible with CSS only, without switching the order of the label and input. You can use a :focus-within CSS pseudo-class on the parent element, which applies to elements, that has a child element with the focus.
In your example, you could use the following:
.row:focus-within label {
color: red;
}
Note, that this pseudo-class is relatively new, so only modern browsers support it.
There is, but only if you place the label after the input.
<input name="field" type="text" />
<label for="field">Label Here</label>
input:focus + label{
color: red;
}
Now if you want the label to be placed before it, then you need to do some css styling with position absolute to place the label before the input field, then add some margin left on the input to move it to the right.
<div>
<input name="field" type="text" />
<label for="field">Label Here</label>
</div>
div{
position: relative;
}
input{
margin-left: 40px;
}
label{
position:absolute;
left:0;
}
This give you label on top of input, highlight label while input focus.
HTML
<div class="row">
<input id="contact_form_mail" name="contact_form_mail" type="email" placeholder="Your e-mail address...">
<label for="contact_form_mail">Email</label>
</div>
<code>
.row{
display:flex;
flex-direction:column-reverse;
align-self:flex-start;
}
.row input:focus{
border: 1px solid red;
}
.row input:focus+label{
color:red;
}
</code>
First we can use a selector that matches a label immediately followed by the input tag (input:focus + label). But there is still the problem, that the label follows after the actual input field. If one would like to have it above the text input we need to switch the positions of the controls. This can be done with a CSS pseudo-table.
<div class="pseudo-table">
<input id="yourname" name="yourname" type="text" placeholder="Name...">
<label for="yourname">Name</label>
</div>
The style for the artifical table is...
.pseudo-table { display: table; }
With this in place we could transform the label e.g. to a table-header-group:
label { display: table-header-group; }
and the input field to a table-row-group:
input { display: table-row-group; }
In combination with our followed by selector we're done and it looks right:
input:focus + label {
color:red;
font-weight: bold;
}
For a demo please see this Fiddle
HTH
There is no selector to match a preceding element...
This matches a label immediately followed by an input tag.
input:focus + label {
color: red;
}