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

14

42

I've been searching for a good trick to make a Hide/Show content or a list with only CSS and no javascript. I've managed to make this action:

<!DOCTYPE html>
<head>

   <style>
      #cont {display: none; }
      .show:focus + .hide {display: inline; }
      .show:focus + .hide + #cont {display: block;}
   </style>

</head>
<body>

   <div>
        <a href="#show"class="show">[Show]</a>
        <a href="#hide"class="hide">/ [Hide]</a>
        <div id="cont">Content</div>
   </div>

</body>
</html>

Demo here: http://jsfiddle.net/6W7XD/ And it's working but not as it should. Here is the problem: When the content is shown, you can hide it by clicking "anywhere on the page". How to disable that? how to hide content "only" by clicking hide? Thank you in advance!

Wooster answered 18/7, 2013 at 18:41 Comment(2)
Behavior is supposed to only exist in the realm of JavaScript.Mitziemitzl
that's why I'm here! to suppose it in CSS3 too! no need for javascript! let's hope for that! ;)Wooster
M
41

I wouldn't use checkboxes, i'd use the code you already have

DEMO http://jsfiddle.net/6W7XD/1/

CSS

body {
  display: block;
}
.span3:focus ~ .alert {
  display: none;
}
.span2:focus ~ .alert {
  display: block;
}
.alert{display:none;}

HTML

<span class="span3">Hide Me</span>
<span class="span2">Show Me</span>
<p class="alert" >Some alarming information here</p>

This way the text is only hidden on click of the hide element

Mesognathous answered 18/7, 2013 at 19:33 Comment(5)
Good tip. But it would be great if the text was hidden first. In this order: To Show it, then hide it.Wooster
I've just added this .alert{display:none;} and it worked fine. but when I add some others, it goes messy: jsfiddle.net/6W7XD/12 thx anywayWooster
As soon as the focus moves to anything other than either one of the SPANs, the display settings change back. So if the user needs to click on content, the content will change.Schopenhauerism
In Chrome 48.0.2564.22 dev-m, Once 'Hide Me' is clicked, as soon as it loses focus (ie: clicking anywhere else), the content is again hidden. Not a good idea to rely on focus as it's finicky on different OS's, virtual machines, etc.Zitazitah
For anyone not getting this to work right off the bat - make sure your focusable element has tabindex attribute set.Circulate
M
28

This is going to blow your mind: Hidden radio buttons.

input#show, input#hide {
    display:none;
}

span#content {
    display:none;
}
input#show:checked ~ span#content {
  display:block;
}

input#hide:checked ~ span#content {
    display:none;
}
<label for="show">
    <span>[Show]</span>
</label>
<input type=radio id="show" name="group">
<label for="hide">
    <span>[Hide]</span> 
</label>    
<input type=radio id="hide" name="group">
<span id="content">Content</span>
Malikamalin answered 18/7, 2013 at 19:4 Comment(5)
Are you sure it's working? not working for me though (I'm using Firefox)Wooster
Working for me on FF/Chrome/IE. Try copy/pasting into a new one, that might work.Malikamalin
Yes, worked! a checkboxe was displayed, so I replaced first line! thx mate! :) If no one come up with a non-checkboxes solution, well it's all yours ;)Wooster
Cool cool. This does seem kind of cheaty, but eh it gets the job done.Malikamalin
This solution doesn't loose the display settings if the user clicks on content other than the radio buttons. It could be used for page navigation.Schopenhauerism
A
20

I used a hidden checkbox to persistent view of some message. The checkbox could be hidden (display:none) or not. This is a tiny code that I could write.

You can see and test the demo on JSFiddle

HTML:

<input type=checkbox id="show">
<label for="show">Help?</label>
<span id="content">Do you need some help?</span>

CSS:

#show,#content{display:none;}
#show:checked~#content{display:block;}

Run code snippet:

#show,#content{display:none;}
#show:checked~#content{display:block;}
<input id="show" type=checkbox>
<label for="show">Click for Help</label>
<span  id="content">Do you need some help?</span>

http://jsfiddle.net/9s8scbL7/

Anatropous answered 1/6, 2017 at 2:1 Comment(2)
I really like this: elegantly simple and totally functional! It doesn't even jump up to the top of the screen like the checkbox hack does.Envelope
love this (6 more to go)Elder
G
13

There is 3 rapid examples with pure CSS and without javascript where the content appears "on click", with a "maintained click" and a third "onhover" (all only tested in Chrome). Sorry for the up of this post but this question are the first seo result and maybe my contribution can help beginner like me

I think (not tested) but the advantage of argument "content" that you can add great icon like from Font Awesome (its \f-Code) or an hexadecimal icon in place of the text "Hide" and "Show" to internationalize the trick.

example link http://jsfiddle.net/MonkeyTime/h3E9p/2/

