Ein sehr, sehr, sehr großer Div

109

Für ein Projekt von mir (siehe BigPictu.re oder bigpicture.js GitHub-Projekt ) muss ich mich möglicherweise mit einem sehr, sehr, sehr großen <div>Container befassen .

Ich wusste, dass bei dem einfachen Ansatz, den ich verwende, das Risiko einer schlechten Leistung besteht, aber ich hatte nicht erwartet, dass er hauptsächlich mit ... nur Chrome vorhanden ist!

Wenn Sie diese kleine Seite testen (siehe Code unten), lautet das Schwenken (Klicken + Ziehen) wie folgt:

  • Normal / glatt bei Firefox
  • Normal / glatt auch im Internet Explorer
  • Sehr langsam (fast abstürzend) auf Chrome!

Natürlich könnte ich (in meinem Projekt) Code hinzufügen, um dies zu tun. Wenn Sie viel hineingezoomt haben, wird Text mit möglicherweise sehr großer Schriftgröße ausgeblendet. Aber warum gehen Firefox und Internet Explorer richtig damit um und nicht mit Chrome?

Gibt es in JavaScript, HTML oder CSS eine Möglichkeit, den Browser anzuweisen, nicht zu versuchen , die gesamte Seite (die hier 10000 Pixel breit ist) für jede Aktion zu rendern? (Nur das aktuelle Ansichtsfenster rendern!)


<!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>
Basj
quelle
54
[OT] 600K Schriftgröße. Muss eine Zugänglichkeitsfunktion für Personen mit sehr schlechtem Sehvermögen sein? ;-)
geert3
61
@ geert3 Ich bin sicher, es ist für einen Mond umlaufenden Webbrowser
David Wilkins
3
Ihre Demo ist flüssig in Chrome 41.0.2236.0 dev-m
Pier-Luc Gendreau
11
Ich bin auf Kanarienvogel (41.0.2241.0 Kanarienvogel) und bekomme immer noch die Verzögerung. Ihr
solltet
3
Entgegen der landläufigen Meinung ist der IE beim Rendern der meisten Seiten tatsächlich schneller als Chrome. Die Javascript-Engine ist allerdings etwas langsamer.
Falanwe

Antworten:

62

Der Wechsel zu position: fixedscheint die Dinge zu beschleunigen.

geert3
quelle
27
Es ist keine direkte Antwort auf seine Frage, aber es ist eine mögliche Lösung für sein ursprüngliches Problem (langsame Antwort in Chrome). Über den Tellerrand hinaus zu denken sollte ermutigt werden, IMHO.
Geert3
Hier scheint es perfekt zu funktionieren: gget.it/e0ubdh67/big-div-test_fixed.html . Weißt du, warum ? :)
Basj
2
Ich kann nur raten. fixedDas Layout ist offensichtlich weniger komplex und sie können möglicherweise mehr Optimierungen vornehmen. Aber ich habe mir den Quellcode der Rendering-Engine nicht angesehen, wenn du das meinst
;-)
1
Diese und die von ViliusL bereitgestellte Antwort haben beide den gleichen Kommentar "Hinterlasse einen Kommentar" von verschiedenen Personen. Wie cool ist das?
Joe
2
@ Joe, diese stammen aus einer Reihe von Standardantworten, die von StackOverflow zur Verwendung durch Moderatoren bereitgestellt werden. Einige müssen jedoch moderater moderieren.
Geert3
42

Verwenden Sie transformanstelle von top/left:

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

Eine Live-Demo bei jsFiddle .

