Changing Display Resets Scroll Offset
In Chrome 5, Safari 4, Opera 10.53 and sometimes Firefox (although I was unable to reproduce it in this test case), changing the visibility of the
element by toggling display:none
will cause the scroll offset to reset to zero. Toggling visibility:hidden
does
not seem to trigger the same problem.
Scroll the container and then toggle the classes applied.
Class applied:
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
I haven't tested this in Internet Explorer, yet. Feel free to report in the comments.
Conversation
Just tested it in IE 8, and the behavior is the same.
IE testing results:
IE8: display:none resets the scroll offset, visibility:hidden does not
IE7: scroll offset is not reset in any case
IE6: scroll offset is not reset in any case
Think this is a logged issue for Chromium (maybe a webkit issue?). As a work around, you could probably set the height to 0 or push it off stage.
Makes sense though, if you think about it. Playing with visibility just turns off the element's appearance whereas setting display to none seems to cause the object in memory to destroy and then re-render it when its display value is reset.
Same results as Gregory for IE.
Windows Firefox scrolls were not reset.
Windows Safari displays the same behavior as Mac.
Windows Chrome reset the scroll for display:none, but didn't for visibility.
I made a quick test that caches element.scrollTop if anyone’s interested in a workaround:
http://riddle.pl/public/tests/display-scrolltop/index.html
Just tested the CSS fix for this - add height: 0 to your .visibility class and use this in conjunction with visibility hidden (just make sure you work out the specificity, #a has a height set in your example that needs to be over-written).
The latest FF - scroll position remains.
In the qooxdoo framework we have a special handling for automatically restoring the position of scroll containers when showing them again. This is indeed a bug (or missing feature) in most browsers. That visibility don't shows the issue is quite logical as the element is still being computed and rendered - just not shown.
One thing to add: Even more complicated is, when the scroll-able area is not the thing which has the scroll bars but a children inside of it. Think about dragable windows using JavaScript with a scroll-area inside.
This does make sense; setting display to none has pretty much the same effect as removing it, and thus also removing its properties. I don't think this should be classified as a bug, even if it seems counter-intuitive or wrong to some people.
Firefox 3.5.9 on Ubuntu Linux 9.10 64-bit: Scroll offset preserved both ways.
Pressing F5 resets scroll offset in Chromium, not in Firefox.
Good one!
Did you report the bug to the Webkit and Opera teams?
@Lea Verou: I did not. The behaviour seemed reasonable consistent across multiple products that it was unclear whether this was by design or a bug.
Safari 5 (Mac): display:none reset the scroll offset, visibility:hidden does not.
FF 3.0 on WinXP behaves correctly (scroll position preserved)
The spec says "the element and its content are removed from the formatting structure entirely" which is consistent with what you see. The visibility property does not remove the element, but merely makes it invisible.
+1 on the "makes sense" aspect. Changing the offsetHeight of the page to, essentially, zero, *should* act as a kind of soft refresh.
Interesting observation.
I confirm Jonathan that in IE8, display:none resets offset while visibility does not.
Considering the W3C spec states, as Divya pointed out:
would certainly explains why this behavior is considered normal. However, the spec does not state that the element is destroyed or removed from memory as Ara suggested. I would suggest crafting a workaround using JavaScript to remember the scroll position upon removing it from the structure, then setting the position when the element is called again.
This seems odd. But couldn't you record the scroll offset in a javascript variable in an onkeydown event and reapply it to the area when it's subsequently displayed?