0

Issue: I cannot natively lazy load an iframe on a modal window. When I check the waterfall in Inspect element > Network, the iframe loads immediately.

Goal: The iframe should load ONLY when modal is triggered. Can you help please?

I don't use dependencies like jQuery, but javascript is OK if it provides a solution. I tried the native and several other lazy loading solutions with no success.

My code:

.modal-state {
  display: none
}

.modal-state:checked+.modal {
  opacity: 1;
  visibility: visible
}

.modal-state:checked+.modal .modal__inner {
  top: 0
}

.modal {
  opacity: 0;
  visibility: hidden;
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  text-align: left;
  background: #f2f2f2;
  transition: opacity .01s ease;
  z-index: 7;
  display: flex;
  flex-direction: column;
  height: 100vh;
  overflow-y: auto
}

.modal__bg {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  cursor: pointer
}

.modal__inner {
  transition: top .01s ease;
  height: max-content;
  position: relative;
  max-width: 1200px;
  width: -webkit-fill-available;
  margin: auto;
  padding: 1em 1em;
}

.modal__close {
  position: absolute;
  right: 1.1em;
  top: 0;
  /*-.3em*/
  width: 1.1em;
  height: 1.1em;
  cursor: pointer;
  z-index: 1
}

.modal__close:after,
.modal__close:before {
  content: '';
  position: absolute;
  width: 2px;
  height: 1.5em;
  background: #999;
  display: block;
  transform: rotate(45deg);
  left: 50%;
  margin: -3px 0 0 -1px;
  top: 0
}

.modal__close:hover:after,
.modal__close:hover:before {
  background: #000
}

.modal__close:before {
  transform: rotate(-45deg)
}

.container-pay {
  position: relative;
  width: 100%;
  height: 200px;
  overflow: hidden;
  padding-top: 56.25%;
  /* 16:9 Aspect Ratio */
}

.responsive-iframe-pay {
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  width: 100%;
  height: 100%;
  border: none;
}
<p>In our <label for="modal-store">merchandize store</label>.</p>


<input class="modal-state" id="modal-store" type="checkbox" />

<div class="modal">
  <label class="modal__bg" for="modal-store"></label>
  <div class="modal__inner"><label class="modal__close" for="modal-store"></label>
    <p>
      <div class="container-pay">
        <iframe loading="lazy" class="responsive-iframe-pay" src="https://store.website.com"></iframe>
      </div>
    </p>
  </div>
</div>
NDi
  • 184
  • 1
  • 2
  • 17
  • 1
    Does no jQuery mean no Javascript at all? You can't stop something from loading by using CSS but you can control when it loads by appending the iframe or modal to the DOM before you show it and removing it when it's closed. – Bryce Howitson Jan 15 '21 at 20:25
  • Thank you for your kind reply. I agree with you. I will SURELY accept Javascript. Can you assist? – NDi Jan 15 '21 at 20:32

1 Answers1

1

iFrames load when they're encountered in the rendered HTML DOM. Since your iFrame exists as part of the initially loaded code, it will load when the parser hits that portion of the HTML.

You can defeat that initial load action by either adding the iFrame to the DOM or modifying the URL right before the modal window is opened.

Modifying the <iframe src="" /> is likely the best solution since it will keep the loaded content for any additional times the modal is displayed.

You can do this by adding an "onchange" event to the checkbox which will run the javascript to change the src attribute of the iframe.

Make sure to change the src on the iframe to an empty string"" so it doesn't try to load anything right away.

var toggle = document.getElementById('modal-store');
var frame = document.getElementById('the-iframe');
var urlTarg = "https://google.com";
// put the page you want to load in the frame in the urlTarg

