Un div molto, molto, molto grande


109

Per un mio progetto (vedi BigPictu.re o bigpicture.js progetto GitHub ), devo occuparmi di un <div>contenitore potenzialmente molto, molto, molto grande .

Sapevo che c'era il rischio di prestazioni scadenti con il semplice approccio che utilizzo, ma non mi aspettavo che fosse presente principalmente con ... solo Chrome!

Se provi questa piccola pagina (vedi codice sotto), la panoramica (clic + trascina) sarà:

  • Normale / liscio su Firefox
  • Normale / fluido anche su Internet Explorer
  • Molto lento (quasi in crash) su Chrome!

Ovviamente, potrei aggiungere del codice (nel mio progetto) per farlo quando ingrandisci molto, il testo con dimensioni del carattere potenzialmente molto grandi sarebbe nascosto. Ma ancora, perché Firefox e Internet Explorer lo gestiscono correttamente e non Chrome?

Esiste un modo in JavaScript, HTML o CSS per dire al browser di non tentare di eseguire il rendering dell'intera pagina (che è larga 10000 pixel qui) per ogni azione? (renderizza solo la vista corrente!)


<!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] 600.000 caratteri. Deve essere una caratteristica di accessibilità per le persone con una vista molto scarsa? ;-)
geert3

61
@ geert3 Sono sicuro che sia per un browser web in orbita lunare
David Wilkins

3
La tua demo è fluida in Chrome 41.0.2236.0 dev-m
Pier-Luc Gendreau

11
Sono a canary (41.0.2241.0 canary) e sto ancora ricevendo il ritardo. Dovreste provarlo su un laptop invece che su un impianto di gioco, lo vedrete
markasoftware

3
Contrariamente alla credenza popolare, IE è in realtà più veloce di Chrome per il rendering della maggior parte delle pagine. Il suo motore javascript è però un po 'più lento.
Falanwe

Risposte:


62

Cambiare a position: fixedsembra accelerare le cose.


27
Non è una risposta diretta alla sua domanda, ma è una potenziale soluzione al suo problema iniziale (risposta lenta in Chrome). Pensare fuori dagli schemi dovrebbe essere incoraggiato, IMHO.
geert3

Qui sembra funzionare perfettamente: gget.it/e0ubdh67/big-div-test_fixed.html . Sai perché ? :)
Basj

2
Posso solo immaginare. fixedè ovviamente meno complesso da definire e forse possono fare più ottimizzazioni. Ma non ho esaminato il codice sorgente del motore di rendering se lo intendi ;-)
geert3

1
Questa risposta, e quella fornita da ViliusL, hanno entrambe lo stesso commento "lascia un commento", di persone diverse. Quant'è fico?
Joe

2
@ Joe questi provengono da una serie di risposte standard fornite da StackOverflow per l'utilizzo da parte dei moderatori. Alcuni hanno bisogno di moderare più moderatamente però.
geert3

42

Utilizzare transforminvece di top/left:

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

Una demo dal vivo su jsFiddle .


2
Una cosa molto strana : nel tuo jsFiddle, è davvero veloce con Chrome. Ho fatto esattamente la modifica che proponi nel mio codice originale qui: gget.it/1owxq8kr/big-div-test_transform.html , e quest'ultimo collegamento è lento su Chrome :( Com'è possibile? Sembra uguale al tuo jsFiddle ! [Nota: miracolosamente, le risposte di geert3 sembrano funzionare, non so perché ma funziona: gget.it/e0ubdh67/big-div-test_fixed.html]
Basj

@Basj Forse dipende dalla versione, il mio Chrome (39.0.2171.71 m) scorre la pagina collegata nel tuo commento in modo fluido e veloce come FF. Ad ogni modo, l'impostazione della posizione su fixedelimina l'elemento dal flusso di testo e consente di risparmiare un sacco di ri-rendering. Nella documentazione di transformMDN si legge: "... verrà creato un contesto di stacking. In tal caso l'oggetto fungerà da blocco contenitore per la posizione: fissi gli elementi che contiene."
Teemu

