Why the vertical scroll bar moves automatically?
Asked Answered
C

2

10

I don't understand why the vertical scroll bar moves automatically to the most top position when "Line 9" clicked, for example. Further clicks does not move the scroll bar. Could anyone explain why, and how to fix this ? I work with Firefox 3.6.3.

HTML:

<html>
    <head>
        <link rel="stylesheet" href="test.css" type="text/css" />
        <script src="http://code.jquery.com/jquery-latest.js"></script>
        <script language="JavaScript" src="test.js"></script>
    </head>

    <body>
        <div>
            <table>
                <tr row='0'><td class='column1'>Line 0</td></tr>
                <tr row='1'><td class='column1'>Line 1</td></tr>
                <tr row='2'><td class='column1'>Line 2</td></tr>
                <tr row='3'><td class='column1'>Line 3</td></tr>
                <tr row='4'><td class='column1'>Line 4</td></tr>
                <tr row='5'><td class='column1'>Line 5</td></tr>
                <tr row='6'><td class='column1'>Line 6</td></tr>
                <tr row='7'><td class='column1'>Line 7</td></tr>
                <tr row='8'><td class='column1'>Line 8</td></tr>
                <tr row='9'><td class='column1'>Line 9</td></tr>
            </table>
        </div>
    </body>
</html>

JS:

$(document).ready(function() {
    $(".column1").each(function(index) {
        $(this).after("<td class='column2'>Details " + index + "</td>");
        $(this).toggle(function() { $("[row='" + index + "'] .column2").fadeIn("fast") },
                       function() { $("[row='" + index + "'] .column2").fadeOut("fast") });
    });
});

CSS:

div {
    overflow: auto;
    height: 100px;
    width: 300px;
    border: 1px solid blue;
}

.column1 {
    cursor: pointer;
    width: 100px;
    background-color: green;
    color: white;
}

.column2 {
    display: none;
    width: 200px;
    background-color: blue;
    color: white;
}
Chorography answered 16/5, 2010 at 14:27 Comment(1)
Interesting. It seems that there is the same problem with Opera 10.53. IE8 and Chrome work without problems however.Towery
C
6

After doing some trial and error tests, it looks like this is related to the moment that the browser recalculates and redraws the table when you fade in/fade out one of the cells. There's nothing wrong with your code, and jQuery is correctly toggling the 'display' property of the cell - it looks like it's a minor bug in FF.

Probably the easiest way around it is to avoid toggling table cells themselves, and instead toggle the contents of the column2 cell, like so:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
    <head>
        <link rel="stylesheet" href="test.css" type="text/css" />
        <script src="http://code.jquery.com/jquery-latest.js"></script>
        <script language="JavaScript">
        $(document).ready(function() {
            $("td.column1").each(function(index) {
                $(this).after('<td class="column2"><span class="details">Details ' + index + '</span></td>');
                $(this).toggle(
                  function(){$(this).siblings('.column2').children('span.details').fadeIn("fast")},
                  function(){$(this).siblings('.column2').children('span.details').fadeOut("fast")}
                ) 
            });
        });
        </script>
        <style type="text/css" media="screen">
          div {
              overflow: auto;
              height: 100px;
              width: 300px;
              border: 1px solid blue;
          }

          .column1 {
              cursor: pointer;
          }

          .column2 .details{
              display:none;
          }

        </style>
    </head>

    <body>
        <div>
            <table>
                <tr row='0'><td class='column1'>Line 0</td></tr>
                <tr row='1'><td class='column1'>Line 1</td></tr>
                <tr row='2'><td class='column1'>Line 2</td></tr>
                <tr row='3'><td class='column1'>Line 3</td></tr>
                <tr row='4'><td class='column1'>Line 4</td></tr>
                <tr row='5'><td class='column1'>Line 5</td></tr>
                <tr row='6'><td class='column1'>Line 6</td></tr>
                <tr row='7'><td class='column1'>Line 7</td></tr>
                <tr row='8'><td class='column1'>Line 8</td></tr>
                <tr row='9'><td class='column1'>Line 9</td></tr>
            </table>
        </div>
    </body>
</html>

So, the script adds the column2 cell, and that stays visible the whole time - instead we show/hide the <span class="details"> within it. I've tested this version in FF 3.6.3 and it behaves as it should!

Oh - and I cleaned up your jQuery selectors for better performance. If you want more info on why, let me know!

Chlamydospore answered 20/5, 2010 at 15:50 Comment(6)
Nice workaround, but it does not solve my problem completely. In my case .column2 has a fixed width and a background-color. If you add these attributes to the CSS code you'll see the background-color even when the details span is not displayed. I will edit the question accordingly. Also, please let me know why your jQuery selectors have better performance than mine.Chorography
OK - I think, in order to remove the source of the problem, column2 is going to have to be visible at all times. My belief is that it's the showing and hiding of the cell that is the direct cause - here's why: Unlike most elements, TD's have inter-dependencies with elements around them. The size of one cell can depend on the widths of both other cells in the same row, and others in the same column. If you add a new cell (via .fadeIn()), the browser needs to recalculate the dimensions of some or all of the other cells in the table. (continued)Chlamydospore
...when this happens, it appears FF loses its 'place' in the scrolling container, and returns you to the top. This is only my theory, of course, but it does seem to match all the facts. So - what to do? Can you apply the styles currently on .column2 to .column2 .details? Probably the only thing required on .column2 itself is the width (to avoid redraw of the table). Failing that, perhaps you could markup the content without using a table. What sort of data is it? It is tabular, right?Chlamydospore
As far as jQuery selector performance goes, mine are more specific, and work as a series of fast operations on small collections of nodes. In particular, your $("[row='" + index + "']) selector requires inspecting every element in the whole page looking for the right row attribute. It's always more efficient to search based on a known node: in this case, we know the TD that was clicked on, so we start our search from there, first getting the siblings (which is a browser-native DOM operation), then searching their children (also DOM native).Chlamydospore
Setting the width of column2 does not help. Finally, I used scrollTo() function to get the scroll bar value before the fading operation, and then set it back after the fading. It's not an ideal solution because there is some flickering effect, but it is also not too bad.Chorography
Setting the width of column2 will not help if you still show/hide column2 via toggling the display to 'none' and back (via fadeIn() and fadeOut() in this case).Chlamydospore
R
1

I copied and tried your code, on Firefox 3.6.3 and Chrome 5.0.375.29. And saw nothing what you described so I am at loss.

Scrollbar moved only when scrolling normally, not when clicking on the text.

Recor answered 16/5, 2010 at 15:51 Comment(3)
Very strange... Are you sure that you clicked on "Line 9" ? Here are the steps to see the problem: (1) (Re)Load the page (2) Move the scroll bar to see "Line 9" (3) Click on "Line 9". After this click the scroll bar is moved up automatically such that I see only "Line 0", "Line 1", "Line 2", and "Line 3". Am I the only one that experiencing this problem ?Chorography
@Misha Ah, now that I followed your instructions I see it. However to fix it, I changed the .fadeIn() and .fadeOut to .css("display", "block") and .css("display", "none") and the scrolling started to work as intented.Recor
Mattijle: Setting table cells to 'display:block' will side-step the problem, but cause other issues, as the cells are no longer effectively part of the table structure. I think this simple example doesn't show up these problems, but it isn't a good idea in a real life scenario. When you fadeIn() or fadeOut() a table cell with jQuery, jQuery toggles the display between 'none' and 'table-cell' which is correct.Chlamydospore

© 2022 - 2024 — McMap. All rights reserved.