Teemu
quelle
2
Eine sehr seltsame Sache: In Ihrer jsFiddle ist es mit Chrome in der Tat schnell. Ich habe genau die Änderung vorgenommen, die Sie in meinem ursprünglichen Code hier vorgeschlagen haben: gget.it/1owxq8kr/big-div-test_transform.html , und dieser letzte Link ist in Chrome langsam :( Wie ist das möglich? Es sieht genauso aus wie Ihre jsFiddle ! [Anmerkung: Wie durch ein Wunder scheinen die Antworten von geert3 zu funktionieren, ich weiß nicht warum, aber es funktioniert: gget.it/e0ubdh67/big-div-test_fixed.html]
Basj
@Basj Vielleicht ist es versionabhängig, mein Chrome (39.0.2171.71 m) schwenkt die in Ihrem Kommentar verlinkte Seite so flüssig und schnell wie FF. Wenn Sie die Position so einstellen, dass fixeddas Element aus dem Textfluss entfernt wird, sparen Sie viel Rendering. In der Dokumentation von transformMDN heißt es: "... wird ein Stapelkontext erstellt. In diesem Fall fungiert das Objekt als enthaltender Block für position: feste Elemente, die es enthält."
Teemu
2
Seltsamerweise habe ich auch Chrome 39.0.2171.71 m ... und gget.it/1owxq8kr/big-div-test_transform.html schwenkt langsam, so langsam wie meine ursprüngliche Version (in der Frage selbst). Oohhh möglicherweise hängt es von der Hardwarebeschleunigung ab: Ich habe wahrscheinlich keine Hardwarebeschleunigung, weil ich einen Laptop mit einem schlechten Grafikchip habe ...
Basj
1
@Basj füge einen Wrapper hinzu <div style="position:relative;min-height: 900px;">Your's divs</div>jsFiddle auch
Alfonso Rubalcava
1
@AlfonsoRubalcava Oh ok ... Dies erklärt, warum die jsfiddle glatt und der direkte Link nicht glatt ist (Chrome): gget.it/1owxq8kr/big-div-test_transform.html ! Vielen Dank! Die Verbesserung der Leistung position:relativeist also wahrscheinlich auf die Antwort von geert3 zurückzuführen
Basj
22
  1. Antworte auf die erste Quest "Warum". Eines der Probleme ist die Schriftgröße . Wenn Sie eine Schriftgröße von 600000px haben, wird diese von den meisten Browsern als zu hoch angesehen und kleiner gerendert, während Chrome versucht, die Originalgröße zu rendern. Sieht so aus, als könne Chrom so große Buchstaben nicht sehr schnell mit den gewünschten Stilen neu streichen.

Durch die Kombination von Teemu- und geert3-Antworten - mithilfe von Transformation und Position: Fixed - funktioniert Chrome auch bei großen Schriftarten viel schneller.

  1. Antwort auf die zweite Frage: "Gibt es eine Möglichkeit ... nicht zu versuchen, die gesamte Seite zu rendern" - Sie können versuchen, eine Mausaktion für Elemente im Container anzuwenden, nicht für den gesamten Container.

Maximale Schriftgröße: 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
ViliusL
quelle
6
Das tut es tatsächlich. Das OP stellt zwei Fragen, von denen die erste beantwortet wird: "Warum geht FF, IE richtig damit um und nicht Chrome?"
Hans Roerdinkholder
Interessant. Haben Sie einige Elemente im Sinn, die zeigen, dass Firefox bei 10.000 stoppt und Chrome versucht, die Originalgröße zu rendern? (Es wäre interessant für zukünftige Referenz). Vielen Dank im Voraus @ViliusL!
Basj
1
@Basj hat maximale Schriftgrößen für jeden Browser hinzugefügt (heute getestet), und für Firefox sind es 2 KB.
ViliusL
Vielen Dank @ViliusL! In der Tat begrenzt FF das font-sizeund dies könnte der Grund für die Nicht-Langsamkeit von FF sein. Aber dann hätte es auch im IE sehr langsam sein sollen, aber es ist nicht ... seltsam!
Basj
4

Zusätzlich zu Teemus Antwort auf die Verwendung von translate:

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

Welche Sie auch andere Herstellerpräfixe verwenden sollten, können Sie einfach beheben, indem Sie dies auf dem Körper verwenden:

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

und das auf html:

height: 100%;

Dadurch wird jedoch das Scrollen deaktiviert. Ich würde also mousedowndem Body ein Ereignis hinzufügen und diese Stile mit einer CSS-Klasse anwenden, wenn sie mousedownausgelöst wird, und diese Klasse entfernen mouseup.

Häftling
quelle
Ich habe versucht hinzuzufügen, was Sie hier erwähnt haben: gget.it/0ufheqmt/big-div-test_prisonersolution.html , haben Sie es gemeint? Hier ist das Ziehen mit Chrome immer noch langsam. Das gleiche für Sie? (PS: Ich habe nicht verstanden: Sie schlagen vor, diese CSS-Änderungen anstelle von style.transformoder mit zu verwenden transform?). Danke übrigens für deine Antwort @Prisoner!
Basj
2

@Teemus 'Antwort macht fast alles.

Verwenden Sie transform mittranslate3d anstelle von top/left.

translate3d aktiviert die Hardwarebeschleunigung.

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

Eine Live-Demo bei jsFiddle .

Koen.
quelle
1

Ich habe dies analysiert und festgestellt, dass das ursprüngliche Problem mit der Chrome-Anzeigearchitektur und der Verwendung von Hintergrundthreads zum Rendern der Seite zusammenhängt.

Wenn Sie schnell rendern möchten, gehen Sie zu chrome: flags, scrollen Sie zur Einstellung Impl-side paint und setzen Sie "Disabled". Starten Sie dann den Browser neu - die Mausbewegung wird reibungslos ausgeführt.

Wenn Sie den FPS-Zähler aktivieren, ist der gemeldete FPS-Wert in diesem Szenario immer noch sehr hoch, obwohl die tatsächliche Bildschirmleistung sehr niedrig ist. Meine vorläufige Erklärung (kein Experte für Chrome-Anzeigearchitektur) lautet: Wenn sich der UI-Thread und die Anzeige in separaten Threads befinden, kann es beim Rendern des Div zu Konflikten kommen - in dem Fall, in dem sich der UI-Thread und der Rendering-Thread auf dem befinden Im selben Thread kann der UI-Thread keine Nachrichten schneller senden, als der UI-Thread rendern kann.

Ich würde vorschlagen, dass dies als Chrome-Fehler abgelegt wird.

Theodore Ferro
quelle
1

Verwenden Sie display: tableund table-layout:fixedauf dem div oder eine Tabelle, die das div umschließt. In HTML:

Das HTML-Tabellenmodell wurde so konzipiert, dass Benutzeragenten mit Unterstützung des Autors Tabellen inkrementell rendern können (dh wenn Tabellenzeilen eintreffen), anstatt auf alle Daten warten zu müssen, bevor sie mit dem Rendern beginnen.

Damit ein Benutzeragent eine Tabelle in einem Durchgang formatieren kann, müssen die Autoren dem Benutzeragenten Folgendes mitteilen:

Die Anzahl der Spalten in der Tabelle. Weitere Informationen zur Bereitstellung dieser Informationen finden Sie im Abschnitt zur Berechnung der Anzahl der Spalten in einer Tabelle. Die Breiten dieser Spalten. Weitere Informationen zur Bereitstellung dieser Informationen finden Sie im Abschnitt zur Berechnung der Spaltenbreite.

Genauer gesagt kann ein Benutzeragent eine Tabelle in einem einzigen Durchgang rendern, wenn die Spaltenbreiten unter Verwendung einer Kombination von COLGROUP- und COL-Elementen angegeben werden. Wenn eine der Spalten relativ oder prozentual angegeben ist (siehe Abschnitt zur Berechnung der Spaltenbreite), müssen die Autoren auch die Breite der Tabelle selbst angeben.

Für die inkrementelle Anzeige benötigt der Browser die Anzahl der Spalten und deren Breite. Die Standardbreite der Tabelle ist die aktuelle Fenstergröße (width = "100%"). Dies kann durch Festlegen des width-Attributs des TABLE-Elements geändert werden. Standardmäßig haben alle Spalten dieselbe Breite, Sie können jedoch Spaltenbreiten mit einem oder mehreren COL-Elementen angeben, bevor die Tabellendaten beginnen.

Das verbleibende Problem ist die Anzahl der Spalten. Einige Leute haben vorgeschlagen, zu warten, bis die erste Zeile der Tabelle empfangen wurde, aber dies kann lange dauern, wenn die Zellen viel Inhalt haben. Insgesamt ist es sinnvoller, wenn die Autoren eine inkrementelle Anzeige wünschen, die Anzahl der Spalten im TABLE-Element explizit anzugeben.

Autoren müssen Benutzeragenten weiterhin mitteilen können, ob sie eine inkrementelle Anzeige verwenden oder die Tabelle automatisch an den Zelleninhalt anpassen möchten. Im automatischen Größenänderungsmodus mit zwei Durchgängen wird die Anzahl der Spalten durch den ersten Durchgang bestimmt. Im inkrementellen Modus muss die Anzahl der Spalten im Voraus angegeben werden (mit COL- oder COLGROUP-Elementen).

und CSS:

17.5.2.1 Festes Tabellenlayout

Bei diesem (schnellen) Algorithmus hängt das horizontale Layout der Tabelle nicht vom Inhalt der Zellen ab. Dies hängt nur von der Breite der Tabelle, der Breite der Spalten und den Rändern oder dem Zellenabstand ab.

Die Breite der Tabelle kann explizit mit der Eigenschaft 'width' angegeben werden. Ein Wert von 'auto' (sowohl für 'display: table' als auch für 'display: inline-table') bedeutet die Verwendung des automatischen Tabellenlayoutalgorithmus. Wenn es sich bei der Tabelle jedoch um eine Tabelle auf Blockebene ('display: table') im normalen Ablauf handelt, kann (muss) ein UA den Algorithmus von 10.3.3 verwenden, um eine Breite zu berechnen und ein festes Tabellenlayout anzuwenden, selbst wenn Die angegebene Breite ist 'auto'.

Verweise

Paul Sweatte
quelle