Allowing iframe overflow on mobile devices - javascript

I have to display a 3rd party link (cross-domain) on a webpage that is displayed on tablets and phones.
The 3rd party has decided to display a modal window, vertically centered on initial page load.
The problem I am running into is that the phones (iOS 5 mobile Safari, in particular) automatically resize iframe to fit the content, causing the modal window to be rendered off the bottom of the screen, due to it being many, many pixels tall.
I have tried everything I can think of to get the iframe to just display in a fixed size, but nothing works.
Adding height attribute or styles is ignored, even with !important
Wrapping the iframe in a div with -webkit-overflow-scrolling: touch; seems to work, but in this situation, still results in the iframe expanding and, thus, displaying the modal window off-screen.
Adding scrolling="no" allows the iframe to be displayed in a fixed size, but I can't get the iframe to scroll now.
I'm wondering if there are any alternatives to iframe or if there is anything I can do to get an iframe to properly display with a fixed size.
Oh, and I must mention, I cannot simply open the 3rd party link in a new window/tab, since this webpage is baked into an app, which I have no control over.
<!doctype html>
<html>
<head>
<title>Test</title>
<style>
iframe
{
height: 100px !important;
}
</style>
</head>
<body>
<iframe style="height:100px;" height="100" src="http://dump.mrslayer.com/test2.html"></iframe>
<script>
setTimeout( function( ) {
var iframe = document.getElementsByTagName( 'iframe' )[0];
iframe.style.height = "100px";
iframe.height = 100;
}, 1000 );
</script>
</body>
</html>

You could use PHP, but this prints the entire document contents inline with your document.
<?php
echo file_get_contents("http://dump.mrslayer.com/test2.html");
?>
If it's an issue, you can use regex or something like that to remove everything before the <body> tag and after the </body> tag after you have the file_get_contents().
You can include this function in a <div>, which should be easier to control with CSS. This is the easiest alternative to an iframe I can think of.

Related

How can I scroll inside an iframe, if the iframe has no scrollbars?

Does anybody now a solution for the following or at least know, where to find the documentation of this restriction?
I have a html page (the parent) including an iframe (child) without an libraries, just pure javascript and html. It does not matter if both are on the same domain or not. When I add an iframe with a height of 400px to my parent page and the child page inside the iframe is higher, it shows a scrollbar for the iframe. Inside my child page I add a button, which scrolls to position top: 100, left: 0 onclick, which means, that the iframe content is scrolled to its stop. This is working.
When I add an iframe with the height of 2200px, which is higher that the child iframe content and thus there is no scrollbar, this click event is not scrolling anymore.
The practical part:
What I want to solve is, that I have a parent page with a seamless integrated iframe. the iframe has much content, including forms. On smaller displays you have to scroll a bit, fill out the forms, scroll further and confirm a terms button. This validates the form fields and if a form is invalid, I want the iframe content to scroll to its position of the first invalid input fiel, if it is not in the current viewport
I tested it with current Firefox 109.
This is not a same domain issue, the actual logic works when not inside the iframe.
example parent code:
<h2>IFrame Resizing Testpage parent</h2>
<iframe src="scrolling-page.html" width="100%" height="400px" style="border:2px solid green;"></iframe>
<hr>
<iframe src="scrolling-page.html" width="100%" height="2200px" id="iframe-scrolling" style="border:2px solid red;"></iframe>
Example code of the child page:
<h2>IFrame Resizing Testpage</h2>
<div style="height: 2000px"></div>
<h2>IFrame Resizing Testpage End</h2>
<button id="scroll" type="button">scroll</button>
<script>
document.addEventListener("DOMContentLoaded", function () {
document.getElementById('scroll').addEventListener('click', (event) => {
console.log('test');
window.scrollTo(100, 0);
})
});
</script>

iFrame has fixed width of 300px, without any styling defining 300px

