2014-12-08 2 views
106

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

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

Если тест this small page (см код ниже), панорамирование (нажмите + перетаскивание) будет:

  • Normal/гладкая на Firefox
  • Normal/гладкая даже на Internet Explorer
  • Очень медленно (почти сбой) на Chrome!

Конечно, я мог бы добавить код (в моем проекте), чтобы сделать это, когда вы сильно увеличились, текст с потенциально очень большим шрифтом будет скрыт. Но все же, Почему Firefox и Интернет   Проводник правильно обрабатывает его, а не 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> 
+53

[OT] 600K размер шрифта. Должна быть функция доступности для людей с * очень * плохим зрением? ;-) – geert3

+59

@ geert3 Я уверен, что это для лунного орбитального веб-браузера –

+0

Прекрасно работает для меня на Chrome 38.0.2125.111 m. – FreeAsInBeer

ответ

59

Изменение на position: fixed, похоже, ускоряет работу.

+26

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

+0

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

+2

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

42

Использование transform вместо top/left:

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

A live demo at jsFiddle.

+2

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

+0

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

+0

Ok @Teemu, это Цитирование MDN объясняет, почему решение с 'position: fixed' (http://gget.it/e0ubdh67/big-div-test_fixed.h tml) также работает? – Basj

4

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

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

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

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

и это по html:

height: 100%; 

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

+0

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

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

Но сочетание ответов Teemu и geert3 - с использованием преобразования и положения: фиксированный, делает хромированные работы намного быстрее даже с большими шрифтами.

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

Максимальные размеры шрифта: 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

Это действительно. ОП задает два вопроса, первый из которых отвечает: «Почему FF, IE обрабатывают его правильно, а не Chrome?» –

+0

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

+1

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

1

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

Использование transformс translate3d вместо top/left.

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

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

A live demo at jsFiddle.

1

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

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

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

Я бы предположил, что это должно быть зарегистрировано как ошибка Chrome.

1

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

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

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

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

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

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

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

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

и УС:

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

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

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

Список литературы

Смежные вопросы