Как работает переполнение: скрыто; & border-radius в контейнере вызывает значительное замедление рисования / рендеринга слоя в контейнере, только в IE?

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

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

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

Разница невероятна: с 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 из той же упрощенной структуры:

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


person user56reinstatemonica8    schedule 14.09.2016    source источник
comment
Если я не ошибаюсь, несколько лет назад в Microsoft было сообщено о проблеме: connect.microsoft.com/ IE / feedbackdetail / view / 961961 /.   -  person ConnorsFan    schedule 19.09.2016
comment
@ConnorsFan Perfect, похоже, авторитетный ответ / официальные источники, которые я искал! Не стесняйтесь размещать это как ответ   -  person user56reinstatemonica8    schedule 20.09.2016
comment
Вопрос в том ... выполняем ли мы, программисты и фронт-дизайнеры надлежащие надоедливые, а иногда и умопомрачительные задачи, чтобы наши веб-сайты и веб-приложения могли работать с IE? Законное использование IE составляет 6,9% (без учета использования IE для загрузки Chrome и подобных). В конце концов, у нас есть возможность остановить это безумие Microsoft, которая не поддерживает собственный браузер, чтобы сделать его способным использовать новые интерфейсные технологии. Так зачем нам это делать?   -  person JoelBonetR    schedule 20.09.2016
comment
@ JoëlBonetRodríguez Это старые дебаты. В моем случае этот конкретный клиент работает в отрасли, где многие крупные организации много лет назад приняли неверные решения инвестировать в специализированное программное обеспечение, построенное на старых версиях IE, и теперь застревают с ними, пока не потратят небольшое состояние. Они медленно уходят из-за множества дыр в безопасности IE, но это медленно. А до тех пор, если не поддерживать IE, самые важные пользователи будут закрыты. Однако при нацеливании на широкую публику, которая может свободно и легко переключать браузеры, все чаще просто не поддерживают IE и побуждают пользователей переключаться.   -  person user56reinstatemonica8    schedule 20.09.2016
comment
Поэтому попробуйте интегрировать библиотеку normalize.css или что-то подобное, чтобы старые браузеры хорошо отображались. Было бы потрясающе интегрировать библиотеку рендеринга в большой проект, но я думаю, что это лучший вариант для современной и правильной разработки, не заботясь о IE.   -  person JoelBonetR    schedule 20.09.2016
comment
Уже пользуюсь normalize, к вопросу безразлично. Это удобно, но не волшебно и не может изменить то, как внутренние компоненты браузера (неправильно) обрабатывают события рисования и перекомпоновки. Это не один из тех простых, хорошо документированных движков рендеринга трезубца IE, который отображает вещи иначе, чем стандартные причуды CSS, которые можно решить с помощью пары строк кода в условном комментарии.   -  person user56reinstatemonica8    schedule 20.09.2016
comment
ну, вы всегда можете проверить, какой браузер отображает страницу, и, если это не IE, оставьте его как есть, но, если IE переопределит класс, который загружает радиус границы и переполнение и отключит его ... его можно достичь с помощью нескольких строк js, меньше, чем несколько, если вы используете jquery. Вы также можете добавить эти строки css после загрузки страницы. Я не думаю о другом решении ...   -  person JoelBonetR    schedule 20.09.2016


Ответы (2)


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


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

Кажется, это произойдет только в том случае, если все это правда:

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

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


Но почему?

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

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

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

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

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

  • Он видит overflow: hidden; и приходит к выводу, что он может улучшить производительность, идентифицируя элементы, которые полностью выходят за границы элемента, прежде чем выполнять для них события перерисовки / перекомпоновки / рисования и т. Д.
  • Он видит 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;
}
person user56reinstatemonica8    schedule 15.09.2016
comment
Что за сага. Microsoft должна нанять вас. - person serraosays; 19.09.2016
comment
Вы не представляете, насколько это мне помогло. - person instantaphex; 07.11.2017

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

[IE 9] [IE 11] div с радиусом границы и переполнением кроме видимых, медленное изменение размера при заполнении div с положением относительным

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

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


Единственный важный ответ от Microsoft был опубликован в апреле 2016 года. Он не предлагает решения или обходного пути:

[...] Мы очень внимательно изучили проблему, о которой вы сообщили, и обнаружили, что она очень похожа на аналогичные проблемы, о которых сообщалось. Ни одно из наших обычных разрешений («ПО ДИЗАЙНУ», «ДУПЛИКАТ», «ФИКСИРОВАННЫЙ» и т. Д.) Точно не соответствует этой ситуации, поэтому мы отмечаем его как «НЕ ИСПРАВЛЯЕМ» из-за отсутствия чего-либо лучшего, но на самом деле мы имеем в виду то, что мы я буду иметь дело с этим в совокупности, а не смотреть на этот конкретный инцидент в этой конкретной ситуации. [...]

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

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

person ConnorsFan    schedule 20.09.2016