Проблема с прокруткой в ​​опере - PullRequest
2 голосов
/ 26 октября 2010

Обновление: я оставил следующий код javascript, чтобы показать, как проблема развивалась с течением времени, но теперь выясняется, что это НЕ актуально, поскольку проблема не в javascript. Пожалуйста, посмотрите на HTML / CSS код ниже.

Для страницы обзора с большим меню я реализовал следующую функцию (, большую часть которой я украл отсюда ):

function isScrolledIntoView(elem)
{
    var docViewTop = $(window).scrollTop();
    var docViewBottom = docViewTop + $(window).height();

    var elemTop = $(elem).offset().top;
    var elemBottom = elemTop + $(elem).height();

    alert(elemBottom);

    return ((elemBottom >= docViewTop) && (elemTop <= docViewBottom));
}

$(document).ready(function(){
 var overview = $('#overview');
 var active = $('#active-item');
 if (!isScrolledIntoView(active))
 {
  $('#overview li.active-parent').each(function(index, value){
   if (!isScrolledIntoView(active)) overview.scrollTo(value);
  });
 }
 if (!isScrolledIntoView(active)) overview.scrollTo(active);
});

Идея состоит в том, что после каждой загрузки страницы содержащее меню прокручивается в положение, где виден текущий # активный-элемент. Желательно прокрутить до его первого родителя (элементы меню находятся в дереве), в противном случае до самого элемента.

Теперь это отлично работает в Firefox и Chrome (и никто из яблочных людей не жаловался мне), но Opera делает действительно странную вещь: она прокручивает до нужного элемента, затем очень коротко останавливается, прежде чем прокрутить все путь вверх снова

У кого-нибудь есть идеи?

  1. Что происходит, и
  2. Как я могу это остановить?

Спасибо


Обновление: я тестирую с версией 10.63 на Linux (Fedora)


Обновление: похоже, я искал не в том направлении. Похоже, проблема связана с CSS и может быть воспроизведена с помощью следующего кода:

<html>

<head>

<title>Opera scroll test</title>

  <style>
    .main:after
    {
      content: 'abc';
    }

    :focus
    {
      padding: 0px;
    }

    #overview
    {
      display: block;
      float: left;
      width: 219px;
      height: 500px;
      overflow: auto;

    }
  </style>

</head>

<body>

  <div id="main" class="main">

    <div id="overview">
      <ul>
        <?
        for($i = 1; $i < 100; $i++)
          echo '<li>'.$i.'</li>';
        ?>

      </ul>
    </div>
    <div>

      <p>123</p>

    </div>

  </div>

</body>
</html>

Теперь, если вы прокрутите вниз панель навигации и переместите указатель мыши вправо (поверх панели содержимого), прокрутка панели навигации будет сброшена.

