67

I have a menu and three hidden divs that show up depending on what option the user selects. I would like to show / hide them on click using only CSS. I have it working with jquery right now but I want it to be accessible with js disabled. Somebody here provided this code for someone else but it only works with div:hover or div:active, when I change it to div:visited it doesn't work. Would I need to add something or perhaps this isn't the right way to do it? I appreciate any help :)

The thing is my client wants this particular divs to slide/fade when the menu is selected, but I still want them to display correctly with javascript turned off. Maybe z-index could do the trick...?

0

14 Answers 14

66

For a CSS-only solution, try using the checkbox hack. Basically, the idea is to use a checkbox and assign different styles based on whether the box is checked or not used the :checked pseudo selector. The checkbox can be hidden, if need be, by attaching it to a label.

link to dabblet (not mine): http://dabblet.com/gist/1506530

link to CSS Tricks article: http://css-tricks.com/the-checkbox-hack/

Sign up to request clarification or add additional context in comments.

8 Comments

For some reason I have this obsession with using CSS over java whenever possible, and I like this solution. Anyone else like that too?
@AlexBanman Yes. I have yet to find a cross-browser, cross-device compatible CSS-only solution I didn't love.
How do you keep the browser from focusing (or attempting to focus) on the checkbox when clicking the label? Using this solution, my browser scrolls to the top of the page when I click the label
@froggomad You can try using display:none on the checkbox instead of absolute positioning. It definitely seems to alleviate the jumping, but I haven't fully tested it to see if it causes any other issues.
@AlexBanman Could you ever use Java to show/hide HTML elements like this? Even when Java was widely supported by browsers, there was no reason to use it for something like this.
|
52

This can be achieved by attaching a "tabindex" to an element. This will make that element "clickable". You can then use :focus to select your hidden div as follows...

.clicker {
width:100px;
height:100px;
background-color:blue;
outline:none;
cursor:pointer;
}

.hiddendiv{
display:none;
height:200px;
background-color:green;
}

.clicker:focus + .hiddendiv{
display:block;
}
<html>
<head>
</head>
<body>

<div>
<div class="clicker" tabindex="1">Click me</div>
<div class="hiddendiv"></div>
</div>

</body>

</html>

The + selector will select the nearest element AFTER the "clicker" div. You can use other selectors but I believe there is no current way to select an element that is not a sibling or child.

2 Comments

is there a way to have it hide when clicked again?
You can use the ~ selector to select a sibling element and not be the very next child.
17

In 2022 you can do this with just HTML by using the details element. A summary or label must be provided using the summary element. details is supported by all major browsers.

<details>
    <summary>Click Here for more info</summary>
    Here is the extra info you were looking for.
</details>

1 Comment

What an excellent feature! Apparently this has been well-supported since January 2020. One caveat is that the summary is not keyboard accessible. However, in Firefox, this feature can be enabled (default) and disabled via the dom.details_element.enabled setting, so I believe that avoids any accessibility issues. I'm interested in opinions on this.
7

Although a bit unstandard, a possible solution is to contain the content you want to show/hide inside the <a> so it can be reachable through CSS:

http://jsfiddle.net/Jdrdh/2/

a .hidden {
  visibility: hidden;
}

a:visited .hidden {
  visibility: visible;
}
<div id="container">
  <a href="#">
        A
        <div class="hidden">hidden content</div>
    </a>
</div>

4 Comments

It halfs work for what I need since the div will also have to hide on a second click. But you gave me an idea with only CSS, thanks!
Don't have enough reputation yet, but will come back :P
This does not seem to work in Chrome on OSX in 2020
In my browser this code snippet does nothing when clicking the A link.
6

Fiddle to your heart's content

HTML

<div>
<a tabindex="1" class="testA">Test A</a> | <a tabindex="2" class="testB">Test B</a>
<div class="hiddendiv" id="testA">1</div>
<div class="hiddendiv" id="testB">2</div>
</div>

CSS

.hiddendiv {display: none; }
.testA:focus ~ #testA {display: block; }
.testB:focus ~ #testB {display: block; }

Benefits

You can put your menu links horizontally = one after the other in HTML code, and then you can put all the content one after another in the HTML code, after the menu.

In other words - other solutions offer an accordion approach where you click a link and the content appears immediately after the link. The next link then appears after that content.

With this approach you don't get the accordion effect. Rather, all links remain in a fixed position and clicking any link simply updates the displayed content. There is also no limitation on content height.

