Bardzo, bardzo, bardzo duży div


109

W przypadku mojego projektu (zobacz projekt BigPictu.re lub bigpicture.js na GitHubie ) mam do czynienia z potencjalnie bardzo, bardzo, bardzo dużym <div>kontenerem.

Wiedziałem, że istnieje ryzyko słabej wydajności przy prostym podejściu, którego używam, ale nie spodziewałem się, że będzie to głównie obecne w ... Tylko Chrome!

Jeśli przetestujesz tę małą stronę (zobacz kod poniżej), panoramowanie (kliknij + przeciągnij) będzie wyglądać następująco:

  • Normalny / gładki w przeglądarce Firefox
  • Normalny / płynny nawet w przeglądarce Internet Explorer
  • Bardzo wolno (prawie się zawiesza) w Chrome!

Oczywiście mógłbym dodać kod (w moim projekcie), aby to zrobić, gdy jesteś bardzo powiększony, tekst z potencjalnie bardzo dużą czcionką byłby ukryty. Ale nadal, dlaczego Firefox i Internet Explorer obsługują to poprawnie, a nie Chrome?

Czy istnieje sposób w JavaScript, HTML lub CSS, aby poinformować przeglądarkę, aby nie próbowała renderować całej strony (która ma tutaj szerokość 10000 pikseli) dla każdego działania? (renderuj tylko bieżącą rzutnię!)


<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <style>
            html, body {
                overflow: hidden;
                min-height: 100%; }

            #container {
                position: absolute;
                min-height: 100%;
                min-width: 100%; }

            .text {
                font-family: "Arial";
                position: absolute;
            }
        </style>
    </head>

    <body>
        <div id="container">
            <div class="text" style="font-size: 600px; left:100px; top:100px">Small text</div>
            <div class="text" style="font-size: 600000px; left:10000px; top:10000px">Very big text</div>
        </div>

        <script>
            var container = document.getElementById('container'), dragging = false, previousmouse;
            container.x = 0; container.y = 0;

            window.onmousedown = function(e) { dragging = true; previousmouse = {x: e.pageX, y: e.pageY}; }

            window.onmouseup = function() { dragging = false; }

            window.ondragstart = function(e) { e.preventDefault(); }

            window.onmousemove = function(e) {
                if (dragging) {
                    container.x += e.pageX - previousmouse.x; container.y += e.pageY - previousmouse.y;
                    container.style.left = container.x + 'px'; container.style.top = container.y + 'px';
                    previousmouse = {x: e.pageX, y: e.pageY};
                }
            }
        </script>
    </body>
</html>

54
[OT] Rozmiar czcionki 600 KB. Czy musi to być funkcja ułatwień dostępu dla osób o bardzo złym wzroku? ;-)
geert3

61
@ geert3 Jestem pewien, że to dla księżycowej orbitującej przeglądarki internetowej
David Wilkins,

3
Twoje demo działa płynnie w Chrome 41.0.2236.0 dev-m
Pier-Luc Gendreau,

11
Jestem w stanie kanarek (41.0.2241.0 kanarek) i nadal mam opóźnienie. Powinniście wypróbować to na laptopie zamiast na
konsoli

3
Wbrew powszechnemu przekonaniu IE jest w rzeczywistości szybszy niż Chrome w przypadku renderowania większości stron. Jego silnik javascript jest jednak trochę wolniejszy.
Falanwe

Odpowiedzi:


62

Zmiana na position: fixedwydaje się przyspieszać.


27
Nie jest to bezpośrednia odpowiedź na jego pytanie, ale potencjalne rozwiązanie jego początkowego problemu (powolna odpowiedź w Chrome). Należy zachęcać do myślenia nieszablonowego, IMHO.
geert3

Tutaj wydaje się działać idealnie: gget.it/e0ubdh67/big-div-test_fixed.html . Wiesz dlaczego ? :)
Basj

2
Mogę się tylko domyślać. fixedjest oczywiście mniej skomplikowany do rozplanowania i być może mogą przeprowadzić więcej optymalizacji. Ale nie spojrzałem na kod źródłowy silnika renderującego, jeśli tak masz na myśli ;-)
geert3

1
Ta odpowiedź, jak i ta udzielona przez ViliusL, mają ten sam komentarz „zostaw komentarz”, napisany przez różne osoby. Jakie to jest świetne?
Joe

2
@Joe pochodzą z zestawu standardowych odpowiedzi dostarczonych przez StackOverflow do użytku przez moderatorów. Niektórzy muszą jednak moderować bardziej umiarkowanie.
geert3

42

Użyj transformzamiast top/left:

container.style.transform = 'translate(' + container.x + 'px, ' + container.y + 'px)';

Demo na żywo w jsFiddle .


