Un div muy, muy, muy grande

109

Para un proyecto mío (ver BigPictu.re o proyecto GitHub bigpicture.js ), tengo que lidiar con un <div>contenedor potencialmente muy, muy, muy grande .

Sabía que existía el riesgo de un rendimiento deficiente con el enfoque simple que uso, pero no esperaba que estuviera presente principalmente con ... ¡Solo Chrome!

Si prueba esta pequeña página (consulte el código a continuación), la panorámica (haga clic + arrastre) será:

  • Normal / suave en Firefox
  • Normal / suave incluso en Internet Explorer
  • ¡Muy lento (casi fallando) en Chrome!

Por supuesto, podría agregar algún código (en mi proyecto) para hacer eso cuando se acerca mucho, el texto con un tamaño de fuente potencialmente muy grande estaría oculto. Pero aún así, ¿por qué Firefox e Internet Explorer lo manejan correctamente y no Chrome?

¿Hay alguna forma en JavaScript, HTML o CSS de decirle al navegador que no intente representar la página completa (que tiene 10000 píxeles de ancho aquí) para cada acción? (¡renderiza solo la ventana gráfica actual!)


<!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
fuente
54
[OT] Tamaño de fuente de 600 K. Debe ser una característica de accesibilidad para las personas con muy mala vista del ojo? ;-)
geert3
61
@ geert3 Estoy seguro de que es para un navegador web en órbita lunar
David Wilkins
3
Su demostración es fluida en Chrome 41.0.2236.0 dev-m
Pier-Luc Gendreau
11
Estoy en canary (41.0.2241.0 canary) y todavía tengo el retraso. Ustedes deberían probarlo en una computadora portátil en lugar de una plataforma de juegos, lo verán
markasoftware
3
Contrariamente a la creencia popular, IE es en realidad más rápido que Chrome para procesar la mayoría de las páginas. Sin embargo, su motor javascript es un poco más lento.
Falanwe

Respuestas:

62

Cambiar a position: fixedparece acelerar las cosas.

geert3
fuente
27
No es una respuesta directa a su pregunta, pero es una posible solución a su problema inicial (respuesta lenta en Chrome). Se debe alentar a pensar fuera de la caja, en mi humilde opinión.
geert3
Aquí parece funcionar perfectamente: gget.it/e0ubdh67/big-div-test_fixed.html . Sabes por qué ? :)
Basj
2
Solo puedo adivinar. fixedes obviamente menos complejo de diseñar y quizás puedan hacer más optimizaciones. Pero no he mirado el código fuente del motor de renderizado si te refieres a eso ;-)
geert3
1
Esta respuesta, y la proporcionada por ViliusL, tienen el mismo comentario de "dejar un comentario", de diferentes personas. ¿Cuan genial es eso?
Joe
2
@Joe, estas son de un conjunto de respuestas estándar proporcionadas por StackOverflow para que las usen los moderadores. Sin embargo, algunos necesitan moderarse de manera más moderada.
Geert3
42

Usar en transformlugar de top/left:

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

Una demostración en vivo en jsFiddle .

