Many site owners want to let users toggle different sections of a web page. Often this is both unnecessary and annoying for the site visitors, but it can sometimes be useful for hiding otherwise distracting content.
This toggle menu is made with HTML and CSS only, no Javascript. I also have a Javascript toggle menu which I much prefer over this one. Using only CSS for a menu like this is more of a curiosity than a real advantage in my opinion.
Tested to work in IE9 (but keyboard navigation seems a bit quirky) and other current (2015) browsers.
In older versions of Webkit-based browsers (like Safari 5, Chrome 12 and Android 4) the toggle sections can't be opened due to the Webkit sibling selector bug. According to Can I Use, usage of these browser versions is negligible now.
Click the top row buttons to Show all, Hide all or Toggle individual (default). When Toggle individual sections is selected, the buttons in the left column can be clicked to toggle individual sections. I admit the menu isn't very intuitive to use.
LABEL elements in the top row check hidden radio buttons, while LABEL elements in the left column check hidden checkboxes. The various :checked
combinations change both the styling of the LABEL elements and the display of the associated DIV elements with CLASS "toggle".
Note that even though the labels for the checkboxes appear to be disabled in the Show all and Hide all states, the user can still toggle the checkboxes in the background by clicking the checkbox LABEL elements.
If the radio buttons and checkboxes are hidden, keyboard navigation will be confusing, since the user can't know that the hidden radio buttons at the top must be navigated with the keyboard's arrow keys, while the individual sections are navigated with the Tab key and toggled with the space bar.
If you still want to hide the checkboxes and radio buttons, use CSS opacity: 0;
. If display: none;
or other hiding methods are used the hidden form elements can't be focused with keyboard tabbing. In this demo I also use position: absolute;
(without offsets) to prevent the form elements from affecting the normal content flow.
In browsers that don't support the :checked
pseudo-class the toggle content would normally be inaccessible. To prevent that I put :checked
inside a :not
negation pseudo-class for feature detection. This way the toggle content is only hidden if the browser supports :not
and the toggle checkbox is not checked:
input[type=checkbox]:not(:checked) ~ .toggle {display: none;}
I use a similar trick for hiding the radio button labels in non-supporting browsers, where they would be unusable anyway. First the labels are hidden by default, then made visible again in browsers that support :not
and :checked
.
To hide the INPUT elements from non-supporting browsers I use :not(foo)
. Note that you can't use :not(:checked)
for the INPUT elements, since that's also a selector for content in supporting browsers when a form element is not checked.
.toggle_container input {display: none;}
.toggle_container input:not(foo) {display: inline;}
Alas this feature detection doesn't help against the Webkit sibling selector bug described under the Browser support heading.
published: Dec 11, 2015
last modified: Jan 26, 2017