Очень, очень, очень большой div


109

Для моего проекта (см. BigPictu.re или bigpicture.js проект GitHub ) мне приходится иметь дело с потенциально очень, очень, очень большим <div>контейнером.

Я знал, что при использовании простого подхода есть риск снижения производительности, но я не ожидал, что он будет присутствовать в основном с ... только Chrome!

Если вы протестируете эту маленькую страницу (см. Код ниже), панорамирование (щелчок + перетаскивание) будет:

  • Нормальный / гладкий в Firefox
  • Нормально / плавно даже в Internet Explorer
  • Очень медленно (почти вылетает) в Chrome!

Конечно, я мог бы добавить некоторый код (в свой проект), чтобы сделать это, когда вы сильно увеличите масштаб, текст с потенциально очень большим размером шрифта будет скрыт. Но все же, почему Firefox и Internet Explorer обрабатывают это правильно, а не Chrome?

Есть ли способ в JavaScript, HTML или CSS, чтобы браузер не пытался отображать всю страницу (которая здесь имеет ширину 10000 пикселей) для каждого действия? (визуализировать только текущий видовой экран!)


<!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К. Должна быть функция доступности для людей с очень плохим зрением? ;-)
geert3

61
@ geert3 Я уверен, что это для браузера, вращающегося вокруг Луны,
Дэвид Уилкинс,

3
Ваша демонстрация работает гладко в Chrome 41.0.2236.0 dev-m
Пьер-Люк Жендро

11
Я на канарейке (41.0.2241.0 канарейка), но все еще лаги. Вы, ребята, должны попробовать это на ноутбуке, а не на игровой установке, вы это увидите
markasoftware

3
Вопреки распространенному мнению, IE на самом деле быстрее, чем Chrome, для рендеринга большинства страниц. Однако его движок javascript немного медленнее.
Falanwe

Ответы:


62

Переход на , position: fixedкажется, ускорить процесс .


27
Это не прямой ответ на его вопрос, но это потенциальное решение его первоначальной проблемы (медленный ответ в Chrome). Нестандартное мышление следует поощрять, ИМХО.
geert3

Здесь вроде работает отлично: gget.it/e0ubdh67/big-div-test_fixed.html . Ты знаешь почему ? :)
Basj

2
Я могу только догадываться. fixedочевидно, проще разложить и, возможно, они смогут сделать больше оптимизаций. Но я не смотрел исходный код движка рендеринга, если вы имеете в виду ;-)
geert3

1
Этот ответ и тот, который предоставил ViliusL, имеют одинаковый комментарий «оставить комментарий» от разных людей. Как это круто?
Джо

2
@Joe, это из набора стандартных ответов, предоставленных StackOverflow для использования модераторами. Некоторым нужно модерировать более умеренно.
geert3

42

Используйте transformвместо top/left:

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

Живая демонстрация на jsFiddle .


