Mobile Webkit reflow problem

Doświadczam problemu w mobilnych wersjach webkit (w szczególności Webkit 534.46 na iOS 5.1.1 jako mobile Safari, a teraz Chrome na iOS), który nie występuje w żadnej przeglądarce komputerowej, którą widziałem. (tzn. poniższe dema powinny być wyświetlane w mobilnej wersji webkit.)

Oto żywy przykład tego problemu. Rdzeń CSS jest bardzo prosty. Po lewej stronie znajduje się indeks alfabetu:

#index {
    left:0; margin:0; padding:0; position:fixed; top:0; width:3em;
}

The issue happens gdy element jest ustalona pozycja nad górną częścią ciała. Jest w pełni w stanie wejść w interakcję, dopóki nie zmieni się przewijanie, a następnie przestanie akceptować dane wejściowe. Jeśli (ręcznie) potrząsam przewijaniem nawet o jeden piksel, to staje się ponownie aktywny. Przykład był tak prosty, jak to tylko możliwe i nie używa żadnego JavaScript. Po naprawdę młotkiem na to, odkryłem, że wydaje się, że element myśli, że jest przewinięty, ale został wizualnie naprawiony. Innymi słowy, jeśli klikniesz na 'A' to spróbuj kliknąć na " A " ponownie, czasami dostaniesz drugie kliknięcie, ale będzie dalej w dół listy. Wydawało mi się to problemem CSS reflow. Wiem, że mobilny webkit próbuje zmniejszyć liczbę przepływów.

Oto przykład obejścia problemu.

Jestem w stanie użyć JS, aby zmusić CSS całego dokumentu do ponownego przewijania (z przepustnicą, która zapobiega temu do 100ms po przewinięciu), co wydaje się obejść ten problem w prostym przykładzie. Niestety, nie pomaga to w realnej wersji tego problemu.

Jest to kod strony problemu i skryptu obejścia problemu.

Moje pytanie brzmi, co się tutaj dzieje i czy istnieje obejście CSS, którego mi brakuje? konkretnie, jestem ciekaw, czy jakiś Guru CSS może rozgryźć, jaka jest sytuacja w układzie, który zapobiega kliknięciu w odpowiednie miejsce na stałym elemencie? Lepsze zrozumienie może pomóc w znalezieniu prawdziwego napraw.

Edit: zapomniałem wspomnieć, że przykład jawnie wymusza viewport do rozmiaru okna. Tak więc użytkownik nie może powiększać / pomniejszać, co oznacza, że pozycja:fixed powinna zakotwiczyć element po lewej stronie okna.

Jest to możliwe dzięki temu, że można go używać w przeglądarkach mobilnych. Każde obejście powinno najpierw sprawdzić, czy jest na iOS CssUserAgent wyglądałoby to like:

if (parseFloat(cssua.ua.ios) < 6) { /* ... */ }
Author: mckamey, 2012-07-02

6 answers

Odpowiedź, która faktycznie rozwiązała mój konkretny problem, była odmianą rozwiązania znalezionego w jednym z linków @ Paul Sweatte :

Zasadniczo dodaje się zwykły div, który jest wyższy od ciała. Gdy jest usuwany, powoduje, że ciało skutecznie przewija się lub reflow. Ustawienie opóźnienia na 0ms pomiędzy dodaniem/usunięciem jest wystarczające, aby DOM mógł ponownie obliczyć bez powodowania migotania. To był minimalny skrypt, który mogłem znaleźć, który w pełni rozwiązał problem dla wszystkich position:fixed elementy na mojej konkretnej instancji tego problemu.

var hack = document.createElement("div");
hack.style.height = "101%";
document.body.appendChild(hack);
setTimeout(function(){
    document.body.removeChild(hack);
    hack = null;
}, 0);
 9
Author: mckamey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:25:05

Jak na ironię, moja oryginalna poprawka reflow (powiązana z pytaniem) działa teraz również w mojej prawdziwej aplikacji. Umieszczenie jego wariantu tutaj w przypadku jest przydatne dla kogokolwiek innego. Może być wywołana na dowolnym elemencie kontenera, lub jeśli nic nie zostanie przekazane, przepłynie cały dokument.

var forceReflow = function(elem){
    elem = elem || document.documentElement;

    // force a reflow by increasing size 1px
    var width = elem.style.width,
        px = elem.offsetWidth+1;

    elem.style.width = px+'px';

    setTimeout(function(){
        // undo resize, unfortunately forces another reflow
        elem.style.width = width;
        elem = null;
    }, 0);
};

Fajne w tym jest to, że nie wymaga tworzenia / dodawania / usuwania elementów, tylko poprawiania kontenera.

 6
Author: mckamey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-13 22:20:46

Moja instalacja iWebInspector jest dość zepsuty teraz, ale po bałagan wokół z jsfiddle i iOS sim wydaje się, że Twoje przeczucie jest poprawne-pomimo pozycji: stałe, przeglądarka myśli, że strona przewijała, i wkręca się cele kliknięcia.

Wygląda na to, że jest to ten sam problem co iOS Safari: kotwice w elemencie o stałej pozycji działają tylko raz , co również nie zostało rozwiązane za pomocą czystego CSS. Również powiązane: stała pozycja navbar tylko klikalne raz w Mobile Safari na iOS5.

Stycznie, a jestem pewien, że już to zauważono, nie można przewijać lewej strony, więc na iPhonie indeks pokazuje tylko A-M.

 2
Author: egid,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:33:58

Wygląda na to, że jest to znany błąd :

Podstawowy problem polega na tym, że jeśli strona porusza się programowo (tzn. użytkownik nie spowodował przewijania) elementy wewnątrz elementu fix są niedostępne.

Użyj pozycjonowania bezwzględnego, Zmień znaczniki lub użyj jednego z obejść hybrydowych .

 2
Author: Paul Sweatte,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:45:35

Oto odmiana obejścia McKamey ' a. Pozwala uniknąć dwukrotnego ponownego napełniania i może pomóc w migotaniu (w zależności od aplikacji): {]}

setTimeout(function(){
    document.body.style.borderBottom = 
        document.body.style.borderBottom === 'none' ? '1px solid white' : 'none';
}, 0);
 0
Author: csytan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-10 09:16:24

Uważam, że jest to lepsze i osiąga ten sam efekt, pozwalając na klikanie linków w stopkach stałych. W jakiś sposób ukrywanie urlbara powoduje, że linki w stałej stopce nie są klikalne, dopóki nie przewiniesz trochę. Widziałem to też podczas ustawiania ostrości i dołączam obsługę zdarzeń do wszystkich zdarzeń ostrości, aby również to odpalić. Robię to z dojo, aby dołączyć wydarzenia.

        if(navigator.userAgent.match(/iPhone/i)){
        /* The famous iOS can't-click-links until touch fix, I attach onfocus */
            query('input,textarea,select', this.domNode).on('focus', function(el){
                document.documentElement.style.paddingRight = '1px';
                setTimeout(function () {
                document.documentElement.style.paddingRight = '';
                }, 0);
            });
        }
 0
Author: httpete,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-20 16:17:18