Новое CSS-свойство content-visibility ускоряет отрисовку страницы в несколько раз

5 августа 2020 разработчики Google анонсировали новое CSS-свойство content-visibility в версии Chromium 85. Оно должно существенно повлиять на скорость первой загрузки и первой отрисовки на сайте; причём с только что отрендеренным контентом можно взаимодействовать сразу же, не дожидаясь загрузки остального содержимого. content-visibility заставляет юзер-агент пропускать разметку и покраску элементов, не находящихся на экране. По сути, это работает как lazy-load, только не на загрузке ресурсов, а на их отрисовке.


В этой демке content-visibility: auto, применённый к разбитому на части контенту, даёт прирост скорости рендера в 7 раз

Поддержка


content-visibility основывается на примитивах из спецификации CSS Containment. Хотя на данный момент content-visibility поддерживается только в Chromium 85 (и считается «достойным прототипирования» в Firefox), спецификация Containment поддерживается в большинстве современных браузеров.

Принцип работы


Основная цель CSS Containment — повысить производительность рендеринга веб-контента, обеспечивая предсказуемую изоляцию поддерева DOM от остальной части страницы.

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

Всего есть четыре типа CSS Containment, каждое выступает значением для CSS-свойства contain и может быть скомбинировано с другими:

  • size: Ограничение размера элемента гарантирует, что блок элемента может быть размещен без необходимости изучения его потомков. То есть, зная размер элемента, мы вполне можем опустить вычисление расположения его потомков.
  • layout: Ограничение выкладки не даёт потомкам повлиять на внешнее расположение других блоков на странице. Это позволяет нам потенциально опустить размещение потомков, если все, что мы хотим сделать, это расположить другие блоки.
  • style: Ограничение стилей гарантирует, что свойства, влияющие не только на его потомков, не покидают элемент (например, счетчики). Это позволяет пропустить вычисление стилей для потомков, если все, что нам нужно, — это вычислить стили для других элементов.
  • paint: Ограничение покраски не позволяет потомкам отображаться за пределами своего контейнера. Ничего не будет налезать на элемент, и если он находится за границами экрана или так или иначе невидим, его потомки также будут невидимы. Это позволяет не отрисовывать потомков, если элемент уже за краями экрана.

Пропускаем рендеринг с content-visibility


Может быть непонятно, какие значения contain лучше использовать, поскольку оптимизация браузера может сработать только при правильно указанном наборе параметров. Стоит поиграться со значениями, чтобы эмпирическим путём узнать, что работает лучше всего. А лучше использовать content-visibility для автоматической настройки contain. content-visibility: auto гарантирует максимальный возможный прирост производительности при минимальных усилиях.

В автоматическом режиме свойство получает атрибуты layout, style и paint, а при выходе элемента за края экрана, получает size и перестаёт красить и проверять содержимое. Это значит, что как только элемент выходит из зоны отрисовки, его потомки перестают рендериться. Браузер распознает размеры элемента, но больше не делает ничего, пока в отрисовке не возникнет необходимость.

Пример — тревел-блог



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

  • Часть страницы загружается из сети вместе с необходимыми ресурсами
  • Браузер стилизует и размещает весь контент на странице, не различая контент на видимый и невидимый
  • Браузер переходит к шагу 1 до того пока не загрузит все ресурсы

На шаге 2 браузер обрабатывает содержимое, пытаясь найти изменения. Он обновляет стили и расположение любого нового элемента вместе с элементами которые могли быть изменены в результате обновлений. Это рендеринг. Он занимает время.



Теперь представим, что мы поместили content-visibility: auto на каждый пост в блоге. Основная система та же: браузер загружает и рендерит части страницы. Однако, разница в количестве работы, сделанной в шаге 2. С content-visibility браузер будет стилизовать и размещать тот контент который сейчас видит пользователь (на экране). Но обрабатывая истории вне экрана, браузер будет пропускать рендеринг всего элемента и будет размещать только контейнер. Производительность загрузки этой страницы будет как если бы она содержала заполненные посты на экране и пустые контейнеры для каждого поста вне его. Так получается гораздо быстрее, выигрыш составляет до 50% от времени загрузки. В нашем примере мы видим улучшение с 232мс рендеринга до 30мс, это улучшение производительности в 7 раз.

Что нужно сделать чтобы воспользоваться этими преимуществами? Во-первых, мы разделяем контент на части:



После, мы применяем последующую стилизацию на части:

    .story {
        content-visibility: auto;
        contain-intrinsic-size: 1000px; /* Объяснено далее */
    }

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

Определение типичного размера элемента с contain-intrinsic-size


