Responsive iframe in Drupal 8 from Client Embed Code

 

Nobody likes iframes. That's because you can't style their innards, and they aren't responsive... or are they?!?!

The first thing to know about here is the padding height hack. This allows you to set the height of an object relative to the width, because while height is always as a percentage of the container, padding height is as a percentage of width. So all you have to know is the ratio of height to width and you can make a thing that responsively scales.

My first attempt was to use javascript to get the viewport height from the iframe. Turns out, no, you can't do that. Even if you find some Stack Overflow that seems to say you can. We knew this already, didn't we?

What I did next was to make a field for the client to paste in the embed code. In iframe embed code there's almost always a width and a height. So, just scrape that from the HTML in a preprocess hook, and then set the padding accordingly in the twig file.

Here's my preprocess hook. You can learn more about HTML parsing found in this hook in my post here.

function mytheme_preprocess_field(&$variables, $hook) {
  if ($variables['field_name'] == 'field_myiframe_embed_code') {
    $embed = !empty($variables['items'][0]['content']['#context']['value']) ? $variables['items'][0]['content']['#context']['value'] : '';
    if (!empty($embed)) {
      foreach (Html::load($embed)->getElementsByTagName('iframe') as $iframe) {
        $variables['src'] = $iframe->getAttribute('src');  / Sets a variable `src` accessible in the twig template
        $width = $iframe->getAttribute('width');
        $height = $iframe->getAttribute('height');
        $variables['paddingTop'] =  $height / $width * 100; // Sets a variable `paddingTop` accessible in the twig template
      }
      if (empty($width) || empty($height) || empty($variables['src'])) {
        drupal_set_message('There\'s something wrong with your embed code. Please fix. Needs height, width, and src.', 'error');
      }
    }
    else {
      drupal_set_message('No value found for your embed code', 'error');
    }
  }
}

Here's my twig field template (field--field-myiframe-embed-code.html.twig):

<div class="myiframe__iframe-wrapper" style="padding-top: {{ paddingTop }}%;">
  <iframe src="{{ src }}" class="myiframe__iframe" />
</div>

And here's the CSS I used, more detail here.

.myiframe__iframe {
  position: absolute;
  top:0;
  left: 0;
  width: 100%;
  height: 100%;
  border: none;
}
 
.myiframe__iframe-wrapper {
  position: relative;
  height: 0;
  overflow: hidden;
}

About the Author

Hi. My name is Jeremiah John. I'm a sf/f writer and activist.

I just completed a dystopian science fiction novel. I run a website which I created that connects farms with churches, mosques, and synagogues to buy fresh vegetables directly and distribute them on a sliding scale to those in need.

In 2003, I spent six months in prison for civil disobedience while working to close the School of the Americas, converting to Christianity, as one does, while I was in the clink.