1

In the example, I have to click twice to see Foo content, but only once to see Bar content. The only difference is that Foo content has a internal style and Bar has inline style.

<html>

<head>
  <style>
    .content {
      display: none;
    }
  </style>

  <script>
    function showHide(element) {
      sibling = element.nextElementSibling;
      if (sibling.style.display == "none")
        sibling.style.display = "block"
      else sibling.style.display = "none";
    }
  </script>
</head>

<body>
  <h1 onclick="showHide(this)">Foo</h1>
  <div class="content">
    Foo Content
  </div>

  <h1 onclick="showHide(this)">Bar</h1>
  <div style="display: none;">
    Bar Content
  </div>
</body>

</html>

You can see this code in jsfiddle here

I'd like to use internal css or external css but having the same behaviour as I get in inline css, is this possible? I guess this is a basic topic, but I don't know what concepts to use to going deeper.

showdev
  • 28,454
  • 37
  • 55
  • 73
jjcb
  • 19
  • 4
  • if you inspece and then click the element you can see the issue. here you are missing the condition you put in js. css dose not have different behaviour. – jual ahmed May 19 '23 at 03:46

2 Answers2

5

When you read sibling.style.display from JavaScript, you get the inline display style on that element. When there is no inline display style, you get "". Getting the computed style is something you can do, but the better general solution is not to set styles directly from JavaScript at all, and instead manipulate meaningful classes:

function showHide(element) {
    const sibling = element.nextElementSibling;
    sibling.classList.toggle("content-hidden");
}
.content-hidden {
    display: none;
}
<h1 onclick="showHide(this)">Foo</h1>
<div class="content-hidden">
    Foo Content
</div>

<h1 onclick="showHide(this)">Bar</h1>
<div class="content-hidden">
    Bar Content
</div>

In this specific case, you might just be looking for <details>, though:

.thing > summary {
  display: flex;
}
<details class="thing">
    <summary><h1>Foo</h1></summary>
    Foo Content
</details>

<details class="thing">
    <summary><h1>Bar</h1></summary>
    Bar Content
</details>
Ry-
  • 218,210
  • 55
  • 464
  • 476
4

The issue is that sibling.style.display refers to the style attribute, not the computed style for the element. You'll notice that if you click it again it works, because the first click sets the style to display: none so a subsequent click makes it visible.

But you can solve this by using the element's classList to toggle a class that makes it visible, as in this example.

function showHide(element) {
  sibling = element.nextElementSibling;
  sibling.classList.toggle('visible')
}
.content {
  display: none;
}

.visible {
  display: block;
}
<h1 onclick="showHide(this)">Foo</h1>
<div class="content">
  Foo Content
</div>

<h1 onclick="showHide(this)">Bar</h1>
<div class="content">
  Bar Content
</div>
ray
  • 26,557
  • 5
  • 28
  • 27