Извините, что тратит время на охоту на JavaScript: (

Если есть какие-нибудь гсс-гуру, которые знают, как это исправить, или которые могут просто объяснить, что происходит, я был бы очень благодарен.


Обновление: проверенный выше код в Windows на Opera 10.63. Такое же странное поведение происходит.


Обновление: сообщили об этом в Opera как об ошибке. Интересно, что будет ...

Ответы [ 4 ]

2 голосов
/ 03 ноября 2010

Не знаю, почему, но проблема, похоже, напрямую связана с настройкой .main:after content CSS.Можете ли вы использовать JQuery?Если это так, если вы закомментируете или удалите параметр CSS .main:after и замените его следующим скриптом в теге <head>, вы получите тот же визуальный результат без странной проблемы с прокруткой:

<script type="text/javascript">
  $(document).ready(function(){
    $(".main").append("abc");
  });
</script>
2 голосов
/ 29 октября 2010

У меня есть представление о том, что происходит, однако я попробовал ваш код и до сих пор не могу воспроизвести проблему.Chrome и Opera ведут себя одинаково.

Это HTML-код, который я пробовал:

<div id="overview" style="height: 300px;overflow-y: scroll;">
 <ul>   
  <li class="item" style="height: 400px;">item 1</li>
  <li class="item" style="height: 400px;">item 2 </li>
  <li class="active-parent" style="height: 400px;">active-parent<br/><br/>
    <ul>
      <li id="active-item" style="height: 300px;">active-item</li>
    </ul>
  </li>
 </ul>
</div>

Почему он не работает в Opera: Какую версию Opera вы используете? Я пытался 10.63 (последний) и хорошо на этом.

Поскольку я не могу воспроизвести проблему, я собираюсь сделать слепую попытку:

Попробуйте ввести небольшую задержку, чтобы этот код выполнялся после всего остального в очереди:

$(document).ready(function() {
  window.setTimeout(function() {
    // Your code goes here
  }, 500);
});

ПОСЛЕДНЕЕ ДОБАВЛЕНИЕ:

В ответ на ваше заявление: «Я действительно хотел бы понять, что здесь происходит. Почему задержка? И нужно ли задержкубыть медленнее на медленных компьютерах? ":

Если установка задержки решает вашу проблему, то причина ясна, есть какой-то другой фрагмент кода, мешающий функционированию" прокрутки вверх ", который выполнялся после него.Установив задержку в 500 мс, вы убедитесь, что ваш код запускается после каждого другого фрагмента Javascript , который выполняется при загрузке документа, это может быть то, что вы явно добавили в очередь функций jQuery при загрузке документа(используя $(document).ready(function(){) или неявно добавлено Opera в виде «виджета» (у вас есть какие-либо инструменты перевода, панели инструментов Google и т. д., установленные?).

Относительно того, должна ли задержка быть более длительной для медленных компьютеров, я лично не думаю, что ключ заключается в том, что задержка заставляет ваш код выполняться ПОСЛЕ КАЖДОГО ДРУГОГО СКРИПТА, запускаемого событием document.onload.Поскольку я подозреваю, что все, что мешает, выполняется в прямом правопреемстве после загрузки документа, вам на самом деле не нужна очень большая задержка, даже 50 мсек может сделать это, ключ в том, что задержка заставляет ваш код идтив конце очереди.

Надеюсь, это поможет прояснить ситуацию.

1 голос
/ 01 ноября 2010

Это всего лишь теория, но вы можете начать.

Когда вы нажимаете в браузере, это часто приводит вас к точке на странице, где вы в последний раз просматривали.

Возможно ли, что опера пытается подвести вас к той точке, которая мешает вашему коду?

Интересно, очистите ли вы свою историю / кэш, уничтожите оперный процесс и начните с нового процесса. Имеет ли это какое-либо значение.

1 голос
/ 31 октября 2010

Как отметил Стивен де Салас, добавление задержки помогает -> $ (window) .scrollTop () возвращает 0, если не задержано !!

Я немного поиграл и придумал этот пример:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Scrolling Test</title>

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.3/jquery.min.js" type="text/javascript"></script>
<style type="text/css">
.parent { margin-bottom:100px; border:1px solid red; }
</style>

<script type="text/javascript">

(function ($){
    $.fn.extend({
        viewport : function(){
            if (this.length > 0) {

                var element = $(this.get(0)),
                pad = $.fn.viewport.PADDING,
                vp = {
                    height : element.height() + 2 * pad,
                    top : element.offset().top - pad,
                    docHeight : $(window).height(),
                    docTop : $(window).scrollTop(),
                    completelyInViewport : false
                };
                vp.bottom = vp.top + vp.height + pad;
                vp.docBottom = vp.docTop + vp.docHeight;
                vp.fitsInViewport = vp.height <= vp.docHeight;

                if (vp.top > vp.docTop && vp.bottom < vp.docBottom) {
                    vp.completelyInViewport = true;
                }

                return vp;
            }

            return null;
        }
    });

    $.fn.extend($.fn.viewport, {
        PADDING: 10, // ADJUST TO YOUR NEEDS
        LARGE_PARENT_BEHAVIOR: "bottom" // if parent list is bigger than viewport and 
                                        // the active item is not in the first page of 
                                        // the parents list, where should it be shown
                                        // possible: "bottom", "middle" or "top"
    });

    $.extend({
        ensureViewport: function(element, parent) {
            var e_vp = element.viewport(),
            p_vp = parent.viewport();

            if (null == e_vp || null == p_vp) {
                return;
            }

            if (!p_vp.completelyInViewport) {
                if (p_vp.fitsInViewport || e_vp.bottom - p_vp.top <= e_vp.docHeight) {
                    doScroll(p_vp.top);
                } else {
                    switch($.fn.viewport.LARGE_PARENT_BEHAVIOR) {
                        case "top":
                            doScroll(e_vp.top);
                            break;
                        case "middle":
                            doScroll(e_vp.top - (e_vp.docHeight - e_vp.height)/2);
                            break;
                        case "bottom":
                        default:
                            doScroll(e_vp.bottom - e_vp.docHeight);
                            break;
                    }
                }
            }

            function doScroll(y){
                window.scrollTo(0, y);
                // you could implement instead some sort of smooth scroling mechanism here
                // e.g. http://github.com/kswedberg/jquery-smooth-scroll
            }
        }
    });

    $(function(){
        window.setTimeout(function(){
            var item = $("li.active-item");
            if (item.size() > 0) {
                $.ensureViewport(item, item.closest("li.parent"));
            }
        }, 0);
    });
})(jQuery);

</script> 

</head>
<body>

<div id="overview">
 <ul>
  <li class="parent">
   parent 1
   <ul class="item"><li>item 1</li><li>item 2</li></ul>
  </li>
  <li class="parent">
   parent 2
   <ul class="item"><li>item 1</li><li>item 2</li></ul>
  </li>
  <li class="parent">
   parent 3
   <ul class="item"><li>item 1</li><li>item 2</li></ul>
  </li>
  <li class="parent">
   parent 4
   <ul class="item"><li>item 1</li><li class="active-item">item 2</li></ul>
  </li>
  <li class="parent">
   parent 5
   <ul class="item"><li>item 1</li><li>item 2</li></ul>
  </li>
  <li class="parent">
   parent 6
   <ul class="item"><li>item 1</li><li>item 2</li></ul>
  </li>
  <li class="parent">
   parent 7
   <ul class="item"><li>item 1</li><li>item 2</li></ul>
  </li>
 </ul>
</div>

</body>
</html>

Протестировал его в Opera 10.63, и он тоже там работает.

Приветствия

...