2
Bardzo dziwna rzecz: w jsFiddle, to szybko z Chrome rzeczywiście. Zrobiłem dokładnie modyfikację, którą proponujesz w moim oryginalnym kodzie tutaj: gget.it/1owxq8kr/big-div-test_transform.html , a ten ostatni link jest wolny w Chrome :( Jak to możliwe? Wygląda tak samo jak twój jsFiddle ! [Uwaga: cudownie, odpowiedzi geert3 wydają się działać, nie wiem dlaczego, ale działają: gget.it/e0ubdh67/big-div-test_fixed.html]
Basj

@Basj Może to zależy od wersji, mój Chrome (39.0.2171.71 m) przesuwa stronę, do której link znajduje się w Twoim komentarzu, tak płynnie i szybko jak FF. W każdym razie ustawienie pozycji na fixedusuwa element z przepływu tekstu i oszczędza wiele ponownego renderowania. W dokumentacji transformMDN jest napisane: "... zostanie utworzony kontekst stosu. W takim przypadku obiekt będzie działał jako blok zawierający pozycję: ustalone elementy, które zawiera."
Teemu

2
Dziwne, mam też Chrome 39.0.2171.71 m ... a gget.it/1owxq8kr/big-div-test_transform.html patrzy wolno, tak wolno jak moja oryginalna wersja (w samym pytaniu). Oohhh prawdopodobnie zależy to od akceleracji sprzętowej: prawdopodobnie nie mam akceleracji sprzętowej, ponieważ mam laptopa ze słabym układem graficznym ...
Basj

1
@Basj add a wrapper <div style="position:relative;min-height: 900px;">Your's divs</div>jsFiddle so does
Alfonso Rubalcava

1
@AlfonsoRubalcava O ok ... To wyjaśnia, dlaczego jsfiddle jest płynne, a bezpośredni link nie jest gładki (Chrome): gget.it/1owxq8kr/big-div-test_transform.html ! Dzięki! Tak więc poprawa wydajności wynika position:relativeprawdopodobnie z odpowiedzi, która jest podobna do odpowiedzi
geert3

22
  1. Odpowiedz na pierwsze pytanie „dlaczego”. Jednym z problemów jest rozmiar czcionki . masz czcionkę o rozmiarze 600000 pikseli, większość przeglądarek uzna ją za zbyt wysoką i renderuje ją jako mniejszą, podczas gdy chrome próbuje renderować oryginalny rozmiar. Wygląda na to, że chrome nie może bardzo szybko przemalować tak dużych liter żądanymi stylami.

Ale połączenie odpowiedzi Teemu i geert3 - używając transform i position: fixed, sprawia, że ​​chrome działa znacznie szybciej nawet z dużymi czcionkami.

  1. Odpowiedź na pytanie drugie: „Czy jest sposób ... aby nie próbować renderować całej strony” - możesz spróbować zastosować akcję myszy dla elementów w kontenerze, a nie dla całego kontenera.

Maksymalne rozmiary czcionek: http://jsfiddle.net/74w7yL0a/

firefox 34 - 2 000 px
chrome 39 - 1 000 000 px
safari 8 - 1 000 000 px
ie 8-11 - 1 431 700 px

6
Właściwie tak. OP stawia dwa pytania, z których odpowiedź na pierwsze pytanie brzmi: „dlaczego FF, IE radzi sobie z tym poprawnie, a nie Chrome?”
Hans Roerdinkholder

Ciekawy. Czy masz na myśli jakieś elementy, które pokazują, że Firefox zatrzymuje się na 10 KB i że Chrome próbuje renderować oryginalny rozmiar? (Byłoby to interesujące do wykorzystania w przyszłości). Z góry dziękuję @ViliusL!
Basj

1
@Basj dodał maksymalne rozmiary czcionek dla każdej przeglądarki (testowane dzisiaj) i wynosi 2k dla Firefoksa.
ViliusL

Wielkie dzięki @ViliusL! Rzeczywiście, FF ogranicza font-sizei może to być powodem braku spowolnienia na FF. Ale wtedy powinno być też bardzo wolno w IE, ale to nie jest ... Dziwne!
Basj

4

Oprócz odpowiedzi Teemu dotyczącej korzystania z translacji:

container.style.transform = 'translate(' + container.x + 'px, ' + container.y + 'px)';

Które powinieneś również użyć prefiksów innych dostawców, możesz to po prostu naprawić, używając tego w treści:

height: 100%;
width: 100%;
position: relative;
overflow: hidden;

a to w html:

height: 100%;

spowoduje to jednak wyłączenie przewijania. Więc to, co zrobiłbym, to dodać mousedownzdarzenie do treści i zastosować te style za pomocą klasy css, gdy mousedownzostanie wyzwolona, ​​i usunąć tę klasę mouseup.


Próbowałem dodać to, o czym tutaj wspomniałeś: gget.it/0ufheqmt/big-div-test_prisonersolution.html , czy o to Ci chodziło? Tutaj nadal wolno przeciągać za pomocą Chrome. Nawzajem? (PS: I nie rozumiem: proponujesz robić te modyfikacje CSS zamiast korzystania style.transformalbo z użyciem transform?). Dzięki za odpowiedź @Prisoner!
Basj

2

Odpowiedź @Teemusa prawie wszystko.

Użyj transform ztranslate3d zamiast top/left.

translate3d włącza akcelerację sprzętową.

container.style.transform = 'translate3d(' + container.x + 'px, ' + container.y + 'px, 0)';

Demo na żywo w jsFiddle .


1

Przeanalizowałem to i odkryłem, że pierwotny problem dotyczył architektury wyświetlania Chrome i wykorzystania wątków w tle do renderowania strony.

Jeśli chcesz mieć szybkie renderowanie, wejdź do chrome: flags, przewiń do ustawienia Malowanie po stronie implantu i ustaw „Wyłączone”, a następnie zrestartuj przeglądarkę - ruch myszy będzie płynny.

Odkryłem, że jeśli włączysz licznik FPS, raportowany FPS w tym scenariuszu jest nadal bardzo wysoki, mimo że rzeczywista wydajność na ekranie jest bardzo niska. Moje wstępne wyjaśnienie (nie będąc ekspertem od architektury wyświetlaczy Chrome) jest takie, że jeśli wątek interfejsu użytkownika i ekran są w osobnych wątkach, może wystąpić rywalizacja w renderowaniu elementu div - w przypadku, gdy wątek interfejsu użytkownika i wątek renderowania znajdują się w W tym samym wątku wątek interfejsu użytkownika nie może wysyłać wiadomości szybciej niż może renderować wątek interfejsu użytkownika.

Sugerowałbym, że powinno to zostać zgłoszone jako błąd Chrome.


1

Użyj display: tablei table-layout:fixedna div lub tabeli zawijającej div. W HTML:

Model tabeli HTML został zaprojektowany w taki sposób, że z pomocą autora programy użytkownika mogą renderować tabele przyrostowo (tj. W miarę pojawiania się wierszy tabeli), zamiast czekać na wszystkie dane przed rozpoczęciem renderowania.

Aby agent użytkownika mógł sformatować tabelę w jednym przebiegu, autorzy muszą przekazać mu:

Liczba kolumn w tabeli. Szczegółowe informacje na temat sposobu podawania tych informacji można znaleźć w części dotyczącej obliczania liczby kolumn w tabeli. Szerokości tych kolumn. Szczegółowe informacje na temat sposobu podawania tych informacji można znaleźć w części dotyczącej obliczania szerokości kolumn.

Dokładniej, agent użytkownika może renderować tabelę w jednym przebiegu, gdy szerokości kolumn są określone przy użyciu kombinacji elementów COLGROUP i COL. Jeśli którakolwiek z kolumn jest określona w kategoriach względnych lub procentowych (patrz rozdział dotyczący obliczania szerokości kolumn), autorzy muszą również określić szerokość samej tabeli.

Do wyświetlania przyrostowego przeglądarka potrzebuje liczby kolumn i ich szerokości. Domyślną szerokością tabeli jest bieżący rozmiar okna (szerokość = „100%”). Można to zmienić, ustawiając atrybut szerokości elementu TABLE. Domyślnie wszystkie kolumny mają tę samą szerokość, ale można określić szerokości kolumn za pomocą co najmniej jednego elementu COL przed rozpoczęciem danych tabeli.

Pozostała kwestia to liczba kolumn. Niektórzy sugerują, że zaczekaj do odebrania pierwszego wiersza tabeli, ale może to zająć dużo czasu, jeśli komórki mają dużo zawartości. Ogólnie rzecz biorąc, gdy pożądane jest wyświetlanie przyrostowe, bardziej sensowne jest skłonienie autorów do jawnego określenia liczby kolumn w elemencie TABLE.

Autorzy nadal potrzebują sposobu, aby powiedzieć agentom użytkownika, czy mają używać wyświetlania przyrostowego, czy też automatycznie dopasowywać rozmiar tabeli do zawartości komórki. W dwuprzebiegowym trybie automatycznej zmiany rozmiaru liczba kolumn jest określana przez pierwszy przebieg. W trybie przyrostowym liczbę kolumn należy podać z góry (z elementami COL lub COLGROUP).

i CSS:

17.5.2.1 Stały układ tabeli

Dzięki temu (szybkiemu) algorytmowi poziomy układ tabeli nie zależy od zawartości komórek; zależy to tylko od szerokości tabeli, szerokości kolumn i obramowań lub odstępów między komórkami.

Szerokość tabeli można określić jawnie za pomocą właściwości „width”. Wartość „auto” (zarówno dla „display: table”, jak i „display: inline-table”) oznacza użycie algorytmu automatycznego układu tabeli. Jeśli jednak tabela jest tabelą na poziomie bloku ('display: table') w normalnym przepływie, UA może (ale nie musi) użyć algorytmu 10.3.3 do obliczenia szerokości i zastosowania stałego układu tabeli, nawet jeśli określona szerokość to „auto”.

Bibliografia

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.