Tab system with pure CSS, anchor avoids the propagation to label - html

I'm making a tab system only with CSS using :target and :checked pseudoclasses, but I have an anchor inside the label, and the label doesn't trigger the :checked.
If you click in the anchor, the :checked doesn't trigger because the click is in the <a> tag, but is inside a <label> that must trigger the radio button. If you click on the border of the tab, you'll see how it triggers the :checked, but not the anchor, so the :target can't be triggered.
Here you are my code, more understandable than the words:
a {
text-decoration: none;
}
.tabs {
position: relative;
}
input {
display: none;
}
.tabs .tab label {
text-decoration: none;
border: 1px solid black;
padding: 2px;
display: inline-block;
top: 2px;
position: relative;
cursor: pointer;
}
.tabs .tab input:checked + label {
background-color: white;
border-bottom: 0;
padding: 4px 2px;
top: 1px;
}
.contents {
border: 1px solid black;
background-color: white;
}
.contents .content {
display: none;
padding: 20px;
}
.contents .content:target {
display: block;
}
<div class="tabs">
<span class="tab">
<input type="radio" name="ch" id="check1">
<label for="check1">
Tab 1
</label>
</span>
<span class="tab">
<input type="radio" name="ch" id="check2">
<label for="check2">
Tab 2
</label>
</span>
<span class="tab">
<input type="radio" name="ch" id="check3">
<label for="check3">
Tab 3
</label>
</span>
</div>
<div class="contents">
<div class="content" id="tab1">Contenido 1</div>
<div class="content" id="tab2"><strong>Contenido 2</strong></div>
<div class="content" id="tab3"><em>Contenido 3</em></div>
</div>
Is there a way to combine :checked and :target pseudoclasses to achieve a complete tab system only with CSS?
Thank you.
EDIT
Here you are the snippet without anchor. Obviously the :target will not be triggered:
a {
text-decoration: none;
}
.tabs {
position: relative;
}
input {
display: none;
}
.tabs .tab label {
text-decoration: none;
border: 1px solid black;
padding: 2px;
display: inline-block;
top: 2px;
position: relative;
cursor: pointer;
}
.tabs .tab input:checked + label {
background-color: white;
border-bottom: 0;
padding: 4px 2px;
top: 1px;
}
.contents {
border: 1px solid black;
background-color: white;
}
.contents .content {
display: none;
padding: 20px;
}
.contents .content:target {
display: block;
}
<div class="tabs">
<span class="tab">
<input type="radio" name="ch" id="check1">
<label for="check1">
Tab 1
</label>
</span>
<span class="tab">
<input type="radio" name="ch" id="check2">
<label for="check2">
Tab 2
</label>
</span>
<span class="tab">
<input type="radio" name="ch" id="check3">
<label for="check3">
Tab 3
</label>
</span>
</div>
<div class="contents">
<div class="content" id="tab1">Contenido 1</div>
<div class="content" id="tab2"><strong>Contenido 2</strong></div>
<div class="content" id="tab3"><em>Contenido 3</em></div>
</div>

When you use input:checked, :target is not efficient cause this event is not triggered at all.
You need to put your input ahead in the flow so you can use the selector ~ to select any sibblings and their children following in the flow of the document:
example
a {
text-decoration: none;
}
.tabs {
position: relative;
}
input {
display: none;
}
.tabs .tab label {
text-decoration: none;
border: 1px solid black;
padding: 2px;
display: inline-block;
top: 2px;
position: relative;
cursor: pointer;
}
#check1:checked ~ .tabs label[for="check1"],
#check2:checked ~ .tabs label[for="check2"],
#check3:checked ~ .tabs label[for="check3"] {
background-color: white;
border-bottom: 0;
padding: 4px 2px;
top: 1px;
}
.contents {
border: 1px solid black;
background-color: white;
}
.contents .content {
display: none;
padding: 20px;
}
#check1:checked ~ .contents #tab1,
#check2:checked ~ .contents #tab2,
#check3:checked ~ .contents #tab3 {
display: block;
}
<!-- begin hidden inputs for CSS tabs purpose -->
<input type="radio" name="ch" id="check1">
<input type="radio" name="ch" id="check2">
<input type="radio" name="ch" id="check3">
<!-- End hidden inputs for CSS tabs purpose -->
<div class="tabs">
<span class="tab">
<label for="check1">
Tab 1
</label>
</span>
<span class="tab">
<label for="check2">
Tab 2
</label>
</span>
<span class="tab">
<label for="check3">
Tab 3
</label>
</span>
</div>
<div class="contents">
<div class="content" id="tab1">Contenido 1</div>
<div class="content" id="tab2"><strong>Contenido 2</strong>
</div>
<div class="content" id="tab3"><em>Contenido 3</em>
</div>
</div>

