YouTube iframe, shadows, rounded corners, and Safari
Tags: webdev, css, codepen, showdev
Published: 2021-10-23 12:42:44

---
title: YouTube iframe, shadows, rounded corners, and Safari
published: true
description: Making a YouTube embed with shadow and rounded corners look good in Chrome, FF, and Safari.
tags: webdev, css, codepen, showdev
//cover_image: https://direct_url_to_image.jpg
---

## Context

Recently I was tasked with embedding a YouTube video in one of our landing pages. Straight-forward enough it seemed and indeed it was, until a new requirement came in last minute (as they tend to do): the embedded player needed to also have rounded corners.

This requirement complicated things a bit because the embed also had a shadow applied to it. Ultimately, implementing it would lead me to noticing strange behavior regarding shadows in Safari. 

Read on if you dare! Alternatively, if you want to just see the code, check out [this codepen for an example](https://codepen.io/tmns/pen/wvqMygj).

## Approach #1: `border-radius`

First, let's take a look at our baseline markup and styles to get a feel for what we were working with:

```html
<div class="container">
  <div class="iframe-wrapper">
    <iframe src="https://www.youtube.com/embed/FcANFVcJeOM?disablekb=1" title="Live performance of Weird Fishes by Radiohead" frameborder="0"></iframe>
  </div>
</div>
```

```scss
.iframe-wrapper {
  position: relative;
  aspect-ratio: 16 / 9;
  box-shadow: 0 0 6px rgb(0 0 0 / 50%);

  iframe {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
  }
}
```
_Note: the styles above are in scss._

My initial thought was to just throw a `border-radius` on `.iframe-wrapper` and call it a day. Indeed this seemed to work fine in Chrome and Safari. However, in Firefox the corners looked very choppy and ugly. As such, that option was out. 

So, unfortunately, our simple approach #1 == ❌

## Approach #2: `clip-path` and `filter: drop-shadow()`

My next thought was to apply a `clip-path` to the `iframe` in order to generate the desired border radius and then apply a `drop-shadow` filter on `.iframe-wrapper` (so that the generated shadow would respect the shape created by the `clip-path`):

```scss
.iframe-wrapper {
  position: relative;
  aspect-ratio: 16 / 9;
  filter: drop-shadow(0 0 4px rgb(0 0 0 / 50%));

  iframe {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    clip-path: inset(0% 0% 0% 0% round 10px);
  }
}
```

This looked great in Chrome and Firefox! The jagged corners that were previously being generated by `border-radius` were gone and in their place was nothing but wonderful smoothness.

I opened up Safari and expected to see the same... but to my horror... what I saw on the screen was a shadow being applied to the player that looked as if I had set a `box-shadow` on `.iframe-wrapper`. See the following screenshot for an example (if the quality isn't good enough you can open the [codepen](https://codepen.io/tmns/pen/wvqMygj) in Safari and replace the styles with those above):

![Strange square shadow applied to iframe in Safari](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/63yzwrjs244xjl680o5m.png)

What is that??! 🤯

To make things even more strange, on non-touch screen devices this weird extra box shadow would disappear and the correct `drop-shadow` would appear as soon as Safari lost focus (e.g. switching applications or interacting with something in dev tools). Conversely on mobile it would disappear once I interacted with the page 😱 

See the following gif for an example of this behavior (again, if the quality isn't good enough you can open the [codepen](https://codepen.io/tmns/pen/wvqMygj) in Safari and replace the styles with those above). Notice, upon switching to the calendar and back the weird square box shadow disappears and the desired drop shadow comes in:

![Upon switching applications the correct shadow is rendered](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2dk93mqhj1lhamnzxvsn.gif)

I still don't understand exactly what the issue was here but indeed it seems that in Safari `drop-shadow` is not applied correctly on first load.

This, of course, was not acceptable.

So, unfortunately, our approach #2 also == ❌

## Approach #3: ?

Now, where could I go from there? How could I simulate a `filter: drop-shadow()`, i.e. a shadow that respects an inner element's contour?

Somewhat unexpectedly, I discovered that keeping the `clip-path` on the `iframe` and applying `border-radius` and `box-shadow` to `.iframe-wrapper` would give me the best of both worlds. That is, the corners would remain smooth in Firefox and the shadow would render correctly in Safari:

```scss
.iframe-wrapper {
  --border-radius: 10px;
  position: relative;
  aspect-ratio: 16 / 9;
  border-radius: var(--border-radius);
  box-shadow: 0 0 6px rgb(0 0 0 / 50%);

  iframe {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    clip-path: inset(0% 0% 0% 0% round var(--border-radius));
  }
```

The only issue I noticed with this approach was that sometimes a strange extra border would peek out from behind the player:

![Strange extra border](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7zdz3k4nvteyhxozqlb4.png)

Further, it wasn't always on the right side. Sometimes it would show up on the bottom 😵‍

However, this ended up being solved quite easily by adjusting the `background-color` of `.iframe-wrapper`! Further, this also had the side effect of providing a quasi-placeholder as the video loads 🤙

In the end, the following declarations gave me the perfect rounded corners and shadow I was after:

```scss
.iframe-wrapper {
  --border-radius: 10px;
  position: relative;
  aspect-ratio: 16 / 9;
  /* The next three declarations simulate
     `filter: drop-shadow(0 0 4px rgb(0 0 0 / 50%));` 
  */
  border-radius: var(--border-radius);
  box-shadow: 0 0 6px rgb(0 0 0 / 50%);
  background-color: rgba(0, 0, 0, 0.3);

  iframe {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    clip-path: inset(0% 0% 0% 0% round var(--border-radius));
  }
```

So, eventually Approach #3 == 👍

## Conclusion

At the end of the day I was quite happy with the result and it worked for the given task. Of course, I would have liked to stop at Approach #2 (just `drop-shadow`); however, I couldn't release something that would look bad on Safari and in turn iOS.

What do you think about this Safari issue? Have you ever ran into it yourself? I couldn't find anything about it in my research 🤷‍♂️

Let me know!

### Update / Approach #4

Just saw a cool effect being used on the YouTube embed at Next.js Conf. They set a linear gradient background with a blur on a pseudo element of the embed's container / wrapper `div`.

This could also be used in our case to achieve our desired shadow, replacing the three declarations added in Approach #3:

```scss
.iframe-wrapper {
  position: relative;
  aspect-ratio: 16 / 9;
  
  &::before {    
    content: "";
    position: absolute;
    inset: -5px;
    z-index: -1;
    background: #000;
    filter: blur(10px);
    opacity: .75;
  }

  iframe {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    clip-path: inset(0% 0% 0% 0% round 10px);
  }
}
```

This is a nice approach and seems to work well in all browsers. This conference hasn't even started yet and I've already learned something 😄