2
Strano, ho anche Chrome 39.0.2171.71 m ... e gget.it/1owxq8kr/big-div-test_transform.html scorre lentamente, come la mia versione originale (nella domanda stessa). Oohhh forse dipende dall'accelerazione hardware: probabilmente non ho accelerazione hardware, perché ho un laptop con un chip grafico scadente ...
Basj

1
@Basj aggiunge un wrapper <div style="position:relative;min-height: 900px;">Your's divs</div>jsFiddle così fa
Alfonso Rubalcava

1
@AlfonsoRubalcava Oh ok ... Questo spiega perché jsfiddle è liscio e il link diretto non è fluido (Chrome): gget.it/1owxq8kr/big-div-test_transform.html ! Grazie! Quindi il miglioramento delle prestazioni deriva dal position:relativeprobabile, che è simile alla risposta di
geert3

22
  1. Risposta alla prima ricerca "perché". Uno dei problemi è la dimensione del carattere . hai una dimensione del carattere di 600000px, la maggior parte dei browser lo vedrà come troppo alto e renderà più piccolo, mentre chrome cerca di rendere la dimensione originale. Sembra che il cromo non possa ridipingere lettere così grandi con gli stili richiesti molto velocemente.

Ma combinando le risposte Teemu e geert3 - usando Transform e Position: Fixed, Chrome funziona molto più velocemente anche con caratteri grandi.

  1. Risposta alla seconda domanda: "Esiste un modo ... per non provare a eseguire il rendering dell'intera pagina" - puoi provare ad applicare l'azione del mouse per gli elementi nel contenitore, non per l'intero contenitore.

Dimensioni massime dei caratteri: 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
Lo fa, in realtà. L'OP pone due domande, alla prima delle quali viene data risposta: "perché FF, IE lo gestisce correttamente e non Chrome?"
Hans Roerdinkholder

Interessante. Hai in mente alcuni elementi che dimostrano che Firefox si ferma a 10k e che Chrome cerca di visualizzare le dimensioni originali? (Sarebbe interessante per riferimento futuro). Grazie in anticipo @ViliusL!
Basj

1
@Basj ha aggiunto le dimensioni massime dei caratteri per ogni browser (testato oggi), ed è 2k per Firefox.
ViliusL

Grazie mille @ViliusL! In effetti, FF limita il font-sizee questo potrebbe essere il motivo della non lentezza su FF. Ma poi avrebbe dovuto essere molto lento anche su IE, ma non è ... Strano!
Basj

4

Oltre alla risposta di Teemu sull'uso di translate:

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

Che dovresti usare anche altri prefissi del fornitore, puoi semplicemente aggiustarlo usando questo sul corpo:

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

e questo su html:

height: 100%;

questo, tuttavia, disabiliterà lo scorrimento. Quindi quello che farei è aggiungere un mousedownevento al corpo e applicare quegli stili usando una classe CSS ogni volta che mousedownviene attivata e rimuovendo quella classe mouseup.