function toggleModal() {
  if(toggle.checked && frame.src != urlTarg){
     frame.src = urlTarg;
  }
}
.modal-state {
      display: none
    }

    .modal-state:checked+.modal {
      opacity: 1;
      visibility: visible
    }

    .modal-state:checked+.modal .modal__inner {
      top: 0
    }

    .modal {
      opacity: 0;
      visibility: hidden;
      position: fixed;
      top: 0;
      right: 0;
      bottom: 0;
      left: 0;
      text-align: left;
      background: #f2f2f2;
      transition: opacity .01s ease;
      z-index: 7;
      display: flex;
      flex-direction: column;
      height: 100vh;
      overflow-y: auto
    }

    .modal__bg {
      position: absolute;
      top: 0;
      right: 0;
      bottom: 0;
      left: 0;
      cursor: pointer
    }

    .modal__inner {
      transition: top .01s ease;
      height: max-content;
      position: relative;
      max-width: 1200px;
      width: -webkit-fill-available;
      margin: auto;
      padding: 1em 1em;
    }

    .modal__close {
      position: absolute;
      right: 1.1em;
      top: 0;
      /*-.3em*/
      width: 1.1em;
      height: 1.1em;
      cursor: pointer;
      z-index: 1
    }

    .modal__close:after,
    .modal__close:before {
      content: '';
      position: absolute;
      width: 2px;
      height: 1.5em;
      background: #999;
      display: block;
      transform: rotate(45deg);
      left: 50%;
      margin: -3px 0 0 -1px;
      top: 0
    }

    .modal__close:hover:after,
    .modal__close:hover:before {
      background: #000
    }

    .modal__close:before {
      transform: rotate(-45deg)
    }

    .container-pay {
      position: relative;
      width: 100%;
      height: 200px;
      overflow: hidden;
      padding-top: 56.25%;
      /* 16:9 Aspect Ratio */
    }

    .responsive-iframe-pay {
      position: absolute;
      top: 0;
      left: 0;
      bottom: 0;
      right: 0;
      width: 100%;
      height: 100%;
      border: none;
    }
    <p>In our <label for="modal-store">merchandize store</label>.</p>

    <input class="modal-state" id="modal-store" type="checkbox" onchange="toggleModal" />

    <div class="modal">
      <label class="modal__bg" for="modal-store"></label>
      <div class="modal__inner"><label class="modal__close" for="modal-store"></label>
        <p>
          <div class="container-pay">
            <iframe id="the-iframe" loading="lazy" class="responsive-iframe-pay" src=""></iframe>
          </div>
        </p>
      </div>
    </div>

Edit: Apply to multiple different buttons showing content in the same iframe

You can apply this to multiple iframe targets on the same page or the same site with a few modifications. This assumes that:

  1. You'll re-use the modal window AND iframe HTML code.
  2. That you want to display a different URL each time the modal is opened
  3. The modal window HTML exists on each HTML page that you want to have modal + iframe.

You would modify the Javascript to something like this:

    // you'll pass all the required values to the function

    function toggleModal(checkbox, frameTarg, urlTarg) {
      var frame = document.getElementById(frameTarg);
      if(checkbox.checked && frame.src != urlTarg){
         frame.src = urlTarg;
      }
    }

You will only need the javascript once per parent page since the same function can work for any combo of checkboxes, iframes, and URLs

And the checkbox HTML to: (Note: the same function could be applied to a button, link, etc)

<input class="modal-state" 
   id="modal-store" 
   type="checkbox" 
   onchange="toggleModal(this, 'the-iframe', 'https://theurltoloadinframe.com')" 
/>

<input class="modal-state2" 
   id="modal-store" 
   type="checkbox" 
   onchange="toggleModal(this, 'iframe2', 'https://someotherurltoload.com')" 
/>

Basically, the function expects you to pass in:

  1. The current checkbox - (denoted by this)
  2. The ID of the iframe you want to change make sure its a string with quotes
  3. The URL you want to load in the iFrame also in a string
Bryce Howitson
  • 7,339
  • 18
  • 40
  • Thank you kindly for your suggestion. Can I apply this script to more than 1 modal windows, by adding more ids? – NDi Jan 15 '21 at 21:49
  • 1
    See if that makes sense – Bryce Howitson Jan 15 '21 at 22:10
  • It makes perfect sense and I will try to modify it also for IMAGES. Let me play with it for 15 minutes, and I will get back to you. – NDi Jan 15 '21 at 22:15
  • I didn't experiment yet on images, but I am sure I will make it happen eventually. Bryce not only the solutions you provided work flawlessly, but you also inspired me to learn more and become a better web developer. Very elegant and with MINIMUM code. Thank you so much for your time and effort! Respect. YOU ROCK! – NDi Jan 15 '21 at 23:08
  • 1
    why would you have two different elements using the same ID (see: 'modal-store' in example above)...? that doesn't make sense to me, shouldn't all IDs be unique? – m.arthur Sep 08 '21 at 04:30