CSS only tabs using input:checked - html

I found this example (the "checked" version) and it works:
http://jsfiddle.net/2cTwA/
But I want to wrap the input and labels inside a container element (like nav), and if I do that the tabs stop working :(
Is there any solution for this?
found solution: http://jsfiddle.net/2cTwA/7/

With a slight HTML and CSS modification - DEMO
CSS
input { display: none; }
nav { overflow: hidden }
label { float: left; display: inline-block; padding: 5px 10px; }
label a { color: #d33; text-decoration: underline; cursor: pointer; }
.tab { display: none; border: 1px solid #333; padding: 10px; }
a[name="tab1"] + .tab { display: block }
:target + .tab { display: block }
:target ~ a[name="tab1"] + .tab { display: none }
HTML
<section class="tab-area tabs-checked">
<nav>
<input checked type="radio" name="tab" id="tab-A" />
<input type="radio" name="tab" id="tab-B" />
<input type="radio" name="tab" id="tab-C" />
<label class="tab-link" for="tab-A">Tab 1</label>
<label class="tab-link" for="tab-B">Tab 2</label>
<label class="tab-link" for="tab-C">Tab 3</label>
</nav>
<a name="tab3"></a>
<article class="tab">
<h3>Tab 3</h3>
</article>
<a name="tab2"></a>
<article class="tab">
<h3>Tab 2</h3>
</article>
<a name="tab1"></a>
<article class="tab">
<h3>Tab 1.</h3>
</article>
</section>

You're using the sibling selector (~), and by using a containing element such as nav, you are removing the inputs and labels from being siblings of the articles.
You simply need to rewrite your css where you use the tilde.

here is the sass example for 12(max) tabs using CSS only
.tabs {
input[type=radio] {
display: none;
#for $i from 1 through 12 {
&:nth-of-type(#{$i}):checked ~ .content .tab:nth-child(#{$i}) {
display: block;
}
}
}
label {
cursor: pointer;
display: inline-block;
}
.tab {
display: none;
}
}
and here is the html markup
<div class="tabs">
<input name="controls" type="radio" id="controls-tab" checked="true"/>
<label for="controls-tab">controls</label>
<input name="controls" type="radio" id="panels-tab"/>
<label for="panels-tab">panels</label>
<input name="controls" type="radio" id="readme-tab"/>
<label for="readme-tab">readme</label>
<div class="content">
<div class="tab">
</div>
<div class="tab">
</div>
<div class="tab">
</div>
</div>
</div>
no need to relatively position tab divs inside content div. no need to set content height.

Related

How to implement line-through using css to custom checkbox?

---------------------------------HTML code----------------------------------------
<label class="round">
<input type="checkbox" id="round-checkbox" class="check-btn">
<span></span>
</label>
<label for="round-checkbox" id="task-text" >Hello Smple TEXT</label>
-----------------------------------------CSS code-----------------------------------------------
.round input:checked+label{
text-decoration: line-through;
}
I tried the above approach but it is not working...
First of all, I think you should read what the label tag is used for (why do you have 2 labels for the same field?).
Then, with a "cleaner" HTML, it becomes easier:
<label>
<input type="checkbox" name="box" class="box">
<span class="label-text">label text</span>
</label>
.box {
display: none;
}
.box:checked ~ .label-text {
text-decoration: line-through;
}
Now you got the idea, you can adapt to "custom" checkbox:
<label>
<input type="checkbox" name="box" class="box">
<span class="custom-box"></span>
<span class="label-text">label text</span>
</label>
.box {
display: none;
}
.custom-box {
display: inline-block;
width: 1em;
height: 1em;
background: green;
}
.box:checked ~ .custom-box {
background: red;
}
.box:checked ~ .label-text {
text-decoration: line-through;
}

How to enable two radioboxes when clicking one label?

I want to implement a page control which does not use javascript. The idea is to use the input:checked + <element> selector. Showing only the selected page is no problem, but it seems not to be possible to have both: active tab and page.
May be it is possible to activate two radiobuttons at once with a label without using javascript?
input {
position: absolute;
width: 0;
height: 0;
}
.tabs {
display: flex;
}
.tabs > label,
.pages {
padding: 10px;
background-color: #eee;
border: 1px solid #ddd;
}
.tabs > input:checked + label {
background-color: green;
}
.tabs > label {
border-bottom: none;
border-right-width: 0;
}
.tabs > label:last-child {
border-right-width: 1px;
}
.pages > div {
display: none;
}
.pages > input:checked + div {
display: block;
}
<div class="tabs">
<input type="radio" name="tab" id="tab1" checked="checked">
<label for="page1">First Tab</label>
<input type="radio" name="tab" id="tab2">
<label for="page2">Second Tab</label>
<input type="radio" name="tab" id="tab3">
<label for="page3">Third Tab</label>
</div>
<div class="pages">
<input type="radio" name="page" id="page1" checked="checked">
<div>Page Content #1</div>
<input type="radio" name="page" id="page2">
<div>Page Content #2</div>
<input type="radio" name="page" id="page3">
<div>Page Content #3</div>
</div>
The page control itself is working here. But I want to highlight the active tab. Please note: I don't want to use js (it's easy with js). I don't want to use any lib. The html and css structure can be changed in any way to reach the goal.
New solution
I have arranged a new solution which allows to preserve most of your original html structure so you can still use the flex layout, without the need to duplicate the tabs code for each page as in your last update. The main difference is that I've moved the radio inputs in a parent container, so the css rules can match both tabs and pages. You still have to code N css rules, where N must be greater than the maximum number of tabs allowed:
input {
position: absolute;
width: 0;
height: 0;
}
.tabs {
display: flex;
}
.tabs > label, .pages {
padding: 10px;
background-color: #eee;
border: 1px solid #ddd;
}
.tabs > label {
border-bottom: none;
border-right-width: 0;
}
.tabs > label:last-child {
border-right-width: 1px;
}
.pages > div {
display: none;
}
.TabPane>input:checked:nth-child(1)~.tabs>label:nth-child(1) {background-color: green;}
.TabPane>input:checked:nth-child(1)~.pages>div:nth-child(1) {display: block;}
.TabPane>input:checked:nth-child(2)~.tabs>label:nth-child(2) {background-color: green;}
.TabPane>input:checked:nth-child(2)~.pages>div:nth-child(2) {display: block;}
.TabPane>input:checked:nth-child(3)~.tabs>label:nth-child(3) {background-color: green;}
.TabPane>input:checked:nth-child(3)~.pages>div:nth-child(3) {display: block;}
<div class="TabPane">
<input type="radio" name="tab" id="tab1" checked="checked">
<input type="radio" name="tab" id="tab2">
<input type="radio" name="tab" id="tab3">
<div class="tabs">
<label for="tab1">First Tab</label>
<label for="tab2">Second Tab</label>
<label for="tab3">Third Tab</label>
</div>
<div class="pages">
<div>Page Content #1</div>
<div>Page Content #2</div>
<div>Page Content #3</div>
</div>
</div>
Old solution
The problem with css selectors is that they allow to select only children and sibling elements; since your tabs and pages belong to different containers then there is no way to connect them using pure css selectors. A solution could be to reorganize the html structure to have both elements within the same container. The following code works as long you define enough rules to handle up to n tabs:
input {
position: absolute;
width: 0;
height: 0;
}
.tabs > label, .tabs > div {
padding: 10px;
background-color: #eee;
border: 1px solid #ddd;
}
.tabs > input:checked + label {
background-color: green;
}
.tabs > label {
border-bottom: none;
border-right-width: 0;
}
.tabs > label:last-of-type {
border-right-width: 1px;
}
.tabs > div {
display: none;
}
.tabs > input#tab1:checked ~ div#page1 {display: block;}
.tabs > input#tab2:checked ~ div#page2 {display: block;}
.tabs > input#tab3:checked ~ div#page3 {display: block;}
<div class="tabs">
<input type="radio" name="tab" id="tab1" checked="checked">
<label for="tab1">First Tab</label>
<input type="radio" name="tab" id="tab2">
<label for="tab2">Second Tab</label>
<input type="radio" name="tab" id="tab3">
<label for="tab3">Third Tab</label>
<div id="page1">Page Content #1</div>
<div id="page2">Page Content #2</div>
<div id="page3">Page Content #3</div>
</div>
Inspired by #Daniels118 solution I've found it. Because label:radiobutton relation is not possible as 1:n, I inverted the relation. So n-labels are pointing to 1 specific radio button.
I repeat all tabs for each page. There is only one difference: The active tab has an active class.
With the input:checked + .tabs and input:checked + .tabs + .page selector only the current tab is visible.
This solution is easier to layout on mobile devices. It's also extendable without changing the css. My widget class will output the tabs automatically for each page.
Because there is only one radio button that is focused by the label the focus just works fine (when having for example input controls in a page).
.tabs,
.page {
display: none;
}
.pages > input {
position: absolute;
width: 0;
height: 0;
}
.tabs > label,
.page {
padding: 10px;
background-color: #eee;
border: 1px solid #ddd;
}
.tabs > label {
border-bottom: none;
border-right-width: 0;
user-select: none;
}
.tabs > label:last-child {
border-right-width: 1px;
}
.tabs > label.active {
background-color: green;
}
.pages > input:checked + .tabs {
display: flex;
}
.pages > input:checked + .tabs + .page {
display: block;
}
.pages > input:focus + .tabs > .active {
text-decoration: underline;
}
<div class="pages">
<input type="radio" name="page" id="page1" checked="checked">
<div class="tabs">
<label for="page1" class="active">First Tab</label>
<label for="page2">Second Tab</label>
<label for="page3">Third Tab</label>
</div>
<div class="page">Page Content #1</div>
<input type="radio" name="page" id="page2">
<div class="tabs">
<label for="page1">First Tab</label>
<label for="page2" class="active">Second Tab</label>
<label for="page3">Third Tab</label>
</div>
<div class="page">Page Content #2</div>
<input type="radio" name="page" id="page3">
<div class="tabs">
<label for="page1">First Tab</label>
<label for="page2">Second Tab</label>
<label for="page3" class="active">Third Tab</label>
</div>
<div class="page">Page Content #3<br /><input type="text" placeholder="To test the focus" /></div>
</div>

Can I affect an element outside the div I am currently in purely with CSS?

Context: I am attempting to use the radio hack to toggle what text is viewed within the .tabinfo div, but my radios and the text whose display attribute I want to change are located in different divs.
Problem: Is it possible to use pure CSS selectors to select the #text element by clicking on a nested radio?
Reference Code: I am using the bootstrap layout and have created the following HTML code:
<div class="col-xs-2">
<input id="tab1" type="radio" name="tabs">
<label for="tab1">Foo</label>
</div>
<div class="col-xs-2">
<input id="tab2" type="radio" name="tabs">
<label for="tab2">Bar</label>
</div>
<div class="col-xs-2">
<input id="tab3" type="radio" name="tabs" checked>
<label for="tab3">Foo Bar</label>
</div>
<div class="col-xs-12">
<div class="tabinfo">
<div id="text1">
</div>
<div id="text2">
</div>
<div id="text3">
</div>
</div>
</div>
And the following CSS:
label {
border: solid;
border-top-right-radius: 10px;
border-top-left-radius: 10px;
border-bottom: none;
border-color: rgb(211,211,205);
border-width: 2px;
color: rgb(12,174,175);
background-color: rgb(247,247,247);
}
input:checked + label {
background-color: #fff;
color: rgb(94,94,94);
}
label:hover {
cursor: pointer;
}
.tabinfo {
border: solid;
border-color: rgb(211,211,205);
border-width: 2px;
border-top-right-radius: 10px;
}
#tab1:checked ~ .col-xs-12 .tabinfo #text1,
#tab2:checked ~ .col-xs-12 .tabinfo #text2,
#tab3:checked ~ .col-xs-12 .tabinfo #text3 {
display: block!important;
}
As you probably already guessed, the above does not work since the #texts and the #tabs are located in different divs. Is there any workaround or any solution without breaking the Bootstrap layout?
A brittle solution can be used, but this involves moving the <input> elements away from the <label> elements, and you specify one requirement of any HTML changes is that any change
…does not break the [Bootstrap] layout.
I don't think my changes break that layout, but I'm not entirely sure, so you will need to evaluate this yourself.
That preamble aside, however, I've modified your HTML to the following:
<input id="tab1" type="radio" name="tabs" />
<input id="tab2" type="radio" name="tabs" />
<input id="tab3" type="radio" name="tabs" />
<div class="col-xs-2">
<label for="tab1">Foo</label>
</div>
<div class="col-xs-2">
<label for="tab2">Bar</label>
</div>
<div class="col-xs-2">
<label for="tab3">Foo Bar</label>
</div>
<div class="col-xs-12">
<div class="tabinfo">
<div id="text1">
</div>
<div id="text2">
</div>
<div id="text3">
</div>
</div>
</div>
This approach allows us to take advantage of the <label> element's ability to check/uncheck its associated <input> element regardless of where in the document it may be located (so long as the for attribute identifies the id of that associated <input>); placing the <input> elements ahead of the content allows us to use sibling combinators to find the elements containing the relevant content to style.
On the assumption that you wish to retain the visual effect of the <input> being checked, or otherwise, we've also used CSS generated content to emulate a checked or unchecked radio; this could use some fine tuning, though:
/* Here we hide all <div> elements within the .tabinfo
element, and also all <input> elements whose 'name'
attribute is equal to 'tabs' and whose 'type' is
equal to 'radio': */
.tabinfo div,
input[name=tabs][type=radio] {
display: none;
}
/* This styles the generated content of the ::before
pseudo-element to show the attribute-value of the
element's 'id' attribute; purely for the purposes
of this demo: */
div[id^=text]::before {
content: attr(id);
}
/* Styling the generated content, the ::before pseudo-
element, of the <label> elements, in order to
emulate the moved radio <input>: */
label::before {
/* An empty string, content is required in order for
the pseudo-element to be visible on the page: */
content: '';
/* To allow the pseudo-element to have specified
width and height values: */
display: inline-block;
height: 1em;
width: 1em;
/* To include the border, and any padding, widths
in the calculations for the element's size: */
box-sizing: border-box;
background-color: #eee;
border: 1px solid #999;
/* In order for the pseudo-radio to have a round
shape/border: */
border-radius: 50%;
margin-right: 0.2em;
}
/* This selector styles the <label> element whose 'for'
attribute is equal to 'tab1', which is a child of
the div.col-xs-2 element which itself is a general
sibling of the #tab1 element when that element is
checked; this is the 'checked' style of the pseudo-
'radio' generated content: */
#tab1:checked~div.col-xs-2>label[for=tab1]::before {
background-color: #666;
box-shadow: inset 0 0 0 3px #fff;
}
/* This selects the element with an id of 'text1',
inside of a <div> with the class of 'col-xs-12',
which is a general sibling of the '#tab1' element
when that element is checked: */
#tab1:checked~div.col-xs-12 #text1 {
/* Here we make the content of that element visible: */
display: block;
}
#tab2:checked~div.col-xs-2>label[for=tab2]::before {
background-color: #666;
box-shadow: inset 0 0 0 3px #fff;
}
#tab2:checked~div.col-xs-12 #text2 {
display: block;
}
#tab3:checked~div.col-xs-2>label[for=tab3]::before {
background-color: #666;
box-shadow: inset 0 0 0 3px #fff;
}
#tab3:checked~div.col-xs-12 #text3 {
display: block;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<input id="tab1" type="radio" name="tabs" />
<input id="tab2" type="radio" name="tabs" />
<input id="tab3" type="radio" name="tabs" />
<div class="col-xs-2">
<label for="tab1">Foo</label>
</div>
<div class="col-xs-2">
<label for="tab2">Bar</label>
</div>
<div class="col-xs-2">
<label for="tab3">Foo Bar</label>
</div>
<div class="col-xs-12">
<div class="tabinfo">
<div id="text1">
</div>
<div id="text2">
</div>
<div id="text3">
</div>
</div>
</div>
JS Fiddle demo.
As you can see from the rules formed to show the elements related to the checked <input> elements those rules require some precision and repetition, since CSS has no concept of this, so, given a data-affectedby attribute whose value might be set to the id of the related <input>, there's no way we can have a rule along the lines of:
input[id^=tab]:checked ~ .col-xs-12 [data-affectedby=this.id]
This will be very difficult (perhaps impossible) when working with divs on different levels.
If you flatten the HTML structure a little you might be able to achieve something close to what you are looking for. Note though, it means getting rid of most of the Bootstrap helper layout divs.
Example HTML:
<input id="tab1" type="radio" name="tabs">
<label for="tab1">Foo</label>
<input id="tab2" type="radio" name="tabs">
<label for="tab2">Bar</label>
<input id="tab3" type="radio" name="tabs" checked>
<label for="tab3">Foo Bar</label>
<div id="text1" class="tabinfo">text1</div>
<div id="text2" class="tabinfo">text2</div>
<div id="text3" class="tabinfo">text3</div>
Example CSS:
label {
border: solid;
border-top-right-radius: 10px;
border-top-left-radius: 10px;
border-bottom: none;
border-color: rgb(211,211,205);
border-width: 2px;
color: rgb(12,174,175);
background-color: rgb(247,247,247);
}
input:checked + label {
background-color: #fff;
color: rgb(94,94,94);
}
label:hover {
cursor: pointer;
}
.tabinfo {
display:none;
}
#tab1:checked ~ #text1{
display:block;
}
#tab2:checked ~ #text2{
display:block;
}
#tab3:checked ~ #text3{
display:block;
}
See the example I made here: https://plnkr.co/edit/DyID8me4bM7VPCI9l6Cg?p=preview