Teemu
fuente
2
Algo muy extraño : en tu jsFiddle, es realmente rápido con Chrome. Hice exactamente la modificación que propones en mi código original aquí: gget.it/1owxq8kr/big-div-test_transform.html , y este último enlace es lento en Chrome :( ¿Cómo es esto posible? Se ve igual que tu jsFiddle ! [Nota: milagrosamente, las respuestas de geert3 parecen funcionar, no sé por qué, pero funciona: gget.it/e0ubdh67/big-div-test_fixed.html]
Basj
@Basj Tal vez dependa de la versión, mi Chrome (39.0.2171.71 m) recorre la página vinculada en su comentario tan suave y rápido como FF. De todos modos, establecer la posición en fixedsaca el elemento del flujo de texto y ahorra una gran cantidad de re-renderizado. En la documentación de transformMDN dice: "... se creará un contexto de apilamiento. En ese caso el objeto actuará como un bloque contenedor para la posición: elementos fijos que contiene".
Teemu
2
Extraño, también tengo Chrome 39.0.2171.71 m ... y gget.it/1owxq8kr/big-div-test_transform.html se desplaza lentamente, tan lento como mi versión original (en la pregunta en sí). Oohhh posiblemente depende de la aceleración del hardware: probablemente no tenga aceleración del hardware, porque tengo una computadora portátil con un chip gráfico pobre ...
Basj
1
@Basj agrega un contenedor <div style="position:relative;min-height: 900px;">Your's divs</div>jsFiddle también lo hace
Alfonso Rubalcava
1
@AlfonsoRubalcava Oh, vale ... Esto explica por qué jsfiddle es fluido y el enlace directo no es fluido (Chrome): gget.it/1owxq8kr/big-div-test_transform.html ! ¡Gracias! Entonces, la mejora en el rendimiento proviene de lo position:relativeprobable, que es similar a la respuesta de
geert3
22
  1. Respuesta a la primera búsqueda "por qué". Uno de los problemas es el tamaño de la fuente . tiene un tamaño de fuente de 600000px, la mayoría de los navegadores lo verán como demasiado alto y se reducirán, mientras que Chrome intentará representar el tamaño original. Parece que Chrome no puede volver a pintar letras tan grandes con los estilos solicitados muy rápido.

Pero la combinación de las respuestas de Teemu y geert3, usando transform y position: fixed, hace que Chrome funcione mucho más rápido incluso con fuentes grandes.

  1. Respuesta a la segunda pregunta: "¿Hay alguna manera ... de no intentar representar la página completa"? Puede intentar aplicar la acción del mouse para los elementos del contenedor, no para todo el contenedor.

Tamaños máximos de fuente: 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
fuente
6
De hecho, lo hace. El OP hace dos preguntas, la primera de las cuales se responde: "¿Por qué FF, IE lo maneja correctamente y no Chrome?"
Hans Roerdinkholder
Interesante. ¿Tiene algunos elementos en mente que muestran que Firefox se detiene en 10k y que Chrome intenta representar el tamaño original? (Sería interesante para futuras referencias). ¡Gracias de antemano @ViliusL!
Basj
1
@Basj agregó tamaños máximos de fuente para cada navegador (probado hoy), y es 2k para Firefox.
ViliusL
¡Muchas gracias @ViliusL! De hecho, FF limita el font-sizey este podría ser el motivo de la no lentitud en FF. Pero también debería haber sido muy lento en IE, pero no es ... ¡Extraño!
Basj
4

Además de la respuesta de Teemu de usar translate:

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

Que también debe usar otros prefijos de proveedores, simplemente puede arreglar esto usando esto en el cuerpo:

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

y esto en html:

height: 100%;

esto, sin embargo, desactivará el desplazamiento. Entonces, lo que haría es agregar un mousedownevento al cuerpo y aplicar esos estilos usando una clase css siempre que mousedownse active, y eliminar esa clase en mouseup.

Prisionero
fuente
Intenté agregar lo que mencionaste aquí: gget.it/0ufheqmt/big-div-test_prisonersolution.html , ¿es eso lo que quisiste decir? Aquí todavía es lento arrastrar con Chrome. ¿Lo mismo para ti? (PD: No entendí: ¿sugiere hacer estas modificaciones CSS en lugar de usar style.transformo con usar transform?). ¡Gracias por cierto por tu respuesta @Prisoner!
Basj
2

La respuesta de @Teemus casi lo hace todo.

Usar transform con entranslate3d lugar de top/left.

translate3d habilita la aceleración de hardware.

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

Una demostración en vivo en jsFiddle .

Koen.
fuente
1

Analicé esto y descubrí que el problema original estaba relacionado con la arquitectura de visualización de Chrome y su uso de subprocesos en segundo plano para representar la página.

Si desea obtener un renderizado rápido, vaya a chrome: flags, desplácese hasta la configuración Impl-side painting y configure "Disabled", luego reinicie el navegador; el movimiento del mouse será suave.

Lo que encontré es que si habilita el contador de FPS, el FPS informado en este escenario sigue siendo muy alto, aunque el rendimiento real en pantalla es muy bajo. Mi explicación tentativa (no siendo un experto en arquitectura de pantalla de Chrome) es que si el hilo de la interfaz de usuario y la pantalla están en hilos separados, entonces puede haber contención en la representación del div, en el caso de que el hilo de la interfaz de usuario y el hilo de representación estén en el mismo hilo, el hilo de la interfaz de usuario no puede enviar mensajes más rápido de lo que puede procesar el hilo de la interfaz de usuario.

Sugeriría que esto se registre como un error de Chrome.

Theodore Ferro
fuente
1

Use display: tabley table-layout:fixeden el div, o una tabla que envuelva el div. En HTML:

El modelo de tabla HTML se ha diseñado para que, con la ayuda del autor, los agentes de usuario puedan representar las tablas de forma incremental (es decir, a medida que llegan las filas de la tabla) en lugar de tener que esperar todos los datos antes de comenzar a representar.

Para que un agente de usuario formatee una tabla en una sola pasada, los autores deben decirle al agente de usuario:

El número de columnas de la tabla. Consulte la sección sobre el cálculo del número de columnas en una tabla para obtener detalles sobre cómo proporcionar esta información. Los anchos de estas columnas. Consulte la sección sobre el cálculo del ancho de las columnas para obtener detalles sobre cómo proporcionar esta información.

Más precisamente, un agente de usuario puede representar una tabla en una sola pasada cuando los anchos de columna se especifican usando una combinación de elementos COLGROUP y COL. Si alguna de las columnas se especifica en términos relativos o porcentuales (consulte la sección sobre el cálculo del ancho de las columnas), los autores también deben especificar el ancho de la tabla.

Para la visualización incremental, el navegador necesita el número de columnas y sus anchos. El ancho predeterminado de la tabla es el tamaño de la ventana actual (ancho = "100%"). Esto se puede modificar estableciendo el atributo de ancho del elemento TABLE. De forma predeterminada, todas las columnas tienen el mismo ancho, pero puede especificar anchos de columna con uno o más elementos COL antes de que comiencen los datos de la tabla.

El problema restante es el número de columnas. Algunas personas han sugerido esperar hasta que se haya recibido la primera fila de la tabla, pero esto podría llevar mucho tiempo si las celdas tienen mucho contenido. En general, tiene más sentido, cuando se desea una visualización incremental, hacer que los autores especifiquen explícitamente el número de columnas en el elemento TABLE.

Los autores todavía necesitan una forma de decirles a los agentes de usuario si deben usar la visualización incremental o ajustar el tamaño de la tabla automáticamente para que se ajuste al contenido de la celda. En el modo de dimensionamiento automático de dos pasadas, el número de columnas se determina mediante la primera pasada. En el modo incremental, el número de columnas debe indicarse al principio (con elementos COL o COLGROUP).

y CSS:

17.5.2.1 Disposición de la mesa fija

Con este algoritmo (rápido), el diseño horizontal de la tabla no depende del contenido de las celdas; solo depende del ancho de la tabla, el ancho de las columnas y los bordes o el espacio entre celdas.

El ancho de la tabla se puede especificar explícitamente con la propiedad 'ancho'. Un valor de 'auto' (tanto para 'display: table' como para 'display: inline-table') significa utilizar el algoritmo de diseño de tabla automático. Sin embargo, si la tabla es una tabla a nivel de bloque ('display: table') en flujo normal, un UA puede (pero no tiene que hacerlo) usar el algoritmo de 10.3.3 para calcular un ancho y aplicar un diseño de tabla fijo incluso si el ancho especificado es 'automático'.

Referencias

Paul Sweatte
fuente