I've got html like so:
<body>
[some stuff]
<iframe src="pageWithMyScript.html"></iframe>
[more stuff]
</body>
I want to find the location of the iframe relative to window.top (and/or the top.document) from a script running inside the iframe. (Ideally this would be without any frameworks, though I can always deconstruct how they do it, I suppose.)
This can only work if both the iframe and the container share the same origin, otherwise CORS will have to be set up (to do this you will need access to both domains)
/**
* Calculate the offset of the given iframe relative to the top window.
* - Walks up the iframe chain, checking the offset of each one till it reaches top
* - Only works with friendly iframes. https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy#Cross-origin_script_API_access
* - Takes into account scrolling, but comes up with a result relative to
* top iframe, regardless of being visibile withing intervening frames.
*
* @param window win the iframe we're interested in (e.g. window)
* @param object dims an object containing the offset so far:
* { left: [x], top: [y] }
* (optional - initializes with 0,0 if undefined)
* @return dims object above
*/
var computeFrameOffset = function(win, dims) {
// initialize our result variable
if (typeof dims === 'undefined') {
var dims = { top: 0, left: 0 };
}
// find our <iframe> tag within our parent window
var frames = win.parent.document.getElementsByTagName('iframe');
var frame;
var found = false;
for (var i=0, len=frames.length; i<len; i++) {
frame = frames[i];
if (frame.contentWindow == win) {
found = true;
break;
}
}
// add the offset & recur up the frame chain
if (found) {
var rect = frame.getBoundingClientRect();
dims.left += rect.left;
dims.top += rect.top;
if (win !== top) {
computeFrameOffset(win.parent, dims);
}
}
return dims;
};
Most answers do not consider border and padding of the frame element.
Sometimes they are not 0, so it should be included in the conversion process.
Actual border and padding size of an element can be acquired from the "computed style".
function getTopBoundingClientRect( e )
{
const rcInit = e.getBoundingClientRect();
let f = e.ownerDocument.defaultView.frameElement;
if ( !f )
return rcInit;
const rc = { left: rcInit.left, top: rcInit.top, right: rcInit.right, bottom: rcInit.bottom };
do {
const frc = f.getBoundingClientRect();
const cs = f.ownerDocument.defaultView.getComputedStyle( f );
const lm = +cs.getPropertyValue( 'border-left-width' ).slice( 0, -2 )
+ +cs.getPropertyValue( 'padding-left' ).slice( 0, -2 );
const tm = +cs.getPropertyValue( 'border-top-width' ).slice( 0, -2 )
+ +cs.getPropertyValue( 'padding-top' ).slice( 0, -2 );
rc.left += frc.left + lm;
rc.top += frc.top + tm;
rc.right += frc.left + lm;
rc.bottom += frc.top + tm;
f = f.ownerDocument.defaultView.frameElement;
} while ( f );
return rc;
}
Of course, in cross-domain iframe, any code cannot access parent document (especially frameElement in above code.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With