Подтвердить что ты не робот

Как переполнение: скрыто; & border-radius в контейнере вызывает массовое замедление до "Paint/Render Layer" внутри контейнера, только в IE?

У меня много проблем с плохой производительностью в IE (все версии, включая IE11), в виджетах с поддержкой javascript HTML/SVG, только когда виджет размещен на определенной странице.

После определения того, что основной причиной замедления был перерисован слой paint/render, и исчерпывающий информацию об этом, я мог бы выйти из IE Developer Tools, я прибегал для проб и ошибок, отключающих классы предков по одному, пока производительность не улучшится; затем, при определении класса, отключая правила стиля по одному.

Вся моя проблема, похоже, сводится к одному правилу overflow: hidden; для предка нескольких divs вверх по дереву.

Разница, которую он делает, невероятна: с overflow: hidden; вверх по дереву, простое взаимодействие с пользователем (выделение пути SVG, создание текстовой метки HTML, отображение метки и ее расположение относительно пути и контейнера SVG) процессор уменьшает частоту кадров пользовательского интерфейса до нуля и замораживает все мертвые в пределах от 1000 до 4000 миллисекунд за взаимодействие. Без overflow: hidden; у предка он заканчивается в десятки миллисекунд, и частота кадров никогда не опускается ниже половины (не IE-браузеры одинаковы независимо от overflow: hidden;).

  • Здесь профиль с overflow: hidden; для предка, профилирующий как входящие, так и выключенные взаимодействия, фильтруется для рисования событий:

    введите описание изображения здесь

  • Здесь профиль без overflow: hidden; для предка, профилирующий как входящие, так и выключенные взаимодействия, фильтруется для рисования событий. Единственное изменение заключалось в тике или отключении галочки рядом со стилем overflow: hidden; в инспекторе DOM, и неважно, в каком порядке выполняю тесты:

    введите описание изображения здесь

Я не хочу просто переопределять этот overflow: hidden; как липкую штукатурку и говорить о выполненной работе, не понимая, как это происходит, и рискуя повторением проблемы с другими, казалось бы, тривиальными изменениями CSS. Я бы предпочел понять, почему overflow: hidden; делает такую ​​разницу и адрес надежным способом, который работает независимо от применяемого правила переполнения.

К сожалению, я не могу опубликовать полную демоверсию, но здесь приводится резюме соответствующей части структуры DOM с комментариями к стилям, связанным с компоновкой:

  <div class="responsive-grid">

  <!-- ...lots of nested divs that simply inherit styles, I can't change this aspect of the Drupal layout -->

    <div id="panel-5" class="col-12"> <!-- width: 100%; float: left -->
    <!-- this is the first element IE looks at for offsetWidth when doing the changes below -->

    <!-- ...a few more nested divs without layout-changing styles -->

      <div class="panel"> <!-- overflow: hidden; clear: both; border: 1px; -->
      <!-- this is the element where removing the overflow: hidden changes everything -->
      <!-- I'm not sure what clear:both is for here, since no siblings. Seems redundant -->

      <!-- ...a few more nested divs with no style rules, some contain <p>s <h2>s etc... -->

        <div class="container"> <!-- position: relative; -->
          <div class="sub-column col-8"> <!-- width: 66%; display: inline-block -->
            <div class="square"> <!-- width: 100%; padding-bottom: 100%; position: relative -->
              <svg viewbox="0 0 500 500" preserveAspectRatio="XMinYMin meet" ...>
              <!-- svg position: absolute; width:100%; height: 100% -->
                Many paths here

              <div class="label"> <!-- fixed width in pixels; position: absolute -->
                Some text here
              </div>
            </div>
          </div>
          <div class="sub-column col-4"> <!-- width: 33%; display: inline-block -->
             <div class="sidebar">
                Many interactive controls here

              <!-- .square, svg andd .sidebar contain the only elements that are updated -->
            </div>
          </div>
        </div>

        <!-- some more ordinary position: static text containers -->
      </div>
    </div>
  </div>

Что может происходить здесь, и есть ли способ предотвратить это, не удаляя/запрещая overflow: hidden; в элементе предка?


Я видел Как избежать затрат на переполнение: скрытый?, но оба вопроса и ответы кажутся специфичными для таблиц HTML и старой ошибки Webkit с тех пор исправлено.

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


Обновление: Сюжет сгущается. Мне удалось повторить проблему с моим виджетами в более простой структуре HTML и обнаружил, что проблема возникает только в том случае, если и overflow: hidden; и border-radius (в моем случае, 3px) установлены в одном контейнере. С одной, но не с другой, проблема исчезает.

  • Здесь образец с overflow: hidden;, но не border-radius. Может быть, немного меньше, чем выше, но разница тривиальна:

    введите описание изображения здесь

  • Здесь образец с overflow: hidden; и border-radius из той же упрощенной структуры:

    введите описание изображения здесь

4b9b3361

Ответ 1

После гораздо большего тестирования я думаю, что начинаю понимать, что происходит здесь. Это чисто основано на наблюдении, хотя, поэтому я все равно буду увлекаться более авторитетным ответом, если у кого-нибудь есть.


Что его вызывает?

Это происходит, только если все это верно:

  • Браузер IE (любая версия)
  • Элемент предка, который мы будем называть X, содержит как overflow: hidden, так и border-radius (или -ms-border-radius). В моем тестировании это не происходит, если разные предки в одной ветки имеют эти стили.
  • Существует много сложных элементов, таких как пути SVG или div-width, которые находятся в ветке DOM, где они или элемент между ними и элементом X имеют position: absolute; или position: relative;

