web-dev-qa-db-fra.com

Un très, très, très grand div

Pour un de mes projets (voir BigPictu.re ou projet bigpicture.js GitHub ), je dois faire face à un très, très, très gros <div> récipient.

Je savais qu'il y avait un risque de performances médiocres avec l'approche simple que j'utilise, mais je ne m'attendais pas à ce qu'elle soit principalement présente avec ... Chrome uniquement!

Si vous testez cette petite page (voir le code ci-dessous), le panoramique (clic + glisser) sera:

  • Normal/lisse sur Firefox
  • Normal/lisse même sur Internet Explorer
  • Très lent (presque planter) sur Chrome!

Bien sûr, je pourrais ajouter du code (dans mon projet) pour faire cela lorsque vous zoomez beaucoup, le texte avec une taille de police potentiellement très grande serait caché. Mais quand même, pourquoi Firefox et Internet Explorer le traitent-ils correctement et pas Chrome?

Existe-t-il un moyen en JavaScript, HTML ou CSS de dire au navigateur de ne pas essayer de rendre la page entière (qui fait 10000 pixels de large ici) pour chaque action? (rendre uniquement la fenêtre courante!)


<!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>
106
Basj

Passer à position: fixed semble accélérer les choses.

60
geert3

Utilisez transform au lieu de top/left:

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

ne démo en direct sur jsFiddle .

42
Teemu
  1. Répondez à la première quête "pourquoi". L'un des problèmes est la taille de police . vous avez la taille de police 600000px, la plupart des navigateurs la verront comme trop élevée et plus petite, tandis que chrome essaie de rendre la taille d'origine. Ressemble à chrome ne peut pas repeindre ces grosses lettres avec vos styles demandés très rapidement.

Mais en combinant les réponses Teemu et geert3 - en utilisant transform et position: fixed, rend chrome fonctionne beaucoup plus rapidement même avec de grosses polices.

  1. Réponse à la 2e question: "Existe-t-il un moyen ... de ne pas essayer de rendre la page entière" - vous pouvez essayer d'appliquer l'action de la souris pour les éléments du conteneur, pas pour le conteneur entier.

Tailles de police maximales: 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
22
ViliusL

En plus de la réponse de Teemu d'utiliser translate:

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

Que vous devez également utiliser d'autres préfixes de fournisseurs, vous pouvez simplement résoudre ce problème en utilisant ceci sur le corps:

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

et cela en html:

height: 100%;

cela désactivera cependant le défilement. Donc, ce que je ferais, c'est ajouter un événement mousedown au corps et appliquer ces styles à l'aide d'une classe css chaque fois que mousedown est déclenché, et supprimer cette classe sur mouseup.

4
Prisoner

La réponse de @Teemus fait presque tout.

Utilisez transform avec translate3d au lieu de top/left.

translate3d active l'accélération matérielle.

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

ne démo en direct sur jsFiddle .

2
Koen.

Utilisation display: table et table-layout:fixed sur le div, ou une table enveloppant le div. En HTML:

Le modèle de tableau HTML a été conçu pour que, avec l'aide des auteurs, les agents utilisateurs puissent rendre les tableaux de manière incrémentielle (c'est-à-dire à mesure que les lignes du tableau arrivent) plutôt que d'avoir à attendre toutes les données avant de commencer le rendu.

Pour qu'un agent utilisateur puisse formater une table en une seule passe, les auteurs doivent indiquer à l'agent utilisateur:

Le nombre de colonnes dans le tableau. Veuillez consulter la section sur le calcul du nombre de colonnes dans un tableau pour savoir comment fournir ces informations. Les largeurs de ces colonnes. Veuillez consulter la section sur le calcul de la largeur des colonnes pour plus de détails sur la manière de fournir ces informations.

Plus précisément, un agent utilisateur peut restituer une table en une seule passe lorsque les largeurs de colonne sont spécifiées à l'aide d'une combinaison d'éléments COLGROUP et COL. Si l'une des colonnes est spécifiée en termes relatifs ou en pourcentage (voir la section sur le calcul de la largeur des colonnes), les auteurs doivent également spécifier la largeur du tableau lui-même.

Pour un affichage incrémentiel, le navigateur a besoin du nombre de colonnes et de leurs largeurs. La largeur par défaut du tableau est la taille actuelle de la fenêtre (largeur = "100%"). Cela peut être modifié en définissant l'attribut width de l'élément TABLE. Par défaut, toutes les colonnes ont la même largeur, mais vous pouvez spécifier des largeurs de colonne avec un ou plusieurs éléments COL avant le démarrage des données de la table.

Le problème restant est le nombre de colonnes. Certaines personnes ont suggéré d'attendre la réception de la première ligne du tableau, mais cela pourrait prendre beaucoup de temps si les cellules ont beaucoup de contenu. Dans l'ensemble, il est plus logique, lorsqu'un affichage incrémentiel est souhaité, d'amener les auteurs à spécifier explicitement le nombre de colonnes dans l'élément TABLE.

Les auteurs ont toujours besoin d'un moyen de dire aux agents utilisateurs s'ils doivent utiliser l'affichage incrémentiel ou dimensionner automatiquement le tableau pour qu'il corresponde au contenu de la cellule. Dans le mode de dimensionnement automatique à deux passes, le nombre de colonnes est déterminé par la première passe. En mode incrémental, le nombre de colonnes doit être indiqué en amont (avec les éléments COL ou COLGROUP).

et CSS:

17.5.2.1 Disposition de table fixe

Avec cet algorithme (rapide), la disposition horizontale du tableau ne dépend pas du contenu des cellules; cela dépend uniquement de la largeur du tableau, de la largeur des colonnes et des bordures ou de l'espacement des cellules.

La largeur de la table peut être spécifiée explicitement avec la propriété 'width'. Une valeur 'auto' (pour 'display: table' et 'display: inline-table') signifie utiliser l'algorithme de disposition de table automatique. Cependant, si la table est une table de niveau bloc ('display: table') dans un flux normal, un UA peut (mais n'est pas obligé) d'utiliser l'algorithme de 10.3.3 pour calculer une largeur et appliquer une disposition de table fixe même si la largeur spécifiée est 'auto'.

Références

1
Paul Sweatte

J'ai analysé cela et j'ai trouvé que le problème d'origine était lié à l'architecture d'affichage Chrome et à son utilisation de threads d'arrière-plan pour afficher la page.

Si vous voulez avoir un rendu rapide, allez dans chrome: flags, faites défiler jusqu'au paramètre Peinture côté implant et définissez "Désactivé", puis redémarrez le navigateur - le déplacement de la souris sera fluide.

Ce que j'ai trouvé, c'est que si vous activez le compteur FPS, le FPS signalé dans ce scénario est toujours très élevé, même si les performances réelles à l'écran sont très faibles. Mon explication provisoire (n'étant pas un Chrome expert en architecture d'affichage) est que si le thread d'interface utilisateur et l'affichage sont sur des threads séparés, il peut y avoir des conflits dans le rendu du div - dans le cas où le thread d'interface utilisateur et le thread de rendu se trouvent sur le même thread, le thread d'interface utilisateur ne peut pas envoyer de messages plus rapidement que le thread d'interface utilisateur ne peut le rendre.

Je suggère que cela soit classé comme un bug Chrome.

1
Theodore Ferro