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.)
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.)
Share Improve this question asked Mar 12, 2012 at 22:01 sprugmansprugman 19.8k36 gold badges115 silver badges164 bronze badges4 Answers
Reset to default 7This 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/en-US/docs/Web/Security/Same-origin_policy#Cross-origin_script_API_access
* - Takes into account scrolling, but es 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 puteFrameOffset = 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) {
puteFrameOffset(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 "puted 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.)
A bit more simple like this :
function puteFrameOffset(win, dims ) {
dims = (typeof dims === 'undefined')?{ top: 0, left: 0}:dims;
if (win !== top) {
var rect = win.frameElement.getBoundingClientRect();
dims.left += rect.left;
dims.top += rect.top;
puteFrameOffset(win.parent, dims );
}
return dims;
};
A small correction:
function puteFrameOffset(win, dims ) {
dims = (typeof dims === 'undefined')?{ top: 0, left: 0}:dims;
if (win !== top) {
var rect = win.frameElement.getBoundingClientRect();
dims.left += rect.left;
dims.top += rect.top;
dims = puteFrameOffset(win.parent, dims ); // recursion
}
return dims;
};