javascriptiframetumblrtumblr-themes

Resize video embeds on Tumblr blog with JavaScript


I have a Tumblr theme with responsive design enabled, and want to resize video iframes. Here is a sample of how the page's HTML might look like:

/* rest of blog */
<div id="box-content">
    /* other posts; may contain more video posts */
    <div class="post video">
        <iframe src="[REDACTED]"
                style="display:block;background-color:transparent;overflow:hidden"
                class="embed_iframe tumblr_video_iframe"
                scrolling="no" frameborder="0"
                data-can-gutter="" data-can-resize=""
                data-width="500" data-height="500"
                width="500" height="500" allowfullscreen=""
                mozallowfullscreen="" webkitallowfullscreen="">
        </iframe>
        <div class="post-content">
            /* post content */
        </div>
    </div>
    /* other posts; may contain more video posts */
</div>
/* rest of blog */

I have this function that (I think; I never really learned JavaScript) stores the original width and height of the iframe, as well as the width of the parent, in variables, and changes the width and height of the iframe.

My intended method was

  1. Get all the elements with the class "video"
  2. There is a child iframe element for each of them. Store each of the following in its variable:

    a. that iframe's original width (ow), b. that iframe's original height (oh), and c. the parent element's width (cw for container width)

  3. Set the iframe's width to cw.

  4. Set the iframe's height to oh * cw / ow. (Explanation: cw / ow calculates the scaling factor to maintain the aspect ratio of the iframe.)
  5. Run the function once on load.
  6. Set an event listener for window resize.

...and the function that didn't work was:

function resizeVideos() {
    var videoPostNodeList = document.getElementsByClassName("video");
    for (var i = 0; i < videoPostNodeList.length; i++) {
        var videoNode = videoPostNodelist[i].getElementsByTagName("iframe")[0];
        var ow = videoNode.offsetWidth;
        var oh = videoNode.offsetHeight;
        var cw = videoPostNodelist[i].offsetWidth;
        videoNode.offsetWidth = cw;
        videoNode.offsetHeight = oh * cw / ow;

    }
}
resizeVideos();
window.addEventListener("resize", resizeVideos);

The current version of this theme is available at testing-html.tumblr.com, on which I currently have three videos reblogged: one square video, one horizontal widescreen video, and one vertical widescreen video. What amateur mistake did I make with this?


Solution

    1. An element's offsetWidth and offsetHeight are measurements of what's visible, including the element's borders, padding, scrollbar (if present & rendered) and CSS width.
      Example image showing what offsetWidth will return
      You do have other options though, like clientWidth and clientHeight
      Example image showing what clientWidth and clientHeight will return
      and scrollWidth and scrollHeight (which unfortunately doesn't have a good image on MDN)

      Based on your description of what you want, I'd say you should set your ow and oh based on the scrollWidth and scrollHeight properties instead.

    2. All of these properties are read-only, so you can't just set them directly.
    3. If I understand the situation correctly, your best bet is likely to be setting the elements max-width and max-height CSS properties (though you may prefer to directly override width and height):

      function resizeVideos() {
          var videoPostNodeList = document.getElementsByClassName("video");
          for (var i = 0; i < videoPostNodeList.length; i++) {
              var videoNode = videoPostNodelist[i].getElementsByTagName("iframe")[0];
              var ow = videoNode.scrollWidth;
              var oh = videoNode.scrollHeight;
              var cw = videoPostNodelist[i].offsetWidth;
              videoNode.style.maxWidth = cw;
              videoNode.style.maxHeight = oh * cw / ow;
          }
      }
      
    4. Finally, wait till the content is loaded before you run it (and as you did before, run it on window resize too):

      document.addEventListener("DOMContentLoaded", resizeVideos);
      window.addEventListener("resize", resizeVideos);
      

    See Determining the dimensions of elements on MDN for more info.