<style>
label { position: absolute; top:0; left:0}

input#show, input#hide {
    display:none;
}

span#content {
    display: block;
    -webkit-transition: opacity 1s ease-out;
    transition: opacity 1s ease-out;
    opacity: 0; 
    height: 0;
    font-size: 0;
    overflow: hidden;
}

input#show:checked ~ .show:before {
    content: ""
}
input#show:checked ~ .hide:before {
    content: "Hide"
}

input#hide:checked ~ .hide:before {
    content: ""
}
input#hide:checked ~ .show:before {
    content: "Show"
}
input#show:checked ~ span#content {
    opacity: 1;
    font-size: 100%;
    height: auto;
}
input#hide:checked ~ span#content {
    display: block;
    -webkit-transition: opacity 1s ease-out;
    transition: opacity 1s ease-out;
    opacity: 0; 
    height: 0;
    font-size: 0;
    overflow: hidden;
}
</style>
<input type="radio" id="show" name="group">   
<input type="radio" id="hide" name="group" checked>
<label for="hide" class="hide"></label>
<label for="show" class="show"></label>
<span id="content">Lorem iupsum dolor si amet</span>


<style>
#show1 { position: absolute; top:20px; left:0}
#content1 {
    display: block;
    -webkit-transition: opacity 1s ease-out;
    transition: opacity 1s ease-out;
    opacity: 0; 
    height: 0;
    font-size: 0;
    overflow: hidden;
}
#show1:before {
    content: "Show"
}
#show1:active.show1:before {
    content: "Hide"
}
#show1:active ~ span#content1 {
    opacity: 1;
    font-size: 100%;
    height: auto;
}
</style>

<div id="show1" class="show1"></div>
<span id="content1">Ipsum Lorem</span>


<style>
#show2 { position: absolute; top:40px; left:0}
#content2 {
    display: block;
    -webkit-transition: opacity 1s ease-out;
    transition: opacity 1s ease-out;
    opacity: 0; 
    height: 0;
    font-size: 0;
    overflow: hidden;
}
#show2:before {
    content: "Show"
}
#show2:hover.show2:before {
    content: "Hide"
}
#show2:hover ~ span#content2 {
    opacity: 1;
    font-size: 100%;
    height: auto;
}

/* extra */
#content, #content1, #content2 {
    float: left;
    margin: 100px auto;
}
</style>

<div id="show2" class="show2"></div>
<span id="content2">Lorem Ipsum</span>
Gourd answered 10/2, 2014 at 19:57 Comment(0)
Z
10

Nowadays (2020) you can do this with pure HTML5 and you don't need JavaScript or CSS3.

<details>
<summary>Put your summary here</summary>
<p>Put your content here!</p>
</details>
Zinovievsk answered 1/4, 2020 at 11:37 Comment(2)
Could you expand a bit? This is nothing close to a working example.Hapten
Maybe helps a documentation more? developer.mozilla.org/en-US/docs/Web/HTML/Element/detailsZinovievsk
G
9

This is what I've used recently.

CSS

div#tabs p{display:none;}

div#tabs p.tab1:target {display:block;}
div#tabs p.tab2:target {display:block;}
div#tabs p.tab3:target {display:block;}

HTML

<div id='tabs'>
  <h2 class="nav-tab-wrapper">
    <a href="#tab1" class="nav-tab tab1">Pages</a>
    <a href="#tab2" class="nav-tab nav-tab-active tab2">Email</a>
    <a href="#tab3" class="nav-tab tab3">Support</a>
  </h2>

  <p id='tab1' class='tab1'>Awesome tab1 stuff</p>
  <p id='tab2' class='tab2'>Tab2 stuff</p>
  <p id='tab3' class='tab3'>Tab3 stuff</p>

</div>

https://jsfiddle.net/hoq0djwc/1/

Hope it helps somewhere.

Giorgi answered 17/5, 2015 at 4:19 Comment(0)
A
5

First, thanks to William.

Second - i needed a dynamic version. And it works!

An example:

CSS:

p[id^="detailView-"]
{
    display: none;
}

p[id^="detailView-"]:target
{
    display: block;
}

HTML:

<a href="#detailView-1">Show View1</a>
<p id="detailView-1">View1</p>

<a href="#detailView-2">Show View2</a>
<p id="detailView-2">View2</p>
Amena answered 30/6, 2015 at 13:20 Comment(0)
C
3

The answer below includes changing text for "show/hide", and uses a single checkbox, two labels, a total of four lines of html and five lines of css. It also starts out with the content hidden.

Try it in JSFiddle

HTML

<input id="display-toggle" type=checkbox>
<label id="display-button" for="display-toggle"><span>Display Content</span></label>
<label id="hide-button" for="display-toggle"><span>Hide Content</span></label>    
<div id="hidden-content"><br />Hidden Content</div>