How it works

In your HTML, you first have a DIV. Everything else sits inside this DIV. This is important - it means every element in your solution (in this case, A for links, and DIV for content), is a sibling to every other element.

Secondly, the anchor tags (A) have a tabindex property. This makes them clickable and therefore they can get focus. We need that for the CSS to work. These could equally be DIVs but I like using A for links - and they'll be styled like my other anchors.

Third, each menu item has a unique class name. This is so that in the CSS we can identify each menu item individually.

Fourth, every content item is a DIV, and has the class="hiddendiv". However each each content item has a unique id.

In your CSS, we set all .hiddendiv elements to display:none; - that is, we hide them all.

Secondly, for each menu item we have a line of CSS. This means if you add more menu items (ie. and more hidden content), you will have to update your CSS, yes.

Third, the CSS is saying that when .testA gets focus (.testA:focus) then the corresponding DIV, identified by ID (#testA) should be displayed.

Last, when I just said "the corresponding DIV", the trick here is the tilde character (~) - this selector will select a sibling element, and it does not have to be the very next element, that matches the selector which, in this case, is the unique ID value (#testA).

It is this tilde that makes this solution different than others offered and this lets you simply update some "display panel" with different content, based on clicking one of those links, and you are not as constrained when it comes to where/how you organise your HTML. All you need, though, is to ensure your hidden DIVs are contained within the same parent element as your clickable links.

Season to taste.

2 Comments

Nice, it works, NOTE: TO MAKE SURE YOU CAN CLICK on 'hidden element that appears', you need to set .hiddenDivClass:active{ display: block; } otherwise if you try to click on elements in it, the div will disappear
It still disappears after the click has finished being held down. Is there a way to make it not hide until a new top level menu item is clicked?
5

HTML

<input type="text" value="CLICK TO SHOW CONTENT">
<div id="content">
and the content will show.
</div>

CSS

#content {
  display: none;
}
input[type="text"]{
    color: transparent;
    text-shadow: 0 0 0 #000;
    padding: 6px 12px;
    width: 150px;
    cursor: pointer;
}
input[type="text"]:focus{
    outline: none;
}
input:focus + div#content {
  display: block;
}
<input type="text" value="CLICK TO SHOW CONTENT">
<div id="content">
and the content will show.
</div>

Comments

3

A little hack-ish but it works. Note that the label tag can be placed any where. The key parts are:

  • The css input:checked+div selects the div immediately next to/after the input
  • The label for said checkbox (or hey leave out the label and just have the checkbox)
  • display:none hides stuff

Code:

<head>
    <style>
        #sidebar {height:100%; background:blue; width:200px; clear:none; float:left;}
        #content {height:100%; background:green; width:400px; clear:none; float:left;}
        label {background:yellow;float:left;}
        input{display:none;}
        input:checked+#sidebar{display:none;}
    </style>
</head>
<body>
<div>
<label for="hider">Hide</label>
<input type="checkbox" id="hider">
<div id="sidebar">foo</div>

<div id="content">hello</div>

</div>
</body>

EDIT: Sorry could have read the question better.

One could also use css3 elements to create the slide/fade effect. I am not familiar enough with them to be much help with that aspect but they do exist. Browser support is iffy though.

You could combine the above effect with javascript to use fancy transitions and still have a fall back. jquery has a css method to override the above and slide and fade for transitions.

  • Tilda(~) mean some sibling after; not next sibling like plus(+).
  • [key="value"] is an attribute selector.
  • Radio buttons must have same name

To string tabs together one could use:

<html>
<head>
<style>
input[value="1"]:checked ~ div[id="1"]{
display:none;
}
input[value="2"]:checked ~ div[id="2"]{
display:none;
}
</style>
</head>
<body>
<input type="radio" name="hider" value="1">
<input type="radio" name="hider" value="2">
<div id="1">div 1</div>
<div id="2">div 2</div>
</body>
</html>

Comments

3

You could do this with the CSS3 :target selector.

menu:hover block {
    visibility: visible;
}

block:target {
    visibility:hidden;
}

Comments

1

You can find <div> by id, look at it's style.display property and toggle it from none to block and vice versa.

function showDiv(Div) {
    var x = document.getElementById(Div);
    if(x.style.display=="none") {
        x.style.display = "block";
    } else {
        x.style.display = "none";
    }
}
<div id="welcomeDiv" style="display:none;" class="answer_list">WELCOME</div>
<input type="button" name="answer" value="Show Div" onclick="showDiv('welcomeDiv')" />

