<main>
  <article>
    <header>
      <h1>Cats</h1>
      <i>felis catus</i>
      <img src='https://assets.codepen.io/5928893/cat--resized.png' alt="cat" width="200" height="200" />
    </header>
    <div class="divider"></div>
    <p>
      Be a <a href="#" data-popoverhovertarget="nyan-cat">nyan cat</a>, feel great about it, be annoying 24/7 poop rainbows in litter box all day climb into cupboard and lick the salt off rice cakes scratch at the door then walk away
    </p>
    <p>
      Mice attack curtains love you, then bite you try to hold own back foot to clean it but foot reflexively kicks you in face, go into a rage and bite own foot, hard cat mojo hide head under blanket so no one can see. Stare at ceiling scratch leg; meow for can opener to feed me bite off human's toes but lick human with sandpaper tongue and break lamps and curl up into a ball but scratch the <a href="#" data-popoverhovertarget="postman">postman</a> wake up lick paw wake up owner meow meow, so sun bathe.
    </p>
    <p>
      Kitty loves pigs bite plants, cattt catt cattty cat being a cat purr for no reason get video posted to <a href="#" data-popoverhovertarget="internet">internet</a> for chasing red dot for eat an easter feather as if it were a bird then burp victoriously, but tender. And sometimes switches in french and say "miaou" just because well why not. Twitch tail in permanent irritation.
    </p>
  </article>
</main>
<div id="nyan-cat" class="elevation-1" popover>
  <picture>
    <source media="(prefers-reduced-motion: no-preference)" srcset="https://assets.codepen.io/5928893/nyan-cat.webp" />
    <source media="(prefers-reduced-motion: no-preference)" srcset="https://assets.codepen.io/5928893/nyan-cat.gif" />
    <img src="https://assets.codepen.io/5928893/nyan-cat.png" alt="nyan cat" width="150">
  </picture>
  <div class="popup-text">Nyan Cat</div>
</div>
<div id="postman" class="elevation-1" popover>
  <picture>
    <source media="(prefers-reduced-motion: no-preference)" srcset="https://assets.codepen.io/5928893/postman.webp" />
    <source media="(prefers-reduced-motion: no-preference)" srcset="https://assets.codepen.io/5928893/postman.gif" />
    <img src="https://assets.codepen.io/5928893/postman.png" alt="Postman Pat" width="150">
  </picture>
  <div class="popup-text">Postman</div>
</div>
<div id="internet" class="elevation-1" popover>
  <picture>
    <source media="(prefers-reduced-motion: no-preference)" srcset="https://assets.codepen.io/5928893/internet.webp" />
    <source media="(prefers-reduced-motion: no-preference)" srcset="https://assets.codepen.io/5928893/internet.gif" />
    <img src="https://assets.codepen.io/5928893/internet.png" alt="Cat using keyboard" width="150">
  </picture>
  <div class="popup-text">Internet</div>
</div>
@layer demo {
  [popover] {
    top: calc(var(--bottom) * 1px);
    background: var(--surface-2);
    margin: 0;
    border: 0;
    padding: 0;
    overflow: hidden;
    border-radius: var(--radius-2);
    transition: opacity 0.2s, transform 0.2s;
    opacity: var(--open, 0);
    box-shadow: var(--shadow-4);
    transform: translateX(calc(var(--width) * var(--offset)))
      translateY(calc((1 - var(--open, 0)) * 5%));
  }

  .popup-text {
    padding: var(--size-4);
    font-weight: var(--font-weight-6);
  }

  [popover]:open {
    --open: 1;
  }

  [popover].left {
    --offset: -0.25px;
    left: calc(var(--right) * 1px);
  }
  [popover].right {
    --offset: -0.75px;
    left: calc(var(--left) * 1px);
  }

  a {
    color: var(--indigo-4);
  }
}

@layer base {
  *,
  *:after,
  *:before {
    box-sizing: border-box;
  }

  body {
    display: grid;
    place-items: center;
    min-height: 100vh;
    overflow: auto;
    font-family: "Google Sans", sans-serif, system-ui;
  }

  :where([popover]) {
    margin: auto;
    border-width: initial;
    border-style: solid;
  }

  span {
    display: inline-block;
    translate: 0 60%;
  }

  header {
    display: grid;
    grid-template-columns: 1fr auto;
    grid-template-rows: 1fr 1fr;
    align-content: center;
    justify-content: center;
  }

  header img {
    grid-column: 2;
    grid-row: 1 / -1;
    object-fit: cover;
    height: 100%;
  }

  article > * + * {
    margin-top: var(--size-4);
  }

  h1 {
    margin: 0;
    align-self: end;
  }

  article {
    padding: var(--size-4);
    padding-bottom: var(--size-12);
  }

  .divider {
    background: var(--text-2);
  }
}
const HOVER_TRIGGERS = document.querySelectorAll("[data-popoverhovertarget]");

const SHOW = (trigger, tooltip) => () => {
  const {
    top,
    bottom,
    left,
    right,
    width,
    height
  } = trigger.getBoundingClientRect();
  tooltip.style.setProperty("--top", top);
  tooltip.style.setProperty("--right", right);
  tooltip.style.setProperty("--bottom", bottom);
  tooltip.style.setProperty("--left", left);
  tooltip.style.setProperty("--width", width);
  tooltip.style.setProperty("--height", height);

  tooltip.className = left > window.innerWidth * 0.5 ? "right" : "left";

  if (!tooltip.matches(":open")) tooltip.showPopover();
};

HOVER_TRIGGERS.forEach((TRIGGER) => {
  const POPUP = document.querySelector(
    `#${TRIGGER.getAttribute("data-popoverhovertarget")}`
  );
  const SHOW_POP = SHOW(TRIGGER, POPUP);
  TRIGGER.addEventListener("pointerenter", SHOW_POP);
  TRIGGER.addEventListener("focus", SHOW_POP);
});

const closePopUps = () =>
  document.querySelectorAll("[popover]").forEach((pop) => {
    if (pop.matches(":open")) pop.hidePopover();
  });
window.addEventListener("resize", closePopUps);

External CSS

  1. https://codepen.io/web-dot-dev/pen/XWqWYgB.css
  2. https://codepen.io/web-dot-dev/pen/ZExZWBQ.css

External JavaScript

  1. https://codepen.io/web-dot-dev/pen/XWqWYgB.js
  2. https://codepen.io/web-dot-dev/pen/ZExZWBQ.js