CSS

label {
  background-color: #ccc;
  color: brown;
  padding: 15px;
  text-decoration: none;
  font-size: 16px;
  border: 2px solid brown;
  border-radius: 5px;
  display: block;
  width: 200px;
  text-align: center;
}

input,
label#hide-button,
#hidden-content {
  display: none;
}

input#display-toggle:checked ~ label#display-button {
  display: none;
}

input#display-toggle:checked ~ label#hide-button {
  display: block;
  background-color: #aaa;
  color: #333
}

input#display-toggle:checked ~ #hidden-content {
  display: block;
} 
Collimate answered 24/8, 2017 at 14:8 Comment(2)
This is great if you have only one row. I m tying to get this concept to work with multiple rows, where each row you click will make room to show the hidden content. For example: codepen.io/Chris_Nielsen/pen/qoGgqBDistributor
@Diepen's solution jsfiddle.net/a14bztje is worth a look, for multiple shown/hidden content.Collimate
D
1

I've got another simple solution:

HTML:

<a href="#alert" class="span3" tabindex="0">Hide Me</a>
<a href="#" class="span2" tabindex="0">Show Me</a>
<p id="alert" class="alert" >Some alarming information here</p>

CSS:

body { display: block; }
p.alert:target { display: none; }

Source: http://css-tricks.com/off-canvas-menu-with-css-target/

Duma answered 12/8, 2013 at 4:4 Comment(0)
P
1

I know it's an old post but what about this solution (I've made a JSFiddle to illustrate it)... Solution that uses the :after pseudo elements of <span> to show/hide the <span> switch link itself (in addition to the .alert message it must show/hide). When the pseudo element loses it's focus, the message is hidden.

The initial situation is a hidden message that appears when the <span> with the :after content : "Show Me"; is focused. When this <span> is focused, it's :after content becomes empty while the :after content of the second <span> (that was initially empty) turns to "Hide Me". So, when you click this second <span> the first one loses it's focus and the situation comes back to it's initial state.

I started on the solution offered by @Vector I kept the DOM'situation presented ky @Frederic Kizar

HTML:

<span class="span3" tabindex="0"></span>
<span class="span2" tabindex="0"></span>
<p class="alert" >Some message to show here</p>

CSS:

body {
    display: inline-block;
}
.span3 ~ .span2:after{
    content:"";
}
.span3:focus ~ .alert  {
    display:block;
}
.span3:focus ~ .span2:after  {
    content:"Hide Me";
}
.span3:after  {
    content: "Show Me";
}
.span3:focus:after  {
    content: "";
}
.alert  {
    display:none;
}
Pauperism answered 17/2, 2017 at 23:6 Comment(6)
Working on that idea and reading an answer from @Frederic Kizar where he said that with several < span> the thing goes messy, I've made this other JSFiddle [link] (jsfiddle.net/a14bztje) where I play with the first occurence of an element following an other ( + ) in CSS plus sign, to achieve the result. Note that the < span> and < p> tags keep same shared classes. I used the attr(data-something) for the pseudo contents to personalize the hide/show links.Pauperism
One hour later :-) I've revised the [link] (jsfiddle.net/a14bztje) JSFiddle to simplify it. I removed the classes... just play with the tags styles. And it still works ! And instead of a new attribute (for the show/hide text), I use the "title" attribute to "embed" the text... So we win an onmouseover advantage to display the tooltip... Other styles like margin, position, background-color etc. are there for the visual purpose... The "trick" resides in the sequence of the objects: < span> + < span> + < p>Pauperism
Ok, for more clarity, I've made two JSFidle demos. One with only "the CSS's trick" (same link as previous one just above link ). Note that I forgot the classes and just play with sequences of three < span> elements, separated by at least another tag. Also note that I used the Title="something" attribute to "embed" the switches texts (Show me / Hide me), so we gain an on hover effect ;-). You could have used a personalized attribute like data-text="Something", instead of the title attribute... (to be continued...)Pauperism
In a second JSFiddle example link, I've made some aesthetic adjustments in the CSS, to demonstrate a pratical usage that we could do with all of that. Note here, that I use visibility instead of display and then I add a position:absolute, to allow multiline text in the messages, without destroying all the alignments of the "switch links". ... (to be continued...)Pauperism
The interest, is that you can add any number of sequences of three <span> elements without worrying about classes, names or ids, and just focus on the content of your elements. All of this achieved without Javascript nor checkboxes, <ul> , <li> nor <label for > . ;-)Pauperism
Just for the pleasure... So you liked the three <span> tags series ? What about introducing a fourth one ? And let's play with :after, :before pseudo elements and active, focus or hover states ... Ready ? ... LET'S GO CRAZY ! (here, follow the JSFiddle)-> link :-DPauperism
M
1