2
Очень странное дело: в вашем jsFiddle, он быстро с Chrome действительно. Я сделал именно ту модификацию, которую вы предлагаете в моем исходном коде здесь: gget.it/1owxq8kr/big-div-test_transform.html , и эта последняя ссылка работает медленно в Chrome :( Как это возможно? Она выглядит так же, как ваш jsFiddle ! [Примечание: чудом ответы geert3, кажется, работают, я не знаю почему, но они работают: gget.it/e0ubdh67/big-div-test_fixed.html]
Basj

@Basj Может быть, это зависит от версии, мой Chrome (39.0.2171.71 м) перемещает страницу, указанную в вашем комментарии, так же плавно и быстро, как FF. В любом случае, установка позиции на fixedвыводит элемент из потока текста и избавляет от необходимости повторного рендеринга. В документации transformMDN говорится: «... будет создан контекст наложения. В этом случае объект будет действовать как содержащий блок для элементов position: fixed, которые он содержит».
Теему

2
Странно, у меня тоже Chrome 39.0.2171.71 м ... и gget.it/1owxq8kr/big-div-test_transform.html панорамы медленные, такие же медленные, как моя оригинальная версия (в самом вопросе). Ооооо, возможно, это зависит от аппаратного ускорения: у меня, вероятно, нет аппаратного ускорения, потому что у меня ноутбук с плохим графическим чипом ...
Basj

1
@Basj добавляет обертку <div style="position:relative;min-height: 900px;">Your's divs</div>jsFiddle, так же как и
Альфонсо Рубалькава

1
@AlfonsoRubalcava О, хорошо ... Это объясняет, почему jsfiddle гладкий, а прямая ссылка не гладкая (Chrome): gget.it/1owxq8kr/big-div-test_transform.html ! Спасибо! Таким образом, улучшение производительности происходит от position:relativeвероятного, что похоже на ответ
geert3

22
  1. Ответ на первый квест «почему». Одна из проблем - размер шрифта . у вас размер шрифта 600000 пикселей, большинство браузеров сочтут его слишком большим и визуализируют меньше, в то время как хром пытается отобразить исходный размер. Похоже, хром не может быстро перерисовать такие большие буквы с помощью запрошенных вами стилей.

Но объединение ответов Teemu и geert3 - использование transform и position: fixed - заставляет хром работать намного быстрее даже с большими шрифтами.

  1. Ответ на 2-й вопрос: «Есть ли способ ... не пытаться отобразить всю страницу» - вы можете попробовать применить действие мыши для элементов в контейнере, а не для всего контейнера.

Максимальные размеры шрифта: 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
На самом деле это так. OP задает два вопроса, на первый из которых дан ответ: «Почему FF, IE обрабатывает его правильно, а не Chrome?»
Ганс Рурдинкхолдер

Интересный. У вас есть какие-то элементы, которые показывают, что Firefox останавливается на 10k и что Chrome пытается отобразить исходный размер? (Было бы интересно использовать в будущем). Заранее спасибо @ViliusL!
Basj

1
@Basj добавил максимальные размеры шрифтов для каждого браузера (проверено сегодня), а для firefox это 2k.
ViliusL

Большое спасибо @ViliusL! Действительно, FF ограничивает, font-sizeи это может быть причиной отсутствия медленности на FF. Но тогда на IE тоже должно было быть очень медленно, но это не ... Странно!
Basj

4

В дополнение к ответу Теему об использовании перевода:

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

Которые вы также должны использовать префиксы других поставщиков. Вы можете просто исправить это, используя это в теле:

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

и это в html:

height: 100%;

это, однако, отключит прокрутку. Итак, что я бы сделал, это добавить mousedownсобытие в тело и применить эти стили, используя класс css всякий раз, когда mousedownон запускается, и удалить этот класс mouseup.


Я попытался добавить сюда то, что вы упомянули: gget.it/0ufheqmt/big-div-test_prisonersolution.html , вы это имели в виду? Здесь все еще медленно перетаскивается с Chrome. То же самое для вас? (PS: я не понял: вы предлагаете сделать эти модификации CSS вместо использования style.transformили с использованием transform?). Кстати, спасибо за ответ @Prisoner!
Basj

2

Ответ @Teemus делает почти все.

Используйте transform сtranslate3d вместо top/left.

translate3d обеспечивает аппаратное ускорение.

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

Живая демонстрация на jsFiddle .


1

Я проанализировал это и обнаружил, что исходная проблема связана с архитектурой отображения Chrome и использованием фоновых потоков для визуализации страницы.

Если вы хотите иметь быстрый рендеринг, войдите в chrome: flags, прокрутите до параметра Impl-side painting и установите «Disabled», затем перезапустите браузер - движение мыши будет плавным.

Я обнаружил, что если вы включите счетчик FPS, заявленный FPS в этом сценарии все еще будет очень высоким, даже несмотря на то, что фактическая производительность на экране очень низкая. Мое предварительное объяснение (не являющееся экспертом по архитектуре отображения Chrome) заключается в том, что если поток пользовательского интерфейса и отображение находятся в разных потоках, тогда может возникнуть конфликт при рендеринге div - в случае, когда поток пользовательского интерфейса и поток рендеринга находятся в того же потока, поток пользовательского интерфейса не может отправлять сообщения быстрее, чем поток пользовательского интерфейса может отобразить.

Я бы посоветовал зарегистрировать это как ошибку Chrome.


1

Используйте display: tableи table-layout:fixedв div или таблицу, оборачивающую div. В HTML:

Модель таблицы HTML была спроектирована так, что с помощью автора пользовательские агенты могут визуализировать таблицы постепенно (то есть по мере поступления строк таблицы) вместо того, чтобы ждать всех данных перед началом визуализации.

Чтобы пользовательский агент мог отформатировать таблицу за один проход, авторы должны сообщить пользовательскому агенту:

Количество столбцов в таблице. Пожалуйста, обратитесь к разделу о вычислении количества столбцов в таблице, чтобы узнать, как предоставить эту информацию. Ширина этих столбцов. Пожалуйста, обратитесь к разделу о вычислении ширины столбцов, чтобы узнать, как предоставить эту информацию.

Точнее, пользовательский агент может визуализировать таблицу за один проход, когда ширина столбца указывается с использованием комбинации элементов COLGROUP и COL. Если какой-либо из столбцов указан в относительном или процентном выражении (см. Раздел о вычислении ширины столбцов), авторы также должны указать ширину самой таблицы.

Для инкрементального отображения браузеру необходимо количество столбцов и их ширина. Ширина таблицы по умолчанию - это текущий размер окна (ширина = "100%"). Это можно изменить, установив атрибут width элемента TABLE. По умолчанию все столбцы имеют одинаковую ширину, но вы можете указать ширину столбца с одним или несколькими элементами COL до начала данных таблицы.

Остается проблема с количеством столбцов. Некоторые предлагают подождать, пока не будет получена первая строка таблицы, но это может занять много времени, если в ячейках много содержимого. В целом, когда желательно инкрементное отображение, имеет смысл заставить авторов явно указывать количество столбцов в элементе TABLE.

Авторам по-прежнему нужен способ сообщить пользовательским агентам, следует ли использовать инкрементное отображение или автоматически изменять размер таблицы, чтобы она соответствовала содержимому ячеек. В двухпроходном режиме автоматического изменения размера количество столбцов определяется первым проходом. В инкрементальном режиме количество столбцов должно быть указано впереди (с элементами COL или COLGROUP).

и CSS:

17.5.2.1 Фиксированный макет таблицы

При этом (быстром) алгоритме горизонтальная компоновка таблицы не зависит от содержимого ячеек; это зависит только от ширины таблицы, ширины столбцов и границ или расстояния между ячейками.

Ширина таблицы может быть явно указана с помощью свойства width. Значение «auto» (как для display: table, так и для display: inline-table) означает использование алгоритма автоматического макета таблицы. Однако, если таблица является таблицей блочного уровня ('display: table') в нормальном потоке, UA может (но не обязан) использовать алгоритм 10.3.3 для вычисления ширины и применения фиксированного макета таблицы, даже если указанная ширина - «авто».

Ссылки

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.