Bootstrap modal at top of iframe regardless of scroll position. How do I position it on screen?
Asked Answered
S

4

17

When embedding a Bootstrap app in an iframe, modal dialogs always open at the top of the iframe, not the top of the screen. As an example, go to http://getbootstrap.com/javascript/ and open an example modal on the page. Then using the sample code below which places the same bootstrap page in an iframe, find a modal and open it:

<html>
    <head>
    </head>
    <body>
        <table width="100%">
            <tr><td colspan="2" style="height:80px;background-color:red;vertical-align:top">Here's some header content I don't control</td></tr>
            <tr><td style="width:230px;height:10080px;background-color:red;vertical-align:top">Here's some sidebar content I don't control either</td>
                <td valign="top">
                    <iframe width="100%" height="10000px" 
                        scrolling="no" src="http://getbootstrap.com/javascript/">
                    </iframe>
                </td>
            </tr>
        </table>
    </body>
</html>

Demo in fiddle

How do I go about positioning the modal on the screen in this scenario?

UPDATE: Unfortunately, my iFrame cannot fill the screen, nor can I make it fixed since it needs to blend into the rest of the page and the page itself has enough content to scroll. This is not my design and I ultimately intend to rework the whole thing, but this is what I have to work around for now. As a temporary option, I'm using javascript to tell the iframe parent to scroll to the top where the modal dialog pops up. While this is acceptable, this isn't the desired behavior.

I'm using angularjs and the ui-bootstrap library in my code but as you can see above, it's a bootstrap issue.

Specify answered 17/7, 2014 at 13:42 Comment(0)
D
13

If your iframe has the same document.domain as the parent window or it is a sub domain, you can use the code below inside the iframe:

    $('#myModal').on('show.bs.modal', function (e) {
        if (window.top.document.querySelector('iframe')) {
            $('#myModal').css('top', window.top.scrollY); //set modal position
        }
    });

show.bs.modal will fire after you call $('#myModal').show() window.top.scrollY will get the scrollY position from the parent window

In case your document.domain differs from the parent, you can hack it getting the onmousedown position inside the iframe. For example:

$('#htmlElement').on('mousedown', function (event) {
    event.preventDefault();
    $('#myModal').data('y', event.pageY); // store the mouseY position
    $('#myModal').modal('show');
});
$('#myModal').on('show.bs.modal', function (e) {
    var y = $('#myModal').data('y'); // gets the mouseY position
    $('#myModal').css('top', y);
});
Doggerel answered 9/9, 2015 at 5:4 Comment(0)
P
4

Quite old question but I don't see the solution/workaround I've found. It might be helpful for someone in the future.

I had the same issue - my iFrame doesn't fill the entire screen, it displays bootstrap's modal and it is loading content from different domain than the parent page.

TL;DR

  1. Use window.postMessage() API - Documentation here. for communication between parent and iframe (cross-domain)
  2. pass message with currentScrollPosition and Y position of your iframe
  3. Reveive message and update modal's padding from the top

In my case the workaround was to use window.postMessage() API - Documentation here. It requires to add some extra code to the parent and handle message in an iFrame.

You can add EventListener and listen to 'scroll' event. Each time the event handling function is invoked you can get currentScrollPosition like document.scrollingElement.scrollTop. Keep in mind that your iframe can have some margin from the top in the parent page so you should also get its 'offset'. After that you can post these two values to your iframe e.g. ncp_iframe.contentWindow.postMessage(message, '*');

Note that the message has to be a String value

After that in your iFrame you need to add EventListener and listen to 'message' event. The event handling function will pass your 'message' in event.data property. Having that you can update modal padding. (Looks much better if you don't use animations e.g. fade, in classes);

Quick Example:

Parent:

window.addEventListener('scroll', function(event){
  var myIframe = document.querySelector('#myIframe');
  var topOffset = myIframe.getBoundingClientRect().top + window.scrollY;
  var currentScroll = document.scrollingElement.scrollTop;
  myIframe.contentWindow.postMessage(topOffset + ':' + currentScroll, '*');
});

iFrame:

window.addEventListener('message', function(event) {
  var messageContent = event.data.split(':');
  var topOffset = messageContent[0];
  var currentScroll = messageContent[1];

  //calculate padding value and update the modal top-padding

}, false);
Pollute answered 13/9, 2018 at 7:53 Comment(0)
S
2

This is a bug in most browsers (IE appears fine) where the elements are fixed to the iframe, not the window. Typically, if you need something to be relative to the main document, it has to be in the main document.

A workaround is to wrap your iframe in a fixed position div that takes up the whole width of the screen and then maximize the iframe within that. This appears to resolve the issue

HTML:

<div class="fixframe">
    <iframe src="http://getbootstrap.com/javascript/"></iframe>
</div>

CSS:

.fixframe {
    position: fixed;
    top: 0px;
    left: 0px;
    right: 0px;
    bottom: 0px;    
} 
.fixframe iframe {
   height: 100%;
   width: 100%;  
} 

Working Demo in fiddle

See Also:

Supporter answered 17/7, 2014 at 14:41 Comment(1)
this works great if the iframe fills the screen and can scroll itself, but my iframe, unfortunately, cannot scroll itself do to limitations of the existing page design. I've updated my question and the jsfiddle with these detailsSpecify
B
0

It is because the class .modal has position: fixed attribute. Try position: relative instead.

Breakout answered 17/7, 2014 at 14:26 Comment(1)
I tried this in my context and it produced weirdly opposite behavior where the modal started appearing far below the viewport. I think this may be because my iFrame situation is not exactly the way I posted it initially. I've updated my question with a more accurate representation of my scenario.Specify

© 2022 - 2024 — McMap. All rights reserved.