Just wanted to illustrate, in the context of nested lists, the usefulness of the hidden checkbox <input> approach @jeffmcneill recommends — a context where each shown/hidden element should hold its state independently of focus and the show/hide state of other elements on the page.

Giving values with a common set of beginning characters to the id attributes of all the checkboxes used for the shown/hidden elements on the page lets you use an economical [id^=""] selector scheme for the stylesheet rules that toggle your clickable element’s appearance and the related shown/hidden element’s display state back and forth. Here, my ids are ‘expanded-1,’ ‘expanded-2,’ ‘expanded-3.’

Note that I’ve also used @Diepen’s :after selector idea in order to keep the <label> element free of content in the html.

Note also that the <input> <label> <div class="collapsible"> sequence matters, and the corresponding CSS with + selector instead of ~.

jsfiddle here

.collapse-below {
    display: inline;
}

p.collapse-below::after {
    content: '\000A0\000A0';
}

p.collapse-below ~ label {
    display: inline;
}

p.collapse-below ~ label:hover {
    color: #ccc;
}

input.collapse-below,
ul.collapsible {
    display: none;
}

input[id^="expanded"]:checked + label::after {
    content: '\025BE';
}

input[id^="expanded"]:not(:checked) + label::after {
    content: '\025B8';
}

input[id^="expanded"]:checked + label + ul.collapsible {
    display: block;
}

input[id^="expanded"]:not(:checked) + label + ul.collapsible {
    display: none;
}
<ul>
  <li>single item a</li>
  <li>single item b</li>
  <li>
    <p class="collapse-below" title="this expands">multiple item a</p>
    <input type="checkbox" id="expanded-1" class="collapse-below" name="toggle">
    <label for="expanded-1" title="click to expand"></label>
    <ul class="collapsible">
      <li>sub item a.1</li>
      <li>sub item a.2</li>
    </ul>
  </li>
  <li>single item c</li>
  <li>
    <p class="collapse-below" title="this expands">multiple item b</p>
    <input type="checkbox" id="expanded-2" class="collapse-below" name="toggle">
    <label for="expanded-2" title="click to expand"></label>
    <ul class="collapsible">
      <li>sub item b.1</li>
      <li>sub item b.2</li>
    </ul>
  </li>
  <li>single item d</li>
  <li>single item e</li>
  <li>
    <p class="collapse-below" title="this expands">multiple item c</p>
    <input type="checkbox" id="expanded-3" class="collapse-below" name="toggle">
    <label for="expanded-3" title="click to expand"></label>
    <ul class="collapsible">
      <li>sub item c.1</li>
      <li>sub item c.2</li>
    </ul>
  </li>
</ul>
Mittiemittimus answered 5/10, 2019 at 15:51 Comment(0)
B
0

A very easy solution from cssportal.com

If pressed [show], the text [show] will be hidden and other way around.

This example does not work in Chrome, I don't why...

.show {
	display: none;
}
.hide:focus + .show {
	display: inline;
}
.hide:focus {
	display: none;
}
.hide:focus ~ #list { display:none; }
@media print {
.hide, .show {
	display: none;
}
}
<div><a class="hide" href="#">[hide]</a> <a class="show" href="#">[show]</a>
<ol id="list">
<li>item 1</li>
<li>item 2</li>
<li>item 3</li>
</ol>
</div>
Birthday answered 22/12, 2014 at 15:59 Comment(0)
E
0

There is a pure HTML solution! Try the <details> element.

Implementation details from MDN: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/summary

And a try it out example from W3: https://www.w3schools.com/tags/tryit.asp?filename=tryhtml5_details

Browser support info is here: https://caniuse.com/details

Eugine answered 28/10, 2021 at 19:48 Comment(0)
D
0

After reading all the answers, I made this for whoever may still be looking for the trick: https://jsfiddle.net/Junip/do5xbkr6.
You now have the four ways to interact with links with CSS:
No form elements, no summary-details html tags, zero scripting.

#btn1::before { content: "Hover"; }
#btn1:hover::before { content: "Move"; }
#btn1:hover ~ #content { display: block; }

#btn2::before { content: "Hold down"; }
#btn2:active::before { content: "Release"; }
#btn2:active ~ #content { display: block; }
#btn2:active { opacity: 0; }

#btn3 a::before { content: "Click"; }
#btn3 a:focus::before { content: "Click away"; }
#btn3:focus-within ~ #content { display: block; }

#content {
  display: none;
  position: absolute;
  top: 30%;
}
[id^="btn"] a {
  text-decoration: none;
  color: black;
}

#btn4 a[href="#revert"] { display: none; }
#content:target { display: block; }
#content:target ~ #btn4 a[href="#content"] { display: none; }
#content:target ~ #btn4 a[href="#revert"] { display: block; }
Demasculinize answered 1/2, 2023 at 17:39 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.