0

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>
sound wave
  • 3,191
  • 3
  • 11
  • 29
  • You could fake it by using labels and hidden checkboxes, but it seems simpler to just write a little JavaScript. – Heretic Monkey Sep 11 '19 at 20:24
  • You know a place where I can learn to write it? I'm new in this and I'm just able to write some css – sound wave Sep 11 '19 at 20:27
  • 1
    Specifically, look at [this answer](https://stackoverflow.com/a/32721572/215552), not only the accepted one. – Heretic Monkey Sep 11 '19 at 20:37
  • Thank you very much, it seems that in that way only one button per page can be placed though. – sound wave Sep 11 '19 at 20:49
  • 1
    Not if you use different IDs for each one... You could also generalize by using a sibling combinator. – Heretic Monkey Sep 11 '19 at 20:52
  • You mean that I should put `#btnControl + #btnControl` in the CSS code? Could you write a small example? – sound wave Sep 11 '19 at 21:04
  • 1
    This wouldn't really work with the way you have absolutely positioned everything since only closing it by another button press would mean you can have two items open on the same row, and they will be overlapping. If you want this specific behavior, you're probably better off creating tooltips using JavaScript. There are literally thousands of resources online on creating tooltips, give it a search if you like :) – Jochem Kuijpers Sep 11 '19 at 21:27
  • @JochemKuijpers Yes I already thought about tooltips, but I discarded them because I have to put in there text and formulas (images) while keeping all other text visibile and let open multiple at the same time. – sound wave Sep 11 '19 at 22:08

1 Answers1

1

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>
Heretic Monkey
  • 11,687
  • 7
  • 53
  • 122
  • Thank you very much for the help! I've never seen such commands. It would be nice that when a button is clicked a blank space is created below the line with the height given by the height of the content, so that the content can be placed in the blank space without hiding the other text. Do you think that to achieve this feature it is possibile to use the javascript that I added in the section **Javascript for further customization**? Thanks again – sound wave Sep 11 '19 at 22:42