Для того чтобы понять потенциальные преимущества content-visibility, браузер должен применять ограничения по размеру, чтобы гарантировать, что результаты рендеринга контента не будут влиять на размеры элементов. Это означает что элемент будет размещен как если бы он был пустой. Если у элемента не определена высота, то она будет равна нулю.

К счастью, у css есть ещё одна способность, contain-intrinsic-sizе, которая предоставляет возможность определить настоящий размер элемента, если тот подвергся сжатию. В нашем примере мы устанавливаем ширину и высоту примерно 1000px.
Это означает, что он будет располагаться так, будто там один файл «внутренного размера», при этом гарантируя, что div все ещё занимает место. contain-intrinsic-sizе выступает в качестве заполнителя.

Скрываем контент с content-visibility: hidden


content-visibility: hidden делает то же, что и content-visibility: auto делает с контентом вне экрана. Однако, в отличие от auto, он не начинает автоматический рендеринг контента на экране.

Сравним его с обычными способами спрятать контент элемента:

  • display: none: скрывает элемент и удаляет состояние рендеринга. Это означает что доставая элемент будет стоить той же нагрузки как и создание нового элемента.
  • visibility: hidden: скрывает элемент и оставляет состояние рендеринга. Это на самом деле не удаляет элемент из документа, так как он (и его поддерево) все еще занимает геометрическое пространство на странице и по-прежнему может быть нажат. Он также обновляет состояние рендеринга в любое время, когда это необходимо, даже если он скрыт.

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

Заключение


content-visibility и CSS Containment Spec позволяют значительно ускорять рендеринг и загрузку страниц без каких-либо сложных манипуляций, на голом CSS.
The CSS Containment Spec
MDN Docs on CSS Containment
CSSWG Drafts

При подготовке материала использовалась следующая информация — web.dev/content-visibility



На правах рекламы


Серверы для размещения сайтов — это про наши эпичные! Все серверы «из коробки» защищены от DDoS-атак, автоматическая установка удобной панели управления VestaCP. Лучше один раз попробовать ;)

VDSina.ru
Серверы в Москве и Амстердаме

