sound wave
sound wave

Reputation: 3537

Collapse/close a button only by clicking on it

I'm trying to code a responsive button which can be placed multiple times in the same line, showing its content always below the line containing the button.

In the snippet there is a working code, but it has a small flaw: since the pseudo-class focus is used, once the button is opened it's enough to click anywhere on the screen to close it.

The usual behaviour for a button is that to close it you have to click on it, so is it possibile to get this behaviour also for this one?

I used other pseudo-classes but without success, I guess only a javascript can do the job.

.container {
  position: relative;
  margin: 2em;
}
.details {
  display: none;
}
.collapsible:focus {
    margin-bottom: 1.5em;
    pointer-events: none;
}
.collapsible:focus + .details 
{
  display: block;
  margin-top: -1.15em;
  position: absolute;
  left: 0;
  right: 0;
  background: yellow;
}
<div class=container>

You can <button class="collapsible">place</button><span class=details>yes</span> more than <button class="collapsible">one</button><span class=details>nice</span> per line, they are responsive and the content is always shown just <button class="collapsible">below</button><span class=details>cool</span> the line containing the button.
But once opened, you can close it with a click <button class="collapsible">everywhere</button><span class=details>not good</span> on the screen

</div>

Javascript for further customization

<script type="text/javascript">
var coll = document.getElementsByClassName("collapsible");
var i;

for (i = 0; i < coll.length; i++) {
  coll[i].addEventListener("click", function() {
    this.classList.toggle("active");
    var content = this.parentElement.nextElementSibling;
    if (content.style.maxHeight){
      content.style.maxHeight = null;
    } else {
      content.style.maxHeight = content.scrollHeight + "px";
    } 
  });
}
</script>

Upvotes: 0

Views: 76

Answers (1)

Heretic Monkey
Heretic Monkey

Reputation: 12112

Implementation of the idea was a bit more complicated so I'll just answer.

This uses an old trick whereby a label, associated with a hidden checkbox, is used as the click target. Since clicking on a label checks or unchecks the checkbox, and there is a pseudo-class for the checked state of the checkbox, we can use that to persist the state of our styles. Credit to TylerH for his answer to the similar question Can I have an onclick effect in CSS?.

I've implemented it here by using a partial attribute selector, so in this example any checkboxes have to have an ID that begins with "demo". The checkboxes do have to have an ID for the for attribute of the label to hook onto.

.container {
  position: relative;
  margin: 2em;
}

.collapsible:focus {
  margin-bottom: 1.5em;
  pointer-events: none;
}


label {
  display: inline-block;
  background: lightgrey;
}

[id^="demo"] {
  display: none;
}

/* details that are next to labels that are next to unchecked checkboxes are hidden */
[id^="demo"]:not(:checked)+label+.details {
  display: none;
}


/* details that are next to labels that are next to checked checkboxes are displayed */
[id^="demo"]:checked+label+.details {
  display: block;
  position: absolute;
  left: 0;
  right: 0;
  background: yellow;
}

/* labels that are next to unchecked checkboxes have a different color 
   so you can track which ones are "on" */
[id^="demo"]:checked+label {
  background: blue;
  color: white;
}
<div class=container>

  You can <input type="checkbox" id="demo01" /><label for="demo01" >place</label><span class=details>yes</span> more than <input type="checkbox" id="demo02" /><label for="demo02">one</label><span class=details>nice</span>  per line, they are responsive and the content is always shown just <input type="checkbox" id="demo03" /><label for="demo03">below</label><span class=details>cool</span> the line containing the button. But once opened, you can close
  it with a click <input type="checkbox" id="demo04" /><label for="demo04">everywhere</label><span class=details>not good</span> on the screen

</div>

Upvotes: 1

Related Questions