This behavior is specified in HTML5 (emphasis mine):
The activation behavior of a label element for events
targeted at interactive content descendants of a label
element, and any descendants of those interactive content
descendants, must be to do nothing.
Since the link is interactive content, clicking on it won't check the labeled radio input.

Related

Radio Button Method - HTML Accordion

I would like some assistance with my accordion code,
My idea is to get something like this:
The Radio Button Method adds a hidden radio input and a label tag to each accordion tab.
The logic is straightforward:
when a user selects a tab, they essentially check the radio button associated with that tab.
when a user clicks the next tab in the accordion, the next radio button is selected, and so on.
Only one tab can be open at a time using this method.
I'd like some advice on how to incorporate this into my current accordion code.
<!doctype html>
<html>
<head>
<style>
input {
display: none;
}
label {
display: block;
padding: 8px 22px;
margin: 0 0 1px 0;
cursor: pointer;
background: #6AAB95;
border-radius: 3px;
color: #FFF;
transition: ease .5s;
position: relative; /* ADDING THIS IS REQUIRED */
}
label:hover {
background: #4E8774;
}
label::after {
content: '+';
font-size: 22px;
font-weight: bold;
position: absolute;
right: 10px;
top: 2px;
}
input:checked + label::after {
content: '-';
right: 14px;
top: 3px;
}
.content {
background: #E2E5F6;
padding: 10px 25px;
border: 1px solid #A7A7A7;
margin: 0 0 1px 0;
border-radius: 3px;
}
input + label + .collapse {
display: none;
}
input:checked + label + .collapse {
display: block;
}
</style>
</head>
<body>
<input type="checkbox" id="title1" />
<label for="title1">Accordion 1</label>
<div class="collapse">
<p>Your content goes here inside this division with the class "content".</p>
</div>
<input type="checkbox" id="title2" />
<label for="title2">Accordion 2</label>
<div class="collapse">
<p>Your content goes here inside this division with the class "content".</p>
</div>
</body>
</html>
No need to change the CSS (at least the part handling the accordion functionality) but you'd have to change a bit in your HTML.
To get the desired accordion effect where only one tab can be open at a time you should:
use radio buttons instead of checkboxes (input[type="radio"]).
And the important part is to give those radio buttons the same name (the attribute name must be the same for all the accordion component's radio buttons) in order to achieve the desired outcome.
Here's a a live demo:
/** nothing changed on the CSS part, see the HTML part for the required changes */
input {
display: none;
}
label {
display: block;
padding: 8px 22px;
margin: 0 0 1px 0;
cursor: pointer;
background: #6AAB95;
border-radius: 3px;
color: #FFF;
transition: ease .5s;
position: relative;
/* ADDING THIS IS REQUIRED */
}
label:hover {
background: #4E8774;
}
label::after {
content: '+';
font-size: 22px;
font-weight: bold;
position: absolute;
right: 10px;
top: 2px;
}
input:checked+label::after {
content: '-';
right: 14px;
top: 3px;
}
.content {
background: #E2E5F6;
padding: 10px 25px;
border: 1px solid #A7A7A7;
margin: 0 0 1px 0;
border-radius: 3px;
}
input+label+.collapse {
display: none;
}
input:checked+label+.collapse {
display: block;
}
<!-- changed "type=checkbox" to "type=radio" -->
<!-- added the same "name" attribute value for all the radio buttons -->
<input type="radio" name="radio-btn" id="title1" />
<label for="title1">Accordion 1</label>
<div class="collapse">
<p>Your content goes here inside this division with the class "content".</p>
</div>
<!-- changed "type=checkbox" to "type=radio" -->
<!-- added the same "name" attribute value for all the radio buttons -->
<input type="radio" name="radio-btn" id="title2" />
<label for="title2">Accordion 2</label>
<div class="collapse">
<p>Your content goes here inside this division with the class "content".</p>
</div>
CAUTION: Even though the radio buttons hack works as needed, there is no way you can close all the accordion items after interacting for the first time (you can have a closed accordion initially though).
I have found this example using Sass that looks exactly like what you need: https://codepen.io/alvarotrigo/pen/dyJbqpd.
The example uses radio buttons, such as <input type="radio" id="title1" name="select"/>. Because they have the same name, you can only select one at a time.
In your example, you have checkboxes like in this example at w3schools.com. Using checkboxes, you can tick any number of checkboxes at a time, therefore the current accordion behavior.
Here's a stripped-down version (converted to CSS):
input {
position: absolute;
opacity: 0;
z-index: -1;
}
.tab {
overflow: hidden;
}
.tab-label {
display: flex;
justify-content: space-between;
padding: 1em;
background: #2c3e50;
color: white;
cursor: pointer;
}
.tab-content {
max-height: 0;
padding: 0 1em;
color: #2c3e50;
background: white;
}
input:checked ~ .tab-content {
max-height: 100vh;
padding: 1em;
}
<div class="tab">
<input type="radio" id="rd1" name="rd">
<label class="tab-label" for="rd1">Item 1</label>
<div class="tab-content">Content</div>
</div>
<div class="tab">
<input type="radio" id="rd2" name="rd">
<label class="tab-label" for="rd2">Item 2</label>
<div class="tab-content">Content</div>
</div>
I have slightly changed your code and added another div with overflow: hidden:
/** nothing changed on the CSS part, see the HTML part for the required changes */
input {
display: none;
}
label {
display: block;
padding: 8px 22px;
margin: 0 0 1px 0;
cursor: pointer;
background: #6AAB95;
border-radius: 3px;
color: #FFF;
transition: ease .5s;
position: relative;
/* ADDING THIS IS REQUIRED */
}
label:hover {
background: #4E8774;
}
label::after {
content: '+';
font-size: 22px;
font-weight: bold;
position: absolute;
right: 10px;
top: 2px;
}
input:checked+label::after {
content: '-';
right: 14px;
top: 3px;
}
.content {
background: #E2E5F6;
padding: 10px 25px;
border: 1px solid #A7A7A7;
margin: 0 0 1px 0;
border-radius: 3px;
}
input+label+.collapse {
display: none;
}
input:checked+label+.collapse {
display: block;
}
<div class="tab">
<input type="radio" id="title1" name="select"/>
<label for="title1">Accordion 1</label>
<div class="collapse">
Your content goes here inside this division with the class "content".
</div>
</div>
<div class="tab">
<input type="radio" id="title2" name="select" />
<label for="title2">Accordion 2</label>
<div class="collapse">
Your content goes here inside this division with the class "content".
</div>
</div>

How to include Vertical menu for tabs in HTML

I need to have vertical menu whenever I click each of my tab and show some items...When one item is clicked I need to see the content under each item. Here is the output I need..
So I have used below code but I have no idea about the menu items under each item.
body {
background: #ccc;
font-family: 'Roboto', sans-serif;
}
.mytabs {
display: flex;
flex-wrap: wrap;
max-width: 600px;
margin: 50px auto;
padding: 25px;
}
.mytabs input[type="radio"] {
display: none;
}
.mytabs label {
padding: 25px;
background: #e2e2e2;
font-weight: bold;
}
.mytabs .tab {
width: 100%;
padding: 20px;
background: #fff;
order: 1;
display: none;
}
.mytabs .tab h2 {
font-size: 3em;
}
.mytabs input[type='radio']:checked + label + .tab {
display: block;
}
.mytabs input[type="radio"]:checked + label {
background: #fff;
}
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght#400;700&display=swap" rel="stylesheet">
<body>
<div class="mytabs">
<input type="radio" id="tab1" name="mytabs" checked="checked">
<label for="tab1">Free</label>
<div class="tab">
<h2>tab1</h2>
</div>
<input type="radio" id="tab2" name="mytabs">
<label for="tab2">Silver</label>
<div class="tab">
<h2>tab2</h2>
</div>
<input type="radio" id="tab3" name="mytabs">
<label for="tab3">Gold</label>
<div class="tab">
<h2>tab3</h2>
</div>
</div>
</body>
At the moment I could get the tabbed layout without items menu. Can someone show me how to improve my code?

Css :checked showing containers that shold be hidden

I am trying to do simple Tabs on my page, so I have 3 tabs and 3 sections for them. Problem is that in first section i can see all sections containers, in second 2 last and in this last. And it should be simple one section for one tab.
What am i missing?
My html and code https://codepen.io/wojsza/pen/XWMOXXm :
.display__tabs {
display: flex;
flex-wrap: wrap; }
.display__tabs--tab {
display: none; }
.display__tabs--tab:checked ~ .display__tabs--label ~ .display__tabs--content {
display: block; }
.display__tabs--label {
cursor: pointer;
padding: 25px;
color: #2e2e2e; }
.display__tabs--label:hover {
color: #aeaeae;
background-color: #2e2e2e;
font-weight: bold;
text-decoration: underline; }
.display__tabs--content {
width: 100%;
padding: 20px;
order: 1;
display: none; }
and html:
<div class="display__tabs">
<input type="radio" class="display__tabs--tab" id="display-module-info" name="module" checked="checked" />
<label class="display__tabs--label" for="display-module-info">Info</label>
<div class="display__tabs--content">
<p>Module</p>
</div>
<input type="radio" class="display__tabs--tab" id="display-module-wsu" name="module" />
<label for="display-module-wsu" class="display__tabs--label">Wsu</label>
<div class="display__tabs--content">
<p>
WSU
</p>
</div>
<input type="radio" class="display__tabs--tab" id="display-module-sections" name="module" />
<label for="display-module-sections" class="display__tabs--label">Sections</label>
<div class="display__tabs--content">
<p>
SECTION
</p>
</div>
</div>
You nearly there! Just need to change the "~" into "+".
You wanna change your css on this part :
From
.display__tabs--tab:checked ~ .display__tabs--label ~ .display__tabs--content {
display: block;
}
To
.display__tabs--tab:checked + .display__tabs--label + .display__tabs--content {
display: block;
}
This caused by the css selector of ~ which select the general sibling, and you wanted to use +, because the radio element that being set to hidden and block, is adjacent sibling. Reference https://levelup.gitconnected.com/understanding-use-of-the-and-symbols-in-css-selectors-95552eb436f5
You can just add a second class to radio inputs, and display__tabs--content. Then, you can just add CSS for each one of them.
.display__tabs {
display: flex;
flex-wrap: wrap;
}
.display__tabs--tab {
display: none;
}
.tab1:checked ~ .display__tabs--label ~ .display__tabs--content.content1 {
display: block;
}
.tab2:checked ~ .display__tabs--label ~ .display__tabs--content.content2 {
display: block;
}
.tab3:checked ~ .display__tabs--label ~ .display__tabs--content.content3 {
display: block;
}
.display__tabs--label {
cursor: pointer;
padding: 25px;
color: #2e2e2e;
}
.display__tabs--label:hover {
color: #aeaeae;
background-color: #2e2e2e;
font-weight: bold;
text-decoration: underline;
}
.display__tabs--content {
width: 100%;
padding: 20px;
order: 1;
display: none;
}
<div class="display__tabs">
<input type="radio" class="display__tabs--tab tab1" id="display-module-info" name="module" checked="checked" />
<label class="display__tabs--label" for="display-module-info">Info</label>
<div class="display__tabs--content content1">
<p>Module</p>
</div>
<input type="radio" class="display__tabs--tab tab2" id="display-module-wsu" name="module" />
<label for="display-module-wsu" class="display__tabs--label">Wsu</label>
<div class="display__tabs--content content2">
<p>
WSU
</p>
</div>
<input type="radio" class="display__tabs--tab tab3" id="display-module-sections" name="module" />
<label for="display-module-sections" class="display__tabs--label">Sections</label>
<div class="display__tabs--content content3">
<p>
SECTION
</p>
</div>
</div>

How to create material design input form using css and bootstrap?

I want to design following material design input form using css and bootstrap. Following code is I am currently using. But it doesn't provide exact result I want.
Code Pen Link : View Source Code Here
HTML CODE :
<div class="container">
<h2>Google Material Design in CSS3<small>Inputs</small></h2>
<form>
<div class="group">
<input type="text" required>
<span class="highlight"></span>
<span class="bar"></span>
<label>Name</label>
</div>
<div class="group">
<input type="text" required>
<span class="highlight"></span>
<span class="bar"></span>
<label>Email</label>
</div>
</form>
<p class="footer">
a tutorial by scotch.io
</p>
</div>
But I want this design :
CSS Only solution; use combination of sibling selector ~ on the label and :valid pseudo selector on the input.
body {
margin: 10px;
}
.form-group>label {
bottom: 34px;
left: 15px;
position: relative;
background-color: white;
padding: 0px 5px 0px 5px;
font-size: 1.1em;
transition: 0.2s;
pointer-events: none;
}
.form-control:focus~label {
bottom: 55px;
}
.form-control:valid~label {
bottom: 55px;
}
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css">
<div class="container">
<div class="row">
<div class="col-md-6">
<br>
<div class="form-group">
<input type="text" class="form-control" id="usr" required>
<label for="usr">Name</label>
</div>
<div class="form-group">
<input type="text" class="form-control" id="password" required>
<label for="usr">Password</label>
</div>
</div>
</div>
</div>
Since you've tagged Bootstrap 4, I'm assuming you wanted the solution with regards to that framework.
Setup a default form-group, label, and input markup like this;
<div class="form-group">
<label for="usr">Name:</label>
<input type="text" class="form-control" id="usr">
</div>
Then add this css, what this would do is
position label relative to its container (form-group)
then we specified the top and left positions so that it would land
on top of the input field
I added a white background and padding to the label so that it would have a box around the label.
.form-group > label {
top: 18px;
left: 6px;
position: relative;
background-color: white;
padding: 0px 5px 0px 5px;
font-size: 0.9em;
}
Here's a fiddle with that code on bootstrap 4;
http://jsfiddle.net/rw29jot4/
For the animation, check this fiddle, we need to utilize click events and move the position of the label;
Updated code with animation;
http://jsfiddle.net/sedvo037/
EDIT: Please see my answer below which uses only CSS.
Try with this code.
HTML:
<div class="main_div">
<div class="group">
<input type="text" required="required"/>
<label>Name</label>
</div>
</div>
CSS:
.main_div{
padding: 30px;
}
input,
textarea {
background: none;
color: #c6c6c6;
font-size: 18px;
padding: 10px 10px 10px 15px;
display: block;
width: 320px;
border: none;
border-radius: 10px;
border: 1px solid #c6c6c6;
}
input:hover{
border: 3px solid black;
}
input:focus,
textarea:focus {
outline: none;
border: 3px solid black;
}
input:focus ~ label, input:valid ~ label,
textarea:focus ~ label,
textarea:valid ~ label {
top: -5px;
font-size: 12px;
color: #000;
left: 11px;
}
input:focus ~ .bar:before,
textarea:focus ~ .bar:before {
width: 320px;
}
input[type="password"] {
letter-spacing: 0.3em;
}
.group{
position: relative;
}
label {
color: #c6c6c6;
font-size: 16px;
font-weight: normal;
position: absolute;
pointer-events: none;
left: 15px;
top: 12px;
transition: 300ms ease all;
background-color: #fff;
padding: 0 2px;
}

Pure CSS change styling of div element with checkbox

I'm trying to toggle the CSS of a sibling by using the checked state of a sibling checkbox.
Is it possible to target elements anywhere on the page from the checked pseudo class from a checkbox?
I'm trying to avoid using any javascript.
https://codepen.io/dyk3r5/pen/WOmxpV?editors=1111
html,
body {
height: 100%;
}
.container {
height: 100%;
display: flex;
justify-content: center;
}
label {
color: #000;
font-weight: 600;
height: 25px;
padding: 5px 10px;
border-bottom: 2px solid lightgrey;
margin: 5px 1px;
}
input[type="radio"] {
display: none;
}
input[type="radio"]:checked + label {
border-bottom: 2px solid red;
}
input[type="radio"]:checked > div p {
display: none;
}
<div class="container">
<div id="new-account">
<input type="radio" id="opt1" name="radiolist" checked>
<label for='opt1'>New Account</label>
<div class="content">
<p>Lorem Ipsum</p>
</div>
</div>
<div id="existing-account">
<input type="radio" id="opt2" name="radiolist">
<label for='opt2'>Existing Account</label>
<div class="content">
<p>Lorem Ipsum 2</p>
</div>
</div>
</div>
Your mistake is in this line:
input[type="radio"]:checked > div p
your div element is not a "direct children" of input element. What you need here is "general sibling selector" to address any following div sibling.
So it should be:
input[type="radio"]:checked ~ div p
Use css like
input[type="radio"]:checked + label + .content p {
display: none;
}