Проблема также кажется более выраженной пропорционально количеству элементов, затронутых position: absolute;/relative, и их сложности. В случаях, когда были обнаружены пути SVG в гибко масштабируемом контейнере SVG с пропускной способностью% -width с% padding-bottom для фиксированного соотношения сторон, например, проблема была очень выраженной; если эта ветвь была задана position: static, но другая ветвь имела div-width с предком position: absolute;, тогда проблема по-прежнему наблюдалась по сравнению с удалением одного из overflow: hidden; или border-radius, но была гораздо менее серьезной.


Но почему?

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

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

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

Сложив их вместе, я думаю, что есть правдоподобное объяснение того, что происходит здесь. Если это правда, по иронии судьбы, мои проблемы с производительностью были вызваны попыткой IE IE, направленной на то, чтобы оптимизировать производительность и избежать таких проблем, как связанная с Chrome проблема Chrome.

Если эта теория верна, что-то вроде этого происходит в IE:

  • Он видит overflow: hidden; и делает вывод, что он может повысить производительность, идентифицируя элементы, которые полностью находятся за пределами границ элемента, прежде чем делать на них события перерисовывания /reflow/paint и т.д.
  • Он видит position: absolute; и position: relative; дальше DOM и заключает, что они и их дети потенциально могут быть полностью вне контейнера и могут быть проигнорированы как
  • Во время таких событий, как перерисовка и перепланирование, он сначала циклически проходит через все эти элементы и проверяет, что они не полностью за пределами границ. Это происходит даже без border-radius, но в таких случаях оно тривиально и принимает миллисекунды.
  • ... однако IE отмечает граничный радиус и заключает, что форма этого элемента overflow: hidden не является прямоугольником, и поэтому требуется более сложный расчет, чтобы определить, что находится за пределами границ.
  • Предположительно, он также заключает, что пути SVG нужно сравнивать на основе их фактических форм, а не их простых ограничивающих прямоугольных координат, так как это уже не просто сравнение параллельных прямоугольников.
  • Внезапно вычисление для проверки того, можно ли игнорировать элемент во время красок/перерисовки/переплавки, стало сложным. Если повторять сотни раз для сотен элементов, он значительно ухудшает производительность при каждом запуске события.

Как это исправить?

Если вы можете, просто переместите overflow: hidden или border-radius в дочерний элемент, чтобы они не были на одном элементе. Выполнение задания.

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

Лучший подход, который я могу придумать, состоит в том, чтобы предположить, что стиль border-radius не имеет существенного значения для эстетики и что overflow: hidden; может быть существенным для структуры, и поэтому, если браузер IE, найдите дерево предков и удалите border-radius из любого элемента, у которого есть и это, и overflow: hidden;.

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

if( isAnyIE() ) {
  $container.parentsUntil("body").filter(function(){

    var $this = $(this),
      overflow = $this.css('overflow');
    return ( overflow === 'hidden' && hasBorderRadius( $this ) );

  }).addClass( 'remove-border-radius' ); 
}

function hasBorderRadius( $element ){
  function getNum( style ){
    return parseFloat( $element.css( 'border-'+style+'-radius' ) ) || 0;
  }
  var number = 0;

  number += getNum( 'top-left' );
  number += getNum( 'bottom-left' );
  number += getNum( 'top-right' );
  number += getNum( 'bottom-right' );

  $element = null;

  return !!number;
}

function isAnyIE(){
  // isIE(): use conditional comments and classes, see https://stackoverflow.com/a/18615772/568458
  // isIE10: use user agent like navigator.appVersion.indexOf("MSIE 10") !== -1;
  // isIE11: use user agent like !!navigator.userAgent.match(/Trident.*rv[ :]*11\./);

  return isIE11() || isIE10() || isIE();
}

С CSS как:

.remove-border-radius {
  border-radius: 0 0 0 0 !important;
  -ms-border-radius: 0 0 0 0 !important;
}

Ответ 2

Проблема была привлечена к Microsoft внимание в этот отчет об ошибке, написанный Джоппе Кроном в феврале 2014 года:

[IE 9] [IE 11] div с граничным радиусом и переполнением за исключением видимого изменения размера при заполнении div с помощью позиции относительно

Перерисовывание страницы выполняется очень плохо, когда есть много большие элементы DIV с комбинацией положения "абсолютный", "фиксированный", или "относительный", переполнение, отличное от "видимого" и радиус границы. Это можно увидеть при изменении размера окна или прокрутки. Отдельные события рисования могут занять до 1,5 секунд, в результате чего страница перестает реагировать.

Эта проблема производительности появляется в IE 11 и IE 9, но не в IE 10.

<ч/" > Единственный существенный ответ Microsoft был опубликован в апреле 2016 года. Он не обеспечивает решение или обходное решение:

[...] Мы рассмотрели проблему, о которой вы сообщили очень близко, и нашли он очень похож на аналогичные сообщенные проблемы. Ни один из наших обычных резолюции ( "BY DESIGN", "DUPLICATE", "FIXED" и т.д.) в точности совпадают поэтому мы отмечаем это как "WONT FIX" из-за отсутствия что-то лучше, но то, что мы действительно имеем в виду, хорошо справляется с этим в агрегированный вид, а не смотреть на этот точный инцидент в этой точной ситуации. [...]

Все лучшее, команда MS Edge Team

Состояние ошибки: Закрыто, поскольку не будет исправлено