I have a project where I show and hide elements using checkboxes in conjunction mit CSS only. The following pattern, see also https://jsfiddle.net/37bqmbuo/, works for me.
HTML:
<input class="switch-1" type="checkbox">
<input class="switch-2" type="checkbox">
<input class="switch-3" type="checkbox">
<div class="hidden-1 hidden-2">Info 1</div>
<div class="hidden-2 hidden-3">Info 2</div>
<div class="hidden-1 hidden-3">Info 3</div>
<div class="hidden-1">Info 4</div>
<div class="hidden-3">Info 5</div>
CSS:
.switch-1:checked ~ .hidden-1
{
display: none;
}
.switch-2:checked ~ .hidden-2
{
display: none;
}
.switch-3:checked ~ .hidden-3
{
display: none;
}
But the more options I have, the more classes I need to create. Is there a smarter way to implement this with CSS only?
Actually, there is.
Put the element you want to target after the input like so:
<input type="checkbox" value="My Checkbox" />
<div class="toggle">Toggle me</div>
and do some CSS magic:
input:checked + .toggle { display: none; }
Related
complete coding newbie with no formal HTML/CSS education here. I am experimenting with a project and wanted to try and make a list of paragraph elements hidden and expandable.
It is important to note that my ways of modifying the site in question are rather limited. I can only directly modify the CSS of the page and the HTML -in- the <h2 class="label"> (not the class itself).
I have included the pieces of HTML and CSS below. The first toggle correctly hides the "Control me"-text. I was wondering if I could do the same for the div class "value" or the paragraph elements under it. The second piece of CSS is, evidently, not working. I assume this has to do with the placement/relationship of the elements. So, my question is: is this, at all, possible? If so, how?
I am aware that this "checkbox hack" is not recommended. With the limitiations I described above, I at least want to try it. Consequently, I would appreciate all help on this topic, if only for the sake of experimentation/knowledge.
My apologies if this is a silly question. Thanks in advance!
#toggle:checked ~ .control-me{
display: none; /*this works*/
}
#toggle:checked ~ .value{
display: none; /*this does not work*/
}
<section class="item references">
<h2 class="label">
<label for="toggle">References</label>
<input type="checkbox" id="toggle" class="visually-hidden">
<div class="control-me">Control me</div>
</h2>
<div class="value">
<p>Originally lots of different paragraph elements here</p>
</div>
</section>
#toggle:checked ~ .control-me{
display: none; /*this works*/
}
#toggle:checked ~ .value{
display: none; /*this does not work*/
}
<section class="item references">
<label for="toggle">References</label>
<input type="checkbox" id="toggle" class="visually-hidden">
<div class="control-me">Control me</div>
<div class="value">
<p>Originally lots of different paragraph elements here</p>
</div>
The '~' selector requires that both elements have the same parent and element 1 comes before element 2.
In your first example #toggle:checked comes before .control-me and the elements are both children of the same parent.
Where as in your second example: #toggle:check does come before .value but they are not from the same parent
https://www.w3schools.com/cssref/sel_gen_sibling.asp
EDIT: I have added a snippet with the h2 tag removed, to show that if they shared a parent, the desired effect would be achieved.
The main problem is that you have wrapped the control-me class inside a <h2> tag. Where as the .value class is outside the h2 tag so it changes only elements inside <label>.
Solution No 1:
Put the outside h2 tag.It works
<section class="item references">
<h2>
<label for="toggle">References</label>
</h2>
<input type="checkbox" id="toggle" class="visually-hidden" />
<div class="control-me">Control me</div>
<div class="value">
<p>Originally lots of different paragraph elements here</p>
</div>
</section>
Solution No 2:
Wrap the things you want to hide inside h2 tag
<section class="item references">
<h2>
<label for="toggle">References</label>
<input type="checkbox" id="toggle" class="visually-hidden" />
<div class="control-me">Control me</div>
<div class="value">
<p>Originally lots of different paragraph elements here</p>
</div>
</h2>
</section>
Here is a JavaScript answer (because you mentioned in a comment that you can use JS)-
Add a class d-none in CSS and toggle the class via JavaScript on each click.
Here is a working example-
document.getElementById("toggle").addEventListener("click", function(){
document.getElementsByClassName("value")[0].classList.toggle("d-none");
});
#toggle:checked ~ .control-me{
display: none; /*this works*/
}
.d-none{
display: none;
}
<section class="item references">
<h2 class="label">
<label for="toggle">References</label>
<input type="checkbox" id="toggle" class="visually-hidden">
<div class="control-me">Control me</div>
</h2>
<div class="value">
<p>Originally lots of different paragraph elements here</p>
</div>
</section>
Edit : Here is the snippet with script tag in the case there is some problem with inserting scripts externally.
#toggle:checked ~ .control-me{
display: none; /*this works*/
}
.d-none{
display: none;
}
<section class="item references">
<h2 class="label">
<label for="toggle">References</label>
<input type="checkbox" id="toggle" class="visually-hidden" onclick="hide()"/>
<div class="control-me">Control me</div>
</h2>
<div class="value">
<p>Originally lots of different paragraph elements here</p>
</div>
</section>
<script>
function hide(){
document.getElementsByClassName("value")[0].classList.toggle("d-none");
}
</script>
I want to split my site in two vertical sections. If you click on a left button (width:50%), the content for this button should appear below with width:100% and if you click on the right button the same but of course with content 2.
Is it even possible with pure css? Because I don't know java :/ and I think it's a quite simple problem, isn't it?
#content_button_left,
content_button_right {
display: none
}
#button_left:active~#content_button_left {
display: inherit
}
#button_right:active~#content_button_right {
display: inherit
}
<div>
<div style="display:flex">
<div id="button_left" style="flex:1">Menu left</div>
<div id="button_right" style="flex:1">Menu right</div>
</div>
<div id="content_button_left" style="width:100%">
blabla 1
</div>
<div id="content_button_right" style="width:100%">
blabla 2
</div>
</div>
You can use :target CSS selector to fake the click event but for that you have to convert your div to anchor tag, below is CSS
#content_button_left, #content_button_right{
display:none
}
#content_button_left:target {
display:block;
}
#content_button_right:target{
display:block;
}
Updated HTML
<div style="display:flex">
<a id="button_left" href="#content_button_left" style="flex:1">Menu left</a>
<a id="button_right" href="#content_button_right" style="flex:1">Menu right</a>
</div>
<div id="content_button_left" style="width:100%">
blabla 1
</div>
<div id="content_button_right" style="width:100%">
blabla 2
</div>
I would use radio buttons next to the content and labels for your button targeting the radios. This way you can use the adjacent sibling selector to only show the content next to a checked radio:
/* hide radio and content */
.radio,
.content {
display: none;
}
/* show content if it directly follows a checked radio */
.radio:checked + .content {
display: block;
}
<div>
<div style="display:flex">
<label id="button_left" style="flex:1" for="left-input">Menu left</label>
<label id="button_right" style="flex:1" for="right-input">Menu right</label>
</div>
<input type="radio" name="show-content-radio" id="left-input" class="radio">
<div id="content_button_left" style="width:100%" class="content">
blabla 1
</div>
<input type="radio" name="show-content-radio" id="right-input" class="radio">
<div id="content_button_right" style="width:100%" class="content">
blabla 2
</div>
</div>
Using a checkbox for a css toggle, this code works... The div disappears when you click the checkbox...
input:checked ~ #test{display:none}
<div id="main">
<input type="checkbox">Click Me
<div id="test">This is a test</div>
</div>
But here, it doesn't work, because the TEST div is not a sibling, right? It's outside of the main div...
input:checked ~ #test{display:none}
<div id="main">
<input type="checkbox">Click Me
</div>
<div id="test">This is a test</div>
Is there a way to make this work with just css? I thought if I remove the ~ then any div with an ID = TEST would disappear no matter where it is, but that's not the case.
well this kind of works
the trigger is inside your main but the actual checkbox must be on the same level as "test"
#main {white-space:nowrap;}
#check {
display:none;
}
p {display:inline-block;}
.fake{
display:inline-block;
width: 10px;
height: 10px;
background:lightgray;
}
#check[type=checkbox]:checked + #main + #test {
display:none;
}
#check[type=checkbox]:checked + #main > label {
background: gray;
}
<input id="check" type="checkbox">
<div id="main">
<label class="fake" for="check"></label>
<p>Click Me</p>
</div>
<div id="test">This is a test</div>
I have two siblings div where there are more divs contained inside, like this:
<div class="btn_lists">
<div class="btn green_btn">
<img src="<?= asset_url() ?>images/escolar_07__1.png" />
</div>
</div>
<div class="btn-desc-container">
<div class="btn-desc_1">
<p>Description</p>
</div>
</div>
By default I have btn-desc_1 with display: none;
I want that hovering green_btn applies display: inline-block; on btn-desc_1
How could I do this efficiently?
There is no way to achieve this via CSS. Use jquery piece of code:
$('.green_btn').hover(function(){
$('.btn-desc_1').toggleClass('display-inline');
})
like the demo: http://jsfiddle.net/nidzix/sWQr9/3/
Horroristic almost-answer. Probably very unreliable. It is only for demonstration, don't use it. Instead of hovering it works with clicking on the images:
:checked is supported only with IE9+: https://developer.mozilla.org/en-US/docs/Web/CSS/:checked
Live example, click the kittens: http://jsfiddle.net/bzH7S/2/
<body>
<input type="radio" name="btn" value="1" id="radio1">
<input type="radio" name="btn" value="2" id="radio2">
<div id="wrap">
<div class="btn_lists">
<label for="radio1" class="btn btn1"><img src="1"></label>
<label for="radio2" class="btn btn2"><img src="2"></label>
</div>
<div class="btn-desc-container">
<div class="btn-desc_1"><p>Kitten One</p></div>
<div class="btn-desc_2"><p>Kitten Second</p></div>
</div>
</div>
</body>
CSS:
body > input {
display: none;
}
.btn-desc-container > div {
display: none;
}
#radio1:checked ~ #wrap .btn-desc_1,
#radio2:checked ~ #wrap .btn-desc_2 {
display: block;
}
There's no way to do this unless btn_desc1 is a child of green_btn, in which this would work:
.green_btn:hover > .btn-desc_1
{
display:inline-block;
}
with this HTML:
<div class="btn_lists">
<div class="btn green_btn">
<img width='400px' heigh='400px' src="http://www.pieisgood.org/images/slice.jpg" />
<div class="btn-desc_1">
<p>Description</p>
</div>
</div>
in your CSS. However, you could use JQuery for this to reach your goal, like nidzik says:
$('.green_btn').hover(function(){
$('.btn-desc_1').toggleClass('display-inline');
})
Here's the demo
I have very basic and known scenario of form where I need to align labels next to inputs correctly. However I don't know how to do it.
My goal would be that labels are aligned next to inputs to the right side. Here is picture example of desired result.
I have made a fiddle for your convenience and to clarify what I have now - http://jsfiddle.net/WX58z/
Snippet:
<div class="block">
<label>Simple label</label>
<input type="text" />
</div>
<div class="block">
<label>Label with more text</label>
<input type="text" />
</div>
<div class="block">
<label>Short</label>
<input type="text" />
</div>
WARNING: OUTDATED ANSWER
Nowadays you should definitely avoid using fixed widths. You could use flexbox or CSS grid to come up with a responsive solution. See the other answers.
One possible solution:
Give the labels display: inline-block;
Give them a fixed width
Align text to the right
That is:
label {
display: inline-block;
width: 140px;
text-align: right;
}
<div class="block">
<label>Simple label</label>
<input type="text" />
</div>
<div class="block">
<label>Label with more text</label>
<input type="text" />
</div>
<div class="block">
<label>Short</label>
<input type="text" />
</div>
JSFiddle
While the solutions here are workable, more recent technology has made for what I think is a better solution. CSS Grid Layout allows us to structure a more elegant solution.
The CSS below provides a 2-column "settings" structure, where the first column is expected to be a right-aligned label, followed by some content in the second column. More complicated content can be presented in the second column by wrapping it in a <div>.
[As a side-note: I use CSS to add the ':' that trails each label, as this is a stylistic element - my preference.]
/* CSS */
div.settings {
display:grid;
grid-template-columns: max-content max-content;
grid-gap:5px;
}
div.settings label { text-align:right; }
div.settings label:after { content: ":"; }
<!-- HTML -->
<div class="settings">
<label>Label #1</label>
<input type="text" />
<label>Long Label #2</label>
<span>Display content</span>
<label>Label #3</label>
<input type="text" />
</div>
Answered a question such as this before, you can take a look at the results here:
Creating form to have fields and text next to each other - what is the semantic way to do it?
So to apply the same rules to your fiddle you can use display:inline-block to display your label and input groups side by side, like so:
CSS
input {
margin-top: 5px;
margin-bottom: 5px;
display:inline-block;
*display: inline; /* for IE7*/
zoom:1; /* for IE7*/
vertical-align:middle;
margin-left:20px
}
label {
display:inline-block;
*display: inline; /* for IE7*/
zoom:1; /* for IE7*/
float: left;
padding-top: 5px;
text-align: right;
width: 140px;
}
updated fiddle
I use something similar to this:
<div class="form-element">
<label for="foo">Long Label</label>
<input type="text" name="foo" id="foo" />
</div>
Style:
.form-element label {
display: inline-block;
width: 150px;
}
I know this is an old thread but an easier solution would be to embed an input within the label like so:
<label>Label one: <input id="input1" type="text"></label>
You can also try using flex-box
<head><style>
body {
color:white;
font-family:arial;
font-size:1.2em;
}
form {
margin:0 auto;
padding:20px;
background:#444;
}
.input-group {
margin-top:10px;
width:60%;
display:flex;
justify-content:space-between;
flex-wrap:wrap;
}
label, input {
flex-basis:100px;
}
</style></head>
<body>
<form>
<div class="wrapper">
<div class="input-group">
<label for="user_name">name:</label>
<input type="text" id="user_name">
</div>
<div class="input-group">
<label for="user_pass">Password:</label>
<input type="password" id="user_pass">
</div>
</div>
</form>
</body>
</html>
You can do something like this:
HTML:
<div class='div'>
<label>Something</label>
<input type='text' class='input'/>
<div>
CSS:
.div{
margin-bottom: 10px;
display: grid;
grid-template-columns: 1fr 4fr;
}
.input{
width: 50%;
}
Hope this helps ! :)
Here is generic labels width for all form labels. Nothing fix width.
call setLabelWidth calculator with all the labels.
This function will load all labels on UI and find out maximum label width.
Apply return value of below function to all the labels.
this.setLabelWidth = function (labels) {
var d = labels.join('<br>'),
dummyelm = jQuery("#lblWidthCalcHolder"),
width;
dummyelm.empty().html(d);
width = Math.ceil(dummyelm[0].getBoundingClientRect().width);
width = width > 0 ? width + 5: width;
//this.resetLabels(); //to reset labels.
var element = angular.element("#lblWidthCalcHolder")[0];
element.style.visibility = "hidden";
//Removing all the lables from the element as width is calculated and the element is hidden
element.innerHTML = "";
return {
width: width,
validWidth: width !== 0
};
};