Add a floating tooltip relative to the content of the 'cover' video

Viewed 44

Let's say I have a video with a known aspect ratio. I need to make it act like a fixed background-cover for a full-screen section (100vw / 100vh).

But also I need to attach some floating absolute-positioned elements, relative to the content of the video. For example, 60% left / 40% top point relative to the content of the video .

So If I use object-fit: cover on the video, and position: absolute for the floating elements, I can no longer just provide left / top percentage offset, because those percents no longer match the content of the video.

I tried to overcome this problem by using some math formulas like:

--video-aspect-ratio: 1680 / 944;

--video-height: max(100vh, 100vh / var(--video-aspect-ratio));
--video-width: max(100vw, 100vw * var(--video-aspect-ratio));

--vertical-video-offset: min(0%, (100vh - var(--video-height)) / 2);
--horizontal-video-offset: min(0%, (100vw - var(--video-width)) / 2);

position: absolute;
inset: var(--vertical-video-offset) var(--horizontal-video-offset);

But it just doesn't seems to work for some reason.

Need some help in figuring out how to achieve this layout, preferably in plain CSS.

Any ideas? Thanks!

2 Answers

So, looks like I found 2 possible solutions for this:

  1. Using 2 wrappers and flex:
<div class='bg-frame'>
  <div class='video-container'>
    <video />
    ...Floating elements
  </div>
</div>
.bg-frame {
  position: absolute;
  inset: 0;
  display: flex;
  place-content: center;

  > .video-container {
    aspect-ratio: var(--video-aspect-ratio);
    flex: 0 0 auto;
    min-height: 100%;
    min-width: 100%;
    width: max(100vw, 100vh * var(--video-aspect-ratio));

    > video {
      object-fit: cover;
      height: 100%;
      width: 100%;
    }
  }
}
  1. Using 1 wrapper and position absolute:
<div class='video-container'>
  <video />
  ...Floating elements
</div>
.video-container {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);

  aspect-ratio: var(--aspect-ratio);
  min-height: 100%;
  min-width: 100%;
  width: max(100vw, 100vh * var(--aspect-ratio));

  > video {
    object-fit: cover;
    height: 100%;
    width: 100%;
  }
}

I don't really like the transform: translate(-50%, -50%) part of the second solution, but it seems to work fine in the cases I tested.

I tried to get the right formula for positioning the texts when using cover for the video.

For reasons I have been unable to explain this worked when the video height was fixed to the viewport height but not when the width was fixed.

So this snippet uses another sizing and positioning method by setting the position of the video relative to a container depending on whether the viewport aspect ratio is greater or less than the video's aspect ratio.

The text positions are set as % within the video (so you can measure these on the original video) and therefore their positions relative to the overall video do not change. Of course, texts near an edge of the video may disappear or be seen only partially if the viewport gets too narrow or too wide.

* {
  margin: 0;
}

body {
  overflow: hidden;
}

.container {
  height: 100vh;
  width: 100vw;
  overflow: hidden;
  position: absolute;
}

.inner {
  position: absolute;
  width: fit-content;
  height: fit-content;
  overflow: hidden;
}

video {
  position: relative;
  /* here put the aspect ratio of your video */
  aspect-ratio: 1920 / 1080;
  overflow: hidden;
}

.overlay {
  position: absolute;
  top: var(--t);
  left: var(--l);
  transform: translate(-50%, -50%);
  background: white;
  padding: 10px;
}


/* here put the aspect ratio of your video */

@media (min-aspect-ratio: 1920 / 1080) {
  .inner {
    position: relative;
    top: 50%;
    transform: translateY(-50%);
    width: 100vw;
  }
  video {
    width: 100vw;
    height: auto;
  }
}


/* here put the aspect ratio of your video */

@media (max-aspect-ratio: 1920 / 1080) {
  .inner {
    position: relative;
    left: 50%;
    transform: translateX(-50%);
    height: 100vh;
  }
  video {
    height: 100vh;
    width: auto;
  }
}
<div class="container">
  <div class="inner">
    <video src="https://ahweb.org.uk/easter-card.mp4" autoplay muted></video>
    <!-- --t and --l are the % top and left positions of the center of the overlaid text element -->
    <div class="overlay" style="--t: 20%; --l: 20%;">a tree</div>
    <div class="overlay" style="--t:45%; --l: 50%;">another tree</div>
    <div class="overlay" style="--t:80%; --l: 90%;">yet another tree</div>
    <div class="overlay" style="--t: 20%; --l: 80%;">the church</div>
  </div>
</div>

Unfortunately it is not possible to build in the dimensions (or aspect ratio) of the video as the media queries do not allow CSS variables to be used so there are several places where you need to put the ratio in by hand.

Related