Why radio button in HTML in special division doesn't works?

I have two radio buttons which show/hide divs oh my website. The first radio button controls the visibility of a div. In this div I have another radio button which shows/hides another div. The first radio button works, but when I click on the second one nothing happens.
This is an example of my HTML and CSS code :
HTML :
<body>
<label for="a">B</label><input type="radio" id="a" name="a" value="1">
<div id="B">
<p>Div B</p>
<label for="c">D</label><input type="radio" id="c" name="c" value="1">
</div>
<div id="D">
<p>Div D</p>
</div>
</body>
CSS :
#B
{
float:left;
background-color: green;
width: 150px;
height: 50px;
display: none;
}
#D
{
float:right;
background-color: red;
width: 150px;
height: 50px;
display: none;
}
#a:checked ~ #B
{
display: block;
}
#c:checked ~ #D
{
display: block;
}
I don't understand why the second button does nothing.
Is there a solution without using JS?
Thank you,
As #showdev said, #c is not a sibling of #D so sibling selectors won't works in that case.
If you wants this to work with only CSS you have to change your structure or do this with javascript.
EDIT : I made it works with only CSS and HTML arrangement :
See this fiddle
HTML :
<body>
<label for="a">B</label><input type="radio" id="a" name="a" value="1">
<div id="B">
<p>Div B</p>
</div>
<label for="c">D</label><input type="radio" id="c" name="c" value="1">
<div id="D">
<p>Div D</p>
</div>
</body>
CSS that change :
#a:checked ~ #B
{
display: block;
}
#c:checked ~ #D
{
display: block;
}
label:nth-of-type(2), input:nth-of-type(2) { display: none; clear: both;}
#a:checked ~ label:nth-of-type(2), #a:checked ~ input:nth-of-type(2) {
display: block;
}
You should use javascript, unless you need a restricted solution that doesn't involves js at all.. You can easily solve your problem with an onClick function, like this:
<input type="radio" id="a" name="a" value="1" onclick="somefunctionA()">
<label for="c">D</label><input type="radio" id="c" name="c" value="1" onclick="somefunctionB()">
<script>
function somefunctionA(){
//do something!
}
function somefunctionB(){
//do something!
}
</script>

CSS checkbox hack with non-sibling content

The following CSS checkbox hack works under the assumption that the content is a sibling of the checkbox. When the label is clicked, the content is toggled.
DEMO
<input id="checkbox" type="checkbox" />
<label for="checkbox">
Toggle content
</label>
<div class="content">Content here</div>
#checkbox {
display: none;
}
#checkbox:not(:checked) ~ .content {
display: none;
}
Can the same effect be achieved using CSS only if the content is not a sibling of the checkbox? For example:
<div>
<input id="checkbox" type="checkbox" />
<label for="checkbox">
Toggle content
</label>
</div>
<div class="content">Content here</div>
You could do it with the :target pseudo class and using anchors instead of a checkbox. Ugly as hell but CSS only:
a {
color: #000000;
text-decoration: none;
}
#off {
display: none;
}
.content {
display: none;
}
#your-target:target ~ .content {
display: block;
}
#your-target:target #on {
display: none;
}
#your-target:target #off {
display: block;
}
<div id="your-target">
<a id="on" href="#your-target">
Toggle content
</a>
<a id="off" href="#">
Toggle content
</a>
</div>
<div class="content">Content here</div>