Каждый фронтенд-разработчик хоть раз в жизни проклинал технологию <iframe>. Представь типичную задачу: тебе нужно встроить на сайт форму оплаты от стороннего банка, виджет авторизации или блок опросов. Все эти сервисы живут на чужих доменах, а значит, в силу вступает фундаментальное правило браузерной безопасности — Same-Origin Policy.
Родительская страница не имеет права заглянуть внутрь чужого DOM-дерева, чтобы измерить высоту содержимого. В итоге либо под фреймом зияет пустое белое пространство в пол-экрана, либо внутри него появляется уродливый вертикальный скроллбар, на который мучительно больно смотреть на смартфонах.
Годами мы городили сложнейшие архитектурные мосты: внутри фрейма вешали ResizeObserver, слали замеры через window.parent.postMessage, на родительской странице парсили событие message и меняли iframe.style.height. Как мы отмечали, когда обсуждали Адаптивные iframe в Chrome 154: нативное свойство frame-sizing взамен костылей с postMessage, такой подход порождал вечные гонки рендеринга и прыжки макета.
Эксперт Ахмад Альфи (Ahmad Alfy) подробно исследовал, как новая спецификация CSS Box Sizing Module Level 4 кардинально меняет правила игры в браузерах на базе Chromium 154+.
На стороне родителя: одно свойство frame-sizing
Больше никакого JavaScript-кода для отслеживания габаритов на главной странице. Достаточно объявить для фрейма нативное свойство:
<iframe class="payment-widget" src="https://pay.example.com/checkout" title="Оплата"></iframe>
<style>
.payment-widget {
width: 100%;
border: none;
/* Нативная автоматическая подгонка высоты под поток документа */
frame-sizing: content-height;
}
/* Безопасный фолбек для старых браузеров */
@supports not (frame-sizing: content-height) {
.payment-widget {
min-height: 520px;
}
}
</style>
Браузерный движок сам связывает расчет геометрии дочернего документа с общим деревом компоновки (layout) страницы. При изменении ширины окна и переносе текста высота пересчитывается мгновенно, без задержек на межконтекстные сообщения.
На стороне встраиваемого фрейма: явное согласие безопасности
Но позволить любому сайту в интернете считывать габариты чужой страницы было бы дырой безопасности (риск атак timing-attack и утечки приватных интерфейсов). Поэтому встраиваемый документ должен явно дать согласие через новый метатег:
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<!-- Разрешаем доверенному домену родителя измерять высоту документа -->
<meta name="responsive-embedded-sizing" content="allow-origins=https://shop.example.com">
<title>Форма оплаты</title>
</head>
<body>
<div class="checkout-form">
<!-- Интерактивное содержимое -->
<button onclick="expandAccordion()">Показать детали чека</button>
</div>
<script>
function expandAccordion() {
// При динамическом изменении DOM уведомляем движок о пересчете
if ('requestResize' in window) {
window.requestResize();
}
}
</script>
</body>
</html>
Если твой виджет предназначен для публичной встройки на любые сайты, значение атрибута можно задать как allow-origins=*.
А если пользователь нажимает внутри фрейма на спойлер или валидатор формы выводит динамический список ошибок, скрипт вызывает легкий метод window.requestResize(), и движок браузера плавно адаптирует размер контейнера.
Метатег <meta name="responsive-embedded-sizing"> обязан присутствовать в статическом исходном HTML-документе, который отдал сервер. Если попытаться создать и вставить его через JavaScript после загрузки DOM, движок безопасности Chromium проигнорирует директиву.
Пока Safari и Firefox дорабатывают реализацию в своих движках, прогрессивное улучшение через @supports (frame-sizing: content-height) позволяет уже сегодня избавить миллионы пользователей Chrome от скроллбаров внутри платежных виджетов.