Ho provato ad aggiungere quello che hai menzionato qui: gget.it/0ufheqmt/big-div-test_prisonersolution.html , è quello che intendevi? Qui è ancora lento trascinare con Chrome. Lo stesso per te? (PS: non ho capito: suggerisci di fare queste modifiche CSS invece di usare style.transformo con l' uso transform?). Grazie a proposito per la tua risposta @Prisoner!
Basj

2

La risposta di @Teemus fa quasi tutto.

Utilizzare transform contranslate3d invece di top/left.

translate3d abilita l'accelerazione hardware.

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

Una demo dal vivo su jsFiddle .


1

Ho analizzato questo e ho scoperto che il problema originale riguardava l'architettura del display di Chrome e il suo utilizzo di thread in background per il rendering della pagina.

Se vuoi avere un rendering veloce, vai in chrome: flags, scorri fino all'impostazione Impl-side painting e imposta "Disabled", quindi riavvia il browser - il mouseemove sarà fluido.

Quello che ho scoperto è che se abiliti il ​​contatore FPS, l'FPS riportato in questo scenario è ancora molto alto, anche se le prestazioni effettive sullo schermo sono molto basse. La mia spiegazione provvisoria (non essendo un esperto di architettura di visualizzazione di Chrome) è che se il thread dell'interfaccia utente e il display si trovano su thread separati, possono esserci contese nel rendering del div, nel caso in cui il thread dell'interfaccia utente e il thread di rendering si trovano sul stesso thread, il thread dell'interfaccia utente non può inviare messaggi più velocemente di quanto possa eseguire il rendering del thread dell'interfaccia utente.

Suggerirei che questo dovrebbe essere archiviato come un bug di Chrome.


1

Usa display: tablee table-layout:fixedsul div o una tabella che avvolge il div. In HTML:

Il modello di tabella HTML è stato progettato in modo che, con l'assistenza dell'autore, i programmi utente possano eseguire il rendering delle tabelle in modo incrementale (cioè, quando arrivano le righe della tabella) invece di dover attendere tutti i dati prima di iniziare il rendering.

Affinché un programma utente formatta una tabella in un passaggio, gli autori devono dire al programma utente:

Il numero di colonne nella tabella. Si prega di consultare la sezione sul calcolo del numero di colonne in una tabella per i dettagli su come fornire queste informazioni. Le larghezze di queste colonne. Si prega di consultare la sezione sul calcolo della larghezza delle colonne per i dettagli su come fornire queste informazioni.

Più precisamente, un programma utente può riprodurre una tabella in un unico passaggio quando le larghezze delle colonne sono specificate usando una combinazione di elementi COLGROUP e COL. Se una qualsiasi delle colonne è specificata in termini relativi o percentuali (vedere la sezione sul calcolo della larghezza delle colonne), gli autori devono specificare anche la larghezza della tabella stessa.

Per la visualizzazione incrementale, il browser necessita del numero di colonne e della loro larghezza. La larghezza predefinita della tabella è la dimensione della finestra corrente (larghezza = "100%"). Questo può essere modificato impostando l'attributo width dell'elemento TABLE. Per impostazione predefinita, tutte le colonne hanno la stessa larghezza, ma è possibile specificare le larghezze delle colonne con uno o più elementi COL prima dell'inizio dei dati della tabella.

Il problema rimanente è il numero di colonne. Alcune persone hanno suggerito di attendere la ricezione della prima riga della tabella, ma ciò potrebbe richiedere molto tempo se le celle hanno molto contenuto. Nel complesso ha più senso, quando si desidera la visualizzazione incrementale, fare in modo che gli autori specifichino esplicitamente il numero di colonne nell'elemento TABLE.

Gli autori hanno ancora bisogno di un modo per dire ai programmi utente se utilizzare la visualizzazione incrementale o ridimensionare automaticamente la tabella per adattarla al contenuto della cella. Nella modalità di ridimensionamento automatico a due passaggi, il numero di colonne è determinato dal primo passaggio. Nella modalità incrementale, il numero di colonne deve essere indicato in primo piano (con elementi COL o COLGROUP).

e CSS:

17.5.2.1 Layout fisso della tabella

Con questo (veloce) algoritmo, il layout orizzontale della tabella non dipende dal contenuto delle celle; dipende solo dalla larghezza della tabella, dalla larghezza delle colonne e dai bordi o dalla spaziatura delle celle.

La larghezza della tabella può essere specificata esplicitamente con la proprietà 'width'. Un valore di "auto" (sia per "display: table" che per "display: inline-table") significa utilizzare l'algoritmo di layout automatico della tabella. Tuttavia, se la tabella è una tabella a livello di blocco ('display: table') nel flusso normale, un UA può (ma non deve) usare l'algoritmo di 10.3.3 per calcolare una larghezza e applicare un layout fisso della tabella anche se la larghezza specificata è "auto".

Riferimenti

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.