frame-sizing не решает проблемы размера ифреймов?
• css, html, js, dom
Проблема
<iframe> очень давно пытается дать возможность показать кусочек другого сайта. И вариантов использования масса: всевозможные видео-плееры, кнопки соц-сетей, движки для комментов и так далее. Но ифреймы обладают и пачкой нюансов, которые мешают ими пользоваться, а для разработчиков браузеров являются головной болью.
Одна из таких болей – размер ифрейма. Традиционно, размером контента управляет страница, которая встраивает содержимое другого сайта. Если же хочется сделать ифрейм по содержимому, то обычно делают window.top.postMessage(...), в котором прокидывают желаемый размер (а в верхней странице должен быть код, который это всё слушает и реагирует).
В случае, если контента больше, чем доступного места, ифрейм получает скроллбары, что резко начинает выделять ифрейм, делая его чужеродным для сайта.
Как раз проблему размеров ифреймов и пытается решить frame-sizing.
frame-sizing
frame-sizing – молодое CSS свойство, которое только-только появилось в Хроме 154 (текущий стабильный релиз на момент написания поста). У него есть 5 возможных значений:
auto(по умолчанию, или текущее поведение по всех браузерах)content-widthcontent-heightcontent-inline-sizecontent-block-size
Значения content-* заставляют внешнюю часть ифрейма принимать размер по содержимому ифрейма (будь то ширина или высота).
Однако такого функционала не было не просто так: в случае, если мы встроим другой сайт в нашу страницу, то информация о контенте страницы может выдать приватные данные (например, авторизован ли пользователь на странице банка). Чтобы этого не произошло, frame-sizing требует вторую часть апи, которая подтвердит уже изнутри фрейма, что его размеры использовать можно. Эта часть реализована через метатег:
<meta name="responsive-embedded-sizing" content="allow-origins=*">allow-origins – это не атрибут, а именно часть значения атрибута content. Звёздочка * – разрешено встраивание по размеру на всех origin, также можно указать и конкретный список через пробел. Важно: если вы хотите разрешать/запрещать встраивание вашей страницы (не по размеру, а вообще), используйте CSP и frame-ancestors, тут ничего не меняется.
Но и это ещё не всё. Размер выставляется один раз на загрузку ифрейма (в момент DOMContentLoaded). В случае, если контент поменялся (и размер содержимого вместе с ним), дочерняя страница внутри ифрейма может позвать window.requestResize(), который заставит пересчитать размеры ифрейма. Авторы рекомендуют вызывать метод после изменений в DOM, но до реального лейаута страницы.
Вся эта конструкция с однократным выставлением размеров сделана для того, чтобы браузер не ушёл в бесконечный цикл, вычитывая размеры (хотя в примере из статьи используется ResizeObserver для синка размеров, что, на мой взгляд, являются костылём).
Плюсы и минусы
Апишка состоит из HTML, CSS и JS, и призвана решить непростой вопрос. Какие же у неё плюсы и какие случаи она покрывает?
- Вместо кустарного обмена сообщениями между страницами – встроенное в браузер решение
- С
postMessageвозможен “лаг” между лейаутами двух страниц (из-за того, что postMessage асинхронный). В теории, сwindow.requestResize()этой проблемы не будет
Минусы:
- Только ширина или высота, но не вместе. Я так понимаю, что это ещё одно ограничение лейаута браузера, которое могло приводить к циклам
- Апи покрывает только случай уже загруженного ифрейма, но размер ифрейма в процессе загрузки всё ещё нужно решать самим. В том числе управлять видимостью ифрейма и отслеживать состояния “готовности” и “ошибки”, а тут без
postMessageснова не обойтись window.requestResize()может выкидывать ошибки (в случае, если что-то пошло не так иresponsive-embedded-sizingне заработал). Поэтому нужно оборачивать вtry-catch, и продумывать фолбек… В тот жеpostMessage, от которого ещё долго не избавитьсяwindow.requestResize()вызывать после каждого изменения может быть утомительно, кроме того, этот подход не учитывает другие изменения (зум страницы, загрузку шрифтов и так далее).ResizeObserverрешает проблему, но он противоречит идее АПИ. А встроенного отслеживания размеров у ифрейма нет- Скорее всего, ифреймы с высотой выше окна браузера всё ещё будут плохо себя вести. Особенно в слабых устройствах, планшетах, при быстрой прокрутке и так далее. Ифрейм – чужеродный контент для страницы, и его отрисовка может быть в разы более сложной для браузера, часть оптимизаций работать не будет
Итого
postMessage всё ещё нужен. В случае, если вы делаете виджеты для других сайтов – о новом апи стоит знать (и подумать над его интеграцией), но глобально он как будто ничего не меняет.
Проблема решена, но лишь отчасти. Суммарно мы имеем целую пачку ограничений, которые на практике оставляют нас со старым подходом. Что это – костыль для гугловых сайтов и популярных встраиваемых движков комментирования? Пока не очень понимаю, но могло быть лучше.
Обсудить в Telegram



