Проблем със скролирането в opera

Актуализация: Оставих следния 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);
});

Идеята е, че след всяко зареждане на страницата, съдържащото менюто се превърта до позиция, където се вижда текущият #active-item. За предпочитане чрез превъртане до неговия първи родител (елементите от менюто са в дърво), в противен случай до самия елемент.

Сега това работи добре във Firefox и Chrome (и никой от хората на Apple не ми се е оплакал), но 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 :(

Ако има някакви css гурута, които знаят как да го поправят, или които могат просто да обяснят какво се случва, ще съм много благодарен.


Актуализация: тествах горния код в windows на opera 10.63. Появява се същото странно поведение.


Актуализация: докладвахме това на Opera като грешка. Чудя се какво ще стане...


person Michael Clerx    schedule 26.10.2010    source източник
comment
Можете ли да обясните защо не използвате само родния API за scrollIntoView() за това?   -  person Pointy    schedule 28.10.2010
comment
За първи път го чувам... Опитах го сега и има същото поведение в операта   -  person Michael Clerx    schedule 28.10.2010
comment
ЛИПСВА ВЕРСИЯ НА OPERA. jsFiddle би бил полезен. И съветът: Опитайте прост едноредов метод със scrollTo(), за да видите дали работи.   -  person naugtur    schedule 29.10.2010
comment
Изглежда, че се случва в множество случаи: проблемът не е тясно свързан с точния код, публикуван по-горе.   -  person Michael Clerx    schedule 29.10.2010
comment
защо не опитате да тествате с различни версии на Opera/OS...? вашият код изглежда добре.   -  person sdadffdfd    schedule 02.11.2010
comment
Пробвах го на windows, там прави същото...   -  person Michael Clerx    schedule 02.11.2010
comment
Здравей, Майкъл, както казва Стивън де Салас, проблемът може да е свързан с наличието на друга част от кода във вашия източник, който може да пречи! можете ли да потвърдите тази теория, като я тествате, като изолирате кода си и видите дали работи!?   -  person Luca Filosofi    schedule 03.11.2010
comment
Здравейте, aSeptik, моля, разгледайте безплатната за javascript, само css версия на същия бъг в актуализираната ми публикация. Добавих този код преди 2 дни, но сега осъзнавам, че съобщението не е много ясно. Ще се опитам да го актуализирам. Благодаря!   -  person Michael Clerx    schedule 03.11.2010


Отговори (4)


Не съм сигурен защо, но проблемът изглежда пряко свързан с настройката .main:after content CSS. Можете ли да използвате jQuery? Ако е така, ако коментирате или премахнете .main:after CSS настройката и я замените със следния скрипт във вашия <head> маркер, ще получите същия визуален резултат без странния проблем с превъртането:

<script type="text/javascript">
  $(document).ready(function(){
    $(".main").append("abc");
  });
</script>
person 300 baud    schedule 03.11.2010
comment
Благодаря! Ще го предложа на нашия css човек :) - person Michael Clerx; 03.11.2010
comment
Ако превъртите div прегледа и след това преместите курсора надясно извън този div, но оставите курсора в основния div (например над 123 или abc съдържание), тогава странното превъртане до върха не се случва. Това се случва само когато преместите курсора извън основния div. Това странно поведение не се случва, ако съдържанието abc не е приложено чрез ключовата дума CSS content. Следователно ми се струва, че е проблем с това как Opera обработва ключовата дума CSS content. - person 300 baud; 04.11.2010
comment
Странно. Е, сега го докладвах на Opera като грешка. Благодаря много за отделеното време, съжалявам, че закъснях да ви дам наградата. Надявах се някой, който се е занимавал с този проблем преди, все пак да се появи :) - person Michael Clerx; 05.11.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 ms, вие гарантирате, че вашият код се изпълнява след всяка друга част от Javascript, която се изпълнява при зареждане на документ, това може да е нещо, което изрично сте добавили към опашката на функцията jQuery, когато документът зарежда (използвайки $(document).ready(function(){), или имплицитно добавен от Opera под формата на "Widget" (имате ли инсталирани инструменти за превод, лентите с инструменти на Google и т.н.?).

Що се отнася до това дали забавянето трябва да бъде по-дълго за по-бавни компютри, аз лично не мисля така, ключът е, че забавянето принуждава вашия код да се изпълни СЛЕД ВСЕКИ ДРУГ СКРИПТ, задействан от събитието document.onload. Тъй като моето подозрение е, че каквото и да се намесва, се изпълнява в директна последователност след като документът се зареди, всъщност нямате нужда от много дълго забавяне, дори 50ms може да го направят, ключът е, че забавянето принуждава кода ви да отидете най-отзад на опашката.

Надявам се това да помогне да направим нещата по-ясни.

person Steven de Salas    schedule 29.10.2010
comment
Благодаря Стивън, аз също използвам версия 10.63 - person Michael Clerx; 30.10.2010
comment
Благодаря за всичките ти усилия Стивън! - person Michael Clerx; 01.11.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 и там също работи.

наздраве

person roberkules    schedule 31.10.2010
comment
Благодаря за отговора! Наистина бих искал да разбера какво се случва тук. Защо забавяне? И трябва ли забавянето да е по-дълго на по-бавни компютри? - person Michael Clerx; 31.10.2010

Това е само теория, но може да ви помогне да започнете.

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

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

Чудя се дали изчистите историята/кеша си, убиете процеса на Opera и започнете с нов процес. Това има ли някаква разлика.

person Alex KeySmith    schedule 01.11.2010
comment
Благодаря! Добра идея, но без резултат :) - person Michael Clerx; 01.11.2010