2 Comments

pls add some information to your answer like what differs it from other answers? why is it correct? why are you doing what your doing?
And why are you using javascript when the question explicitly says they're currently using javascript and want a CSS only solution...
0

if 'focus' works for you (i.e. stay visible while element has focus after click) then see this existing SO answer:

Hide Show content-list with only CSS, no javascript used

Comments

-1

You're going to have to either use JS or write a function/method in whatever non-markup language you're using to do this. For instance you could write something that will save the status to a cookie or session variable then check for it on page load. If you want to do it without reloading the page then JS is going to be your only option.

1 Comment

This very page has many non-Javascript solutions.
-1

With this method, when you click on Nav Dropdown elements it will NOT disappear, unlike plain :focus solution.

key is:

  • tabindex in parent element
  • parentDiv:focus-within hiddenDiv { display: block;}
  • it will work with both: display and visibility css;

HTML code:

        <div className="DevNavBar dbb">
            {/* MAKE SURE TO ADD TABINDEX TO PARENT ELEMENT, OTHERWISE FAILS */}
            <div className="DevNavBar_Item1 drr" tabIndex="0">
                item1
                <div className="DevNavBar_Item1_HiddenMenu dgg">
                    <ul>
                        <li>blah1</li>
                        <li>blah2</li>
                    </ul>
                </div>
            </div>
        </div>

CSS code:

.DevNavBar {
    padding: 40px;
}

.DevNavBar_Item1 {
    padding: 20px;
    width: fit-content;
    cursor: pointer;
    position: relative;
}

.DevNavBar_Item1:hover {
    color: red;
}

.DevNavBar_Item1_HiddenMenu {
    display: none;
    position: absolute;
    padding: 10px;
    background-color: white;
    z-index: 10;
    left: 0;
    top: 70px;
}

.DevNavBar_Item1:focus {
    color: red; // this is so that when Nav Item is opened, color stays red
}

.DevNavBar_Item1:focus-within .DevNavBar_Item1_HiddenMenu {
    display: block;
    color: black; // this is to remove Bubbling, otherwise it will be RED, like the hover effect
}

Here is Video Demo I created on my youtube channel (note: this is my youtube channel, so I am affiliated to that channel), the link is for 'show and tell' purposes: https://youtu.be/QMqcZjmghf4

5 Comments

@IanCampbell I wrote that I am affiliated, so should be fixed now. (but tbh, now it looks like spam, not that I added these disclosures) ... can I just write: here is link TO MY YOUTUBE CHANNEL??? will this be ok??? cause the main purpose of my channel is suplement to stack overflow and for my own 'reminders on how to do things'
I share your concern that this answer looks like spammy. The opening line is all about your youtube video/channel. To make it less spammy, you might offer your disclosure and hyperlink lower in the answer so that the focus is on your actual insights and code. Some trailing text on your answer might be like "I've created a youtube video about the above approach: [hyperlink]"
The link seems to be a video about how to use React to change favicons, which has nothing to do with your answer here. Why include it?
What do you mean "MAKE SURE TO ADD TABINDEX TO PARENT ELEMENT"? What tabindex value should be added? To what parent element? The div directly before that message? To something outside those divs? What does the tabindex do? It would have been helpful to include a fully working example, rather than a somewhat cryptic message.
I am unable to get your code to do anything at all. It doesn't include any <a> links to click on. You include dbb, drr, dgg classes which don't exist in the CSS code. I'm not clear on how it should work.
-3

You can use text-indent if you need to hide a text element

1 Comment

As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.
-14

CSS does not have an onlclick event handler. You have to use Javascript.

See more info here on CSS Pseudo-classes: http://www.w3schools.com/css/css_pseudo_classes.asp

a:link {color:#FF0000;}    /* unvisited link - link is untouched */
a:visited {color:#00FF00;} /* visited link - user has already been to this page */
a:hover {color:#FF00FF;}   /* mouse over link - user is hovering over the link with the mouse or has selected it with the keyboard */
a:active {color:#0000FF;}  /* selected link - the user has clicked the link and the browser is loading the new page */

2 Comments

Despite being accepted other answers give a CSS only option.
This answer is wrong. The checkbox hack in @josh's solution is a widely used css only solution and should be the accepted answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.