1

While trying to make a basic collapsing div with Javascript, I came across the following odd bug; with this code:

<html> 
    <head> 
        <style type="text/css">
            .hidden
            {
                display: none;
            }
        </style>
        <script type="text/javascript">
            function toggle()
            {
                var element = document.getElementById('hidden1');
                if(element.style.display === 'none')
                {
                    element.style.display = 'inline';
                }
                else
                {
                    element.style.display = 'none';
                }
            }
        </script> 
    </head> 
    <body>
        <a onclick="toggle()">Click me</a><br /> 
        <div id="hidden1" class="hidden">
            stuffs
        </div>
    </body>
</html>

I had expected it to work as it would appear: the div would start hidden, and upon every click it would go from visible to invisible, however it does not: it requires 2 clicks to show the element the first time, and after some debugging I realised that the div seems to be in some weird quantuum flux. When adding the following alert to the top of the toggle() method:

alert('\'' + document.getElementById('hidden1').style.display + '\'');

I'm given '', meaning it's empty. However when I do this in exactly the same place:

console.log(document.getElementById('hidden1').style);

The console then shows:

[object CSS2Properties]

With the following properties:

0: "display"
...
display: "none"

However, when the CSS declaration for .hidden is moved inline to the div's style, the code works exactly as one would expect. Does anyone know why this is happening?

I'd also like to know if anyone can't reproduce the problem, as I've experienced it with apache on both Centos and Windows, and with Firefox 24, Chrome 30 and the latest Opera browsers.

1
  • Hint: If you move your style inline, <div id="hidden1" style="display:none">, you will no longer see the "quantum" state. element.style.display is not set by CSS files. Commented Oct 18, 2013 at 18:30

4 Answers 4

7

That's the C (cascade) in CSS. You are checking if that element directly has the display property set to none. When you load your page, it does not. When you click it the first time, it checks if it's own style.display is none, it's undefined though; so it assigns "none" based on your if/else.

Now, when you click it again, it does have style.display set to "none", so it then changes it to "inline". The element still has the class .hidden which is set to have display: none, but because of the way CSS inherits properties, the element's setting is more valuable.

There are two ways to fix your problem. You can either add the display none inline like this

<div id="hidden1" style="display:none">

Or you can have your if else check for an undefined value and it equaling 'none' like this

// In function toggle()
 if(!element.style.display || element.style.display === 'none')

Which will first check for an empty string or undefined value, and also check if it's set to none.

You could actually do both of these, but it's better practice to not having styles inline if possible.

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

2 Comments

You are checking if that element directly has the display property set to none. So you're saying that Javascript can only see inline declarations of CSS?
Your browser has an order of how to apply styles (See something like this w3.org/TR/CSS2/cascade.html for more on that). You could use getComputedStyle developer.mozilla.org/en-US/docs/Web/API/… to determine what the end result of the cascade is. Or you could logic something like "If this element has the hidden class, do X, otherwise, Y" and then instead of in your toggle function setting the elements local style.display you could instead add and remove the hidden class
0

The problem is you're setting the style in two different ways. You've added a class, hidden, to the div that hides it, but you're also manually setting the CSS property with Javascript. The two conflict, causing the weird "quantum" behavior you're seeing.

I recommend either using jQuery to toggle visibility (you can do this with a single function) or, if you don't want to use jQuery, follow the directions in the first answer here.

1 Comment

But the CSS is changed within the function, and display element is blank even if the function is never called.
0

.css styling and in-line/javascript styling apparently live in different dimensions. That's really weird.

Basically, style.display in javascript only knows of the values you set, not the ones your .css file sets..

Here's a quick work around: http://jsfiddle.net/qy3w8/

if (element.style.display == "") {
    element.style.display = "none";
}

Just added that if statement on top of your if statements. Or you could use jQuery, either works fine.

Comments

0

Another option is to remove the style .hidden, and call your function toggle() on document load.

Comments

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.