Pure CSS tab system that prevents label propagation using anchors

I am in the process of creating a tab system using only CSS with the help of the :target and :checked pseudo classes. However, I have encountered an issue where an anchor inside the label is not triggering the :checked.

When clicking on the anchor, the :checked does not trigger because the click occurs within the <a> tag. The anchor is nested inside a <label> that should be triggering the radio button. Clicking on the border of the tab triggers the :checked but not the anchor, making it impossible to trigger the :target.

Below is my code which provides a clearer understanding:

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">
      <a href="#tab1">Tab 1</a>
    </label>
  </span>
  <span class="tab">
    <input type="radio" name="ch" id="check2">
    <label for="check2">
      <a href="#tab2">Tab 2</a>
    </label>
  </span>
  <span class="tab">
    <input type="radio" name="ch" id="check3">
    <label for="check3">
      <a href="#tab3">Tab 3</a>
    </label>
  </span>
</div>
<div class="contents">
  <div class="content" id="tab1">Content 1</div>
  <div class="content" id="tab2"><strong>Content 2</strong></div>
  <div class="content" id="tab3"><em>Content 3</em></div>
</div>

Is there a way to effectively combine the :checked and :target pseudo classes to create a fully functional tab system using just CSS?

Thank you.

EDIT

Here is a version of the snippet without the anchor. As expected, 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">Content 1</div>
  <div class="content" id="tab2"><strong>Content 2</strong></div>
  <div class="content" id="tab3"><em>Content 3</em></div>
</div>

Answer №1

When utilizing input:checked, it is important to note that :target may not be efficient as this event might not be triggered at all.

To effectively use the selector ~ to select any siblings and their subsequent children in the document flow, you should position your input element ahead in the flow:

For 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">Content 1</div>
  <div class="content" id="tab2"><strong>Content 2</strong>
  </div>
  <div class="content" id="tab3"><em>Content 3</em>
  </div>
</div>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the best way to use CSS to ensure that dynamic, data-driven characters can be properly displayed within a div

I'm in the process of updating a data-centric website that relies on information from an automated database engine. In the HTML, there's a fixed-size button containing text pulled from the database. I'm looking to incorporate some CSS styles ...

What is the solution for resolving the "cannot resolve" issue in CSS for an Angular project?

During a small project I was working on, I decided to add a background image to another image using CSS. Here is the code snippet: .child2 img { width: 200px; height: 200px; border-radius: 50%; background-image: url('./assets/images/imageb ...

incorporate partial html into nodeJS & Jade using AJAX requests

Is there a smart method to load just a segment of a page using Node.js and Jade?: I'm in the process of creating a music blog and I want to incorporate a seamless player at the top of each page. The goal is for the player to keep playing without inte ...

How to Delete the Bottom Border on Selected Tabs in MUI Using React

I am attempting to customize the appearance of MUI Tabs to achieve a design similar to the image below: https://i.sstatic.net/tBS1K.png I have created a sample code example in a codesandbox environment. You can view it here: Codesandbox Example. In this e ...

Guide to implementing Infinite AJAX Scroll in jQuery with a continuous loop

Being a beginner in javascript, I am eager to learn new techniques. I am currently working on implementing an infinite Ajax scroll into my code. Here is a snippet from my php page: <div class="row row-sm padder-lg "> <?php foreach ($top->fee ...

Changing the CSS background in React when updates occur

Currently working on toggling the CSS background image within this React application. The images have been successfully imported and a variable called "image" is set to the imported image as the iteration increases/decreases with each click. The issue I&a ...

Hide the Bootstrap slide menu with jQuery by clicking anywhere on the screen

Here is a Fiddle link: https://jsfiddle.net/r94dq2e4/ I have incorporated a slide-in menu from the left in my website using Twitter Bootstrap version 3. The menu appears when the navbar toggle button is clicked. This is the jQuery code responsible for ...

What is the best way to add an active class to a clicked menu item that already has a class

I have menu items on the master page, and if users click on that menu item, I want to show it as active. My goal is to append "Active" to the existing class to indicate that it is active. _Layout.cshtml: <div class="menu-items-navigation"> <di ...

Center the navigation links within the navigation block

I am using the startbootstrap-small-business template and customizing it to fit my requirements. I have inserted a new logo which caused me to adjust the height of the navbar to approximately 120px. Now, my goal is to vertically align the links on the righ ...

Is there a way to adjust the position of ::before elements without affecting the border placement?

I'm struggling with an element that has a CSS style ::before to display an arrow-up inside a black circle. Check out the code here The issue I'm facing is that the character \25b2 isn't centered vertically within the circle. Adjustin ...

Companimation Woes: CSS3 Animations Not Triggering Unless Loaded

I am currently utilizing Mike Fowler's companimation library for Compass, but unfortunately, I am encountering an issue where my animations are not functioning properly in Firefox (even though they work perfectly in Chrome). The problem arises when el ...

How can I create a table that is 100% width, with one column that has a flexible size and truncates text

I am currently facing an issue with a table nested within a div that is absolutely positioned on my webpage. I want to set specific widths for the second, third, etc columns while allowing the first column to automatically resize, even if it results in tru ...

Exploring audio analysis across different platforms using the power of the Web Audio API

Currently, I am in the process of developing an audio visualizer application using the web audio api and the three.js library. Utilizing the html5 element has been effective in extracting audio from local mp3 files or streaming mp3 files through the crea ...

Displaying a div when hovering over it, and keeping it visible until clicked

I want to display a div when hovering over a button. The shown div should be clickable and persistent even if I move the cursor from the button into the shown div. However, it should be hidden when moving out of the entire area. I'm unsure about how ...

What is the best way to establish a minimum width in pixels and a maximum width determined by the variable width of the browser window?

In this scenario: http://jsbin.com/anoyik/edit#preview http://jsbin.com/anoyik/edit#source Is there a way to make the red box's width a minimum of 200px and allow it to expand as the browser window's width increases horizontally? ...

Don't forget to strip off the height attribute once the transform is

Utilizing the transform property: .parent { display: inline-flex; flex-direction: column; align-items: center; } .first { height: 100px; } .second { height: 100px; transform: translateY(-50%); } <div class="parent"> <div ...

Tips for Printing a div Element with Horizontal Scrollbars

My webpage has both vertical and horizontal scroll bars, but when I use window.print(), it only prints the visible content in the window. Is there a way to print the entire scrollable content within the window? ...

Establish a connection to a regular socket by utilizing WebSocket technology

I am attempting to connect a client interface to a hardware device using WebSocket in a browser like Chrome. The code snippet I have been using for connection is as follows: var ws = new WebSocket("ws://127.0.0.1:13854"); ws.onopen = function() ... Howev ...

What are the steps to customize the appearance of a ComboBox using CSS?

I'm struggling to style the items in a combo box when it's dropped down. Currently using vaadin-time-picker on Svelte, but my issue persists due to the combo box included. Despite experimenting with CSS, I haven't had any success. My goal i ...

Creating Flexible Divs with Gradient Background for Older Versions of Internet Explorer - IE8 and IE7

I'm attempting to achieve the following. https://i.stack.imgur.com/YYOZv.jpg The issue I am encountering is that the elements in row1 have a different gradient background compared to those in row2. Additionally, row1 is populated dynamically with c ...