I prefer the second approach, but without list or nested div structure.
CSS tabs could be accessible, read about it here.
Let’s start with
HTML. This is the full structure:
Let’s break it down by elements:
- wrapper - this element is used to distinguish tabs from the rest of the content;
input type="radio"- this element will be hidden, but will be used as a controlling element;
label- this element will be used as a clickable tab;
- content - this element is used as a wrapper for tab’s content.
This structure may look a bit dirty, but soon you’ll see the benefit of it. The basic principle is to group different types of elements.
Next we’ll add the following classes on every element:
BEM naming convention is used for this purpose.
To make sure every
input type="radio" element is a part of the same block, we’ll add
name attribute with same value on it like this:
`<input class="tabs__radio" name="myTabs" />`
Labels are generally used to define an
input element. If
for attribute is provided with matching
id of an
input, they will be bound together. If you click on a
label that is related to
checked state of an element will be toggled. This will be used as a trigger for changing tabs.
With that clarified, we’ll add unique
id attributes on every
input type="radio" and matching
for attributes to every
label like this:
<input class="tabs__radio" id="myTab1" name="myTabs" />
Finally, we’ll add
value attribute for every
input type="radio" element and
checked attribute on an element which should be active.
First we will import cita-flex mixins in our file. It is a small library which could help you create layouts using flexbox built by me. cita-flex is available through bower and you could install it using command
bower install cita-flex.
After that we should define default variables which will help us write more consistent code. There are 6 variables:
$size- default size for padding,
$background- default background color for tabs,
$background--active- default background color for active tab,
$color- text color for tabs,
$color--disabled- text color for disabled tabs and
$breakpoint- width which will define our tabs layout.
I really like BEM naming convention and I use it for defining
CSS variables, too.
Wrapper element should be displayed as a wrapped flex.
input type="radio" elements should be hidden. Here we hide them using
position: absolute technique and push the elements outside of the viewport.
label elements in this case, are flex items. They are aligned in a row and have fluid width controlled by
Tab’s content is an element which takes 100% of the wrapper’s width. This is achieved by setting
flex-basis to 100%. By default, content is hidden unless matching
input type="radio" is checked.
Now for the fun part, using
CSS to control the tabs. We will take advantage of 3 powerful
nth-of-type- selects the nth child of the same elements,
:checked- check if
inputis checked and
~- selects siblings selector.
If the first child of a
input type="radio" is checked, the first tab should be active and the content of the first tab should be displayed.
Easy, we’ll use
.input__radio:nth-of-type(1) to select the first
input type="radio". Then we’ll check if
input is checked:
.input__radio:nth-of-type(1):checked and find the first tab using siblings selector:
.input__radio:nth-of-type(1):checked ~ .tabs__label:nth-of-type(1). Finally, we’ll find the content of the first tab:
.input__radio:nth-of-type(1):checked ~ .tabs__content:nth-of-type(1).
Now that we know how to do this for first tab, we could use
@for loop and repeat this for every tab. And that’s it!
I’ve had situations where tabs should be disabled. It is legit situation and for this purpose I’ve added disabled state of tab.
:disabled pseudo selector and
hide-if-disabled class for elements that should be hidden.
The principle is the the same: we’ll find disabled
input element and matching tab and content:
.tab__radio:nth-of-type(1):disabled ~ .hide-if-disabled:nth-of-type(1).
Now we could repeat this for every tab using
@for loop and we’re finished.
Below you could see the full solution with disabled tabs 2 and 10.
Full demo is available on Github and via bower:
bower install csstabs.
Do you find this solution usable, because I really like how we could do even more complex things with
CSS only nowdays?