Комментарии 22

    +4
    *{
    content-visibility: auto;
    }

    чики брики и в дамки, как говорится)
      0
      хитро )
      +4
      В нашем примере мы видим улучшение с 232мс рендеринга до 30мс, это улучшение производительности в 7 раз.

      Ок. На демке они уменьшили скорость рендеринга но при этом начало колбасить скролл. Причём понятно ешё когда при движении вниз так как там ещё не считались размеры элементов. Но при возрате наверх то почему? Браузер же уже должен был посчитать размеры и запомнить.

        +1
        Скролл еще и артефакты с краёв экрана вызывает. Самый нижний фон на доли секунды блоком проскакивает. Что самое интересное, фон контейнера для блоков с «content-visibility» не учитывается, даже если добавить последним блоком div без «content-visibility».
        +3

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


        Почему все сайты (которые не использовали flash) года так до 2012 работали молниеносно, как и браузеры тех времён, а потом что-то случилось и сначала браузеры стали в 3 раза медленнее, а потом и сайты с каждым годом стали тупить всё больше


        С теплотой вспоминаю контактик до редизайна, работал быстрее чем кликать успевал и firefox версии до 27 или 37 (не помню точно, помню, что 7ка на конце всё испортила) работал просто зверски быстро, даже ставил его на старый ноут пару лет назад и он работал там быстрее любого современного говнища

          0
          Всё сильно усложняется
          Да ещё и плохо стандартизируется)

          А так на мой взгляд это нынче сурьёзная проблема — тонкостей стало так много, что уже сложно всё отследить вручную. Скоро будут для сайтов какие-нибудь линкеры делать и оптимизаторы)
            0

            Я понимаю, что веб очень плотно вошел во все сферы, технологии развиваются эволюционно, и никто никаких breaking changes вносить не будет, но позволю себе помечтать:


            • Выкинуть все ненужные, устаревшие извращения, применяемые для разметки страниц. Множество UI-тулкитов предложили множество вариантов, зачастую лучших, чем HTML. Стоит сделать новую систему разметки, учитывающую накопленный опыт, и ориентированную на современные потребности, а не натягивать сову для разметки статических сайтов 90х на современный глобус, оптимизированную и лишенную старых недостатков.
            • Возможно, стоит даже выделить отдельные подмножества, оптимизированные на контент и оптимизированые для создания сложных веб-приложений (которые, чаще всего, занимают экран, а не предполагают скроллинг)
            • Есть, конечно, и более радикальное предложение. Дизайнерские изыски переоценены, может, вернемся к простой семантической разметке контента, а средство отображения само решает, как его отобразить? Adaptivity, portability, accessibility и прочие модные слова бонусом из коробки.
            • Все приложение компилируется в бинарь (WASM?), без необходимости парсить весь этот текст, по-сути, просто превращая браузер в кросс-платформенную библиотеку UI-тулкита. Правда, это идет в разрез с п. 2 и 3.
              +1
              Дизайнерские изыски переоценены, может, вернемся к простой семантической разметке контента, а средство отображения само решает, как его отобразить?
              С точки зрения заказчиков сайтов у Веба есть всего две задачи — показ рекламы и сбор телеметрии. Какой выкидывать, кто тогда за разработку сайтов платить будет? Тут даже RSS уже еле живое, от силы один сайт из трёх её поддерживает. Вот именно потому, что никому не нужно, чтобы пользователь просто брал контент и отображал как ему заблагорассудится. Наоборот, в дальнейшем отображение максимально затруднят в целях борьбы с блокировщиками рекламы и скрейперами. Навесят на странички DRM, кучу криптографии, вплоть до пересылки зашифрованных данных в буфер видеокарты с расшифровкой прямо на GPU. Так что тормозить оно будет всё больше и больше, увы.
                0
                Надеюсь, на фоне всего этого найдутся альтернативные сайты с простым отображением контента.
                  0
                  Было бы лучше, если бы появились альтернативные стандарты показа контента. Например контент в виде улучшенного JSON, а систему отображения пользователь выбирает себе сам (из разряда хочу две колонки справа а меню снизу), сервер же только выдает сам контент без стилизации.

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

                  Тогда появятся и альтернативные браузеры и стандарт будет умещаться в буклете, а не в 1200страничном документе, в котором часть подпунктов противоречит другим.
                    +2

                    Есть XML к которому цепляется XSLT шаблон. Сам XML хранит данные а шаблон их оформляет в XHTML. Но никто не запрещает взять пользователю только XML и оформить своим шаблоном.

                  0
                  Вот именно потому, что никому не нужно, чтобы пользователь просто брал контент и отображал как ему заблагорассудится.

                  Я так понимаю, некоторые сайты с "брал контент" напрямую борятся. Инстаграмм какой-нибудь против того, чтобы его картинки можно сохранять было. Только отображение, максимально ими контролируемое.

            –2
            При мощности канала в десятки мегабит обычный текст с парой картинок грузится больше 2 секунд, и это считается достижением — интернет, которого мы заслужили.
              +6
              Так десятки мегабит — это пропускная способность (сколько данных может проходить в секунду, когда передача уже идёт). А есть ещё такая вещь, как пинг — полное время прохождения сигнала до сервера. И, применительно к сайтам, TTFB (time to first byte, время от подачи запроса до получения первого байта данных).
              Это не быстро, ведь у вас на руках нет даже IP-адреса сайта, а есть лишь его доменное имя. Т.е. браузер сперва должен послать запрос на DNS-сервер, дождаться разрешения имени. Затем нужно установить с исходным сайтом соединение HTTPS, для чего сперва нужно запросить у сервера сертификат. Потом проверить этот сертификат, послав запрос на доверенный сервер сертификационного центра. Если всё в порядке, обменяться с исходным сервером ключами, для чего несколько раз понадобится гонять пакеты туда-сюда, и только после этого уже можно посылать запрос на собственно получение данных. Можете замерить, сколько по времени занимает просто начать получать данные:
              curl -o /dev/null -H 'Cache-Control: no-cache'  -s -w "Connect: %{time_connect} TTFB: %{time_starttransfer} Total time: %{time_total} \n" "https://habr.com"
                –1
                Потом проверить этот сертификат, послав запрос на доверенный сервер сертификационного центра.

                Этот этап можно пропустить при правильных настройках сервера.
                  0
                  Минусанувший не слышал о OCSP stapling.
                +3
                У грузовика с терабайтниками, едущего из Москвы в Санкт-Петербург, мощность канала составляет несколько Tbps, однако обычный текст с парой картинок будет грузиться не меньше 15 часов.
                +2
                Исправить медленный рендер как сделали в firefox? Нееет, вот вам новое свойство.
                  +2
                  А чего автор забыл указать что это перевод https://web.dev/content-visibility/ ? Или компания Google уже разрешает копирайты без разрешения… не хорошо
                    0
                    Сегодня Вася вместо 7 часов отработал всего час, а остальную работу оставил «на потом», пока менеджер не начнет его пинать. Такое вот увеличение производительности Васи в 7 раз!
                      +4

                      Статья, не оформленная как перевод, это воровство контента. Поправьте, пожалуйста, не позорьтесь.

                        0
                        Данный материал использовался при написании статьи, но не является единственным источником. Добавили информацию про используемый источник.

                      Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                      Самое читаемое