NOTE: As far as I know there is no one-sided solution for this problem – it can’t be done with just the iframe or just the website, you need to have access to both iframe code and the site hosting it.
A while ago, our client noticed that the iframe does not show scroll, so it’s impossible to know there is a register button in their app iframe.
The idea was to always show the scroll bar using CSS or something like this. And it worked everywhere… except iOS 14 🤦 , because custom scrollbars are no longer supported in iOS 14.“
Since there was no way to indicate to our users that the iframe is scrollable we decided to adjust the iframe height dynamically based on its content.
window.postMessage to the rescue
// Iframe
function resize() {
var height = $(html).height();
// Backwards – send message to parent
window.parent.postMessage(['setHeight', height], '*');
}
// Parent
window.addEventListener('message', function (e) {
var $iframe = $('#the-iframe');
var eventName = e.data[0];
var data = e.data[1];
switch (eventName) {
case 'setHeight':
$iframe.height(data);
break;
...
}
}, false);
This is the basic structure: iframe can via window.parent.postMesage let the parent (i.e. the website hosting it) know its size, and the parent gets it via the window.addEventListener(‘message’ …
In our specific case it looked like this:
// iframe
let height;
const sendPostMessage = () => {
// to determine our id
var params = getQueryParams(window.location.href);
// if height has changed (new content or screen resize)
if (height !== document.getElementsByClassName('iframe-wrapper')[0].offsetHeight) {
// determine the height
height = document.getElementsByClassName('iframe-wrapper')[0].offsetHeight;
// and send it to the parent
window.parent.postMessage({
frameHeight: height,
frameId: params.id
}, '*');
// console.log(height); // just for testing purposes
}
}
window.onload = () => sendPostMessage();
window.onresize = () => sendPostMessage();
// website
window.onmessage = (e) => {
// make sure its the message we need
if (e.data.hasOwnProperty("frameHeight") && e.data.hasOwnProperty("frameId")) {
// to avoid retroactively adding/using ids on iframes
var frameovi = document.getElementsByTagName('iframe');
for (let frame of frameovi) {
let src = frame.getAttribute('src');
// in the case of lazy-loading
let dataSrc = frame.getAttribute('data-src');
if(
(src && src.includes(`iframe?id=${e.data.frameId}`))
|| (dataSrc && dataSrc.includes(`iframe?id=${e.data.frameId}`))
) {
// adjust the height
frame.style.height = `${e.data.frameHeight + 60}px`;
}
}
}
};
Notice that you can use this pattern to send any sort of information from the iframe to the parent. In case you’d like to find some additional amazing iframe features, make sure you check Ben Vinegar’s seamless talk.