I'm using the iframe-resizer package to dynamically change the size of an iframe depending on content.
However, before even trying any dynamic resizing, I run into an issue with the basic iframe: it's always 300px in width. Whatever content I place inside the iframe, the width is always 300px. Will not move; overflow is hidden if I add something >300px and still takes up 300px if my content is smaller than that.
EDIT: To be clear, My problem is that I want to dynamically change the width of an iframe (cross-domain), but it always renders at 300px and will not change. I'm using the iframe-resizer package to successfully dynamically change the height, but that's nto working on the width.
In the parent site, I'm embedding the iframe as follows:
<script type="text/javascript"
src="https://cdn.jsdelivr.net/npm/iframe-resizer#4.2.11/js/iframeResizer.min.js">
</script>
<script type="text/javascript">
var i = new URLSearchParams(window.location.search).get("openWidget"); document.write('<iframe id="inlineFrameExample" title="Inline Frame Example" style="position: fixed; zIndex: 1000; bottom: 0; right: 0" frameBorder="0" scrolling="no" src="http://localhost:3001?openWidget=' + i + '"></iframe>');
window.iFrameResize({ log: true }, '#inlineFrameExample')
</script>
And the content in my for my framed site, I have the following elements and styling:
<div className="App" id="App2">
{openWidget && <div className="button">OK</div>}
{showMessage && <section>This is a message</section>}
<div>
<button className="button" onClick={() => setShowMessage(!showMessage)}>
Msg
</button>
<button className="button" onClick={() => setOpenWidget(!openWidget)}>
{openWidget ? "-" : "+"}
</button>
</div>
</div>
.App {
text-align: center;
float: right;
}
.container {
display: flex;
justify-content: flex-end;
float: right;
}
section {
background-color: mediumseagreen;
color: white;
width: 500px;
}
.button {
width: 100px;
height: 100px;
background-color: mediumseagreen;
color: white;
text-align: center;
float: right;
}
Note that there's nothing in there about width being 300px. There are other widths, but the iframe seems to ignore them and always set itself to 300px.
I also made two code sandboxes, and embedded one site in the other via an iframe. Unfortunately the iframe is hidden for some reason, but if you inspect and look for the iFrame with id="inlineFrameExample" (and not code sandbox's button iframe) you'll see it's 300px wide: https://exzts.csb.app/
The code for the parent site is here: https://codesandbox.io/s/eloquent-flower-exzts?file=/index.html
The code for the framed site is here: https://codesandbox.io/s/iframe-test-ss8fs
UPDATE: I also removed all css styling from both the parent site and the framed site. Still always stuck at 300px. I also viewed the CSS specs which says default will be default set to 300px under certain conditions, but I cannot figure out how to dissatisfy those conditions so that the 300px rule doesn't apply.
I want the iframe to resize based on width. The current set up works perfectly on height, and I understand there's something in the default specs for iframes that sets them to 300px if x conditions are met: w3.org/TR/CSS2/visudet.html#inline-replaced-width What I need is whatever styling/setting/attribute will disable this, so the width will act in the same way as the height (i.e. completely dynamic).
The iframe-resizer doesn't resize iframe width by default. You have to explicitly specify it using sizeWidth setting.
window.iFrameResize({
log: false,
sizeWidth: true,
checkOrigin: false,
widthCalculationMethod: "rightMostElement",
heightCalculationMethod: "lowestElement"
}, "#myFrame");
body { background-color: wheat;}
iframe { border: 3px dashed green; }
span { font-size: 1.5rem;}
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/iframe-resizer#4.2.11/js/iframeResizer.min.js"></script>
<div>Following iframe grows automatically!</div>
<iframe id="myFrame" scrolling="no" src="https://mvyom.csb.app/"></iframe>
<span>😵😜🤪</span>
The iframe content is animated so it affects iframe's width and height according to the specified width and height calculation methods. And the iframe-resizer updates dimensions on every animations start and end event.
Also, the iframe source is from codesandbox and the parent document is this StackOverflow answer page, so we need to set checkOrigin: false as well.
Note: Had to set log: false because the animations are happening very fast creating ton of logs in console.
You can provide your own size calculations form inside the iframe.ref:
<script>
window.iFrameResizer = {
widthCalculationMethod: function () {
return document.querySelector(".one").clientWidth;
}
};
</script>
In following demo the iframe resizes exactly to the width of green box.
window.iFrameResize({
log: false,
sizeWidth: true,
checkOrigin: false,
widthCalculationMethod: "rightMostElement",
heightCalculationMethod: "lowestElement"
}, "#myFrame");
body { background-color: wheat;}
iframe { border: 3px dashed green; }
span { font-size: 1.5rem;}
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/iframe-resizer#4.2.11/js/iframeResizer.min.js"></script>
<div>Following iframe grows automatically!</div>
<iframe id="myFrame" scrolling="no" src="https://mvyom.csb.app/custom.html"></iframe>
<span>😵😜🤪</span>
Refer implementation of custom.html for better understanding. You can implement similar method for heightCalculationMethod.
Not sure if I understand the question. I think you've made an App and a page. On the page you want to use an iframe to show your App and the iframe should be scaled by default to the size of the app. Did I get that right?
I think JavaScript might by your solution. Get the content from the iframe, check in the content for a class App en that's the width you want to use for your iframe.
const iframe = document.querySelector("#inlineFrameExample");
const iWindow = iframe.contentWindow;
const iDocument = iWindow.document;
const iElement = iDocument.querySelector(".App");
iframe.style.width = iElement.style.width;
A problem with this script is that it can only be executed after the content from the iframe was loaded. So make sure you wait for that with a timer,delay, promise, or something. If you don't want to show the resizing to your visitors make sure the iframe has visibilty: hidden and add visibilty: visible of the iframe to the end of the script above.
#crevulus, the inner content of iframe has no impact on the dimensions of it's parent iframe by design
Also, as far as I remember, 300x150px is the common default width and height applied by browsers to any «iframe» element faced in html code on parsing incoming html and building the DOM stages, when the dimentions have been not predefined explicitely
The thing is a browser requires the dimentions of any visible element (i.e. any element that takes space in page layout - for simplicity, let's say any element except those where «display» property has been set to «none») either to be strictly predeclared with «width» and «height» properties (via element attributes with the same names, via internal / external css rule or css rule applied to element directly thru «style» attribute - the way doesn't matter) or to be calculable thru initial (default) values defined in html / css standards (again, for simplicity, if «div» element has no dimentions set, but all the neighbours do, its width will be calculated by browser as all available horizontal space between the left and right neighbours of the element, i.e. the «div» will always have initial width, defined by standard, which equals 100%; similary, the height of this «div» will be calculated as sum of heights of all its internal elements) - the dimentions are strictly required because w/o concrete values for every visible element on page a browser won't be able to render the page content for the current viewport correctly
So, when a browser parses incoming html code and faces «iframe» elements with no predefined dimentions (via attributes, css et cetera), to allocate the space for the element in page layout and thus to be able to move on to parse / render the whole page, a browser assumes the dimentions of the «iframe» as common defaults, which, as I mentioned above, equals square figure 300x150px («recumbent skyscraper»)
To override this behaviour, you should predeclare in any convenient way initial values, which will be suitable for your case
<iframe id="frame1" width="100%" height="250px" />
or
<style>
#frame1 {
width: 100%;
height: 250px;
}
</style>
<iframe id="frame1" />
et cetera, and then, when a page is rendered, if needed, use JavaScript to tune the dimensions of this iframe accoring to the width and height of its content (or any other condition on your choice), like
var frame1 = document.getElementById('frame1')
var width1 = parseFloat(frame1.style.getPropertyValue('width')) | 0
var height1 = parseFloat(frame1.style.getPropertyValue('height')) | 0
/*
* some stuff to define the conditions for iframe dimentions tuning and
* to calculate new width and height and to assing calculated values
* to width1 and height1 variables respectively
*/
frame1.style.setProperty('width', width1 + 'px')
frame1.style.setProperty('height', height1 + 'px')
As a postscript I'd like to note the above is the working concept, 'cause a few month ago I've designed and developed the close scheme to force the iframe of TinyMCE editor, built in Magento 1.9.x admin backend, to keep editor's width always equal to the width of CMS page on site's frontend and to expand / shrink editor's height dynamically accoring to the height of CMS page content being edited
The goal was to simplify and optimise the working process for the content department by making CMS pages in Magento admin area always look in TinyMCE editor exactly the same as on site's frontend
Unfortunately, the whole 1st gen of Magento, up to the last 1.9.4.5 release, is supplied with unspeakable outdated release of TinyMCE editor - 3rd gen of TinyMCE, published in early 2014 even before html5 officially arrived, in comparison even with it's own current 5th gen (which, in turn, frankly, is much inferior to alternative modern lightweight apps of WYSIWYG class) for 2022 feels like the Stone Age, a clumsy craft developed with stone axe by cave dwellers, both in terms of stability and functionality
In other words, that TinyMCE is missing the lion's share of useful builtin APIs / plugings, including the modern one to maintain the editor's dimentions in nominally simplified way, so the only way to achieve the goal I've researched has been to utilize onInit and onChange events provided by TinyMCE3, and to maintain the whole routine with custom JavaScript handlers over the editor, applying the dimentions directly to iframes on the parent level in Magento admin page code, which Magento core utilizes as containers for TinyMCE3 instances
Anyway, the experiment has been successful, so please feel free to ask any additional practical questions or to request some tech details on routines
The good news
If the page loaded by the iframe is on the same domain as yours, then you can easily find out the initial state by defining an onload attribute to the iframe and then access the contentWindow of the iframe and do some measurements and then apply them on your main page. But, as you said, the content of the iframe is from another origin. Bad luck, read on.
Some hope
Well, we know that you cannot directly access the content of the iframe. But, the content of the iframe may let you know when certain events happen. If the content inside the iframe does send messages, then you can addEventListener for message type events and specify the origin to be the site you are using inside the iframe. More info here: https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage
So, the site inside the iframe does some messaging? Maybe yes. But probably not. If it does not message you at the time of events of interest, then read on.
The bad news
Modern browsers do not allow you to directly run Javascript at other origins due to security reasons. One obvious example for this is that cookies can be read for a page and you absolutely do not want some third-party sites to mess with your cookies while you are doing a banking transactions or something of the like.
Some glimmer of hope
You may be able to somehow determine the current state of the iframes content. For example you may have access to API functions or something of the like that you can ask about your status. If those are leaking direct information about your situation inside the iframe (was the button clicked already, for instance?), then you may be able to poll such a source and see whenever a size changing event happens and if so your code could adapt your view accordingly. This way you would use another source of information to find out what is happening inside the iframe.
Sad but true
In general, the answer to your main question is NO. The explanation is that it is not allowed due to security reasons.
You may have some workarounds in your specific situation that may work out for you, but such workarounds are rarely available, most websites are working without providing supports for other websites that would like to use them in iframes. If the workarounds are not available for you, then you may want to reach out to the owner of the website shown in your iframe and see whether he/she is okay with providing support for this. Otherwise you will have to accept that the situation is beyond repair. Is it? If you are not satisfied yet, read on.
Desperation
If you really, really need to resolve this, then here's what you can do:
create a page in the same domain as your main page
from the browser's point of view both your main page and the page inside the iframe are using the very same domain, so they can reach each-other via Javascript
this new page will request the site to be shown in the iframe where the page of the other domain was shown previously (you don't create a further nested iframe, you just change its src)
and it will display it
but you add a little bit of Javascript, doing some measurements
and of course you adjust resource URLs accordingly, changing all relative URLs into absolute URLs
This might work, but it's very cumbersome and you will always need to adjust the given page whenever the site you are to use changes.

iframe cutting off at bottom of page

I have a page with an iframe that displays an image and comments. I don't want anyone to be required to click in the iframe and scroll to see all the content. I've set the height of the iframe to 2500px in hopes that I would only have to scroll the parent frame to view all the content. This isn't working though, it just cuts off at the bottom of the window, forcing me to click inside the iframe and scroll to view everything.
in short, I want to view all content within iframe, without having to click inside the iframe to scroll inside it. any way to do this with css or js?
Is the iframe on the same domain?
It is not a good idea to give a pixel size to a variable size iframe.
This is a solution for a dynamic size:
<script type="text/javascript">
function resizeIframe(iframe) {
iframe.height = iframe.contentWindow.document.body.scrollHeight + "px";
}
</script>
and on you iframe in the html:
<iframe onload="resizeIframe(this)" ...

Display Loading GIF on page load - Iframe?

I am loading an IFrame containing a page with a long list of dynamic data into a site. It takes a few seconds to load depending on the broadband speed and needs to be iframed due to the setup.
I would like to show a loading GIF so the user knows something is happening, but I'm struggling to make it appear as a background image in either the parent page container or the div surrounding the content within the iframed page.
<head>
<script>
var foo = function(){
var a = document.getElementById('content');
var b = document.getElementById('loading_img');
a.style.top='';
a.style.left='';
a.style.position='';
b.style.display='none';
};
</script>
</head>
<body onload="foo();">
<img id="loading_img" style="display:block;margin:20px auto;" src="loading.gif" />
<div id="content" style="position:absolute;left:-8000px;top:-20000px;">
.. table .. and stuff
</div>
</body>
not tested, but should work :)
You could add the image as a background of the body element inside the iframe, with a position near at the top and centered. E.g. background-position: center 30px
When table rendering starts, the image will be overlapped, so it's not even necessary to remove it via javascript.

Scrollbar to Top of iFrame Container Div on Each Page Load?

I have an iframe with external content that is scrolled from a parent div (the iframe has a large height, while the iframe container div has a smaller height).
As a result, when I scroll to the bottom, the scrollbar stays there when I load another page into the iframe.
Is there any way to send the container scrollbar to the top whenever the iframe loads another page?
Thank you.
I guess this was relatively simple, but it wasn't working for me when I had the javascript in an external file. So I put it into the HTML file:
<script language="javascript">
function gotop()
{
document.getElementById('iframeContainer').scrollTop = 0;
}
</script>
<iframe src="http://whatever.com" onload="gotop()"></iframe>

Categories

Resources