map-mask

by xachary

HTML

<div id="container">
  <img id="target" src="https://cdn.pixabay.com/photo/2024/07/28/09/04/mountain-8927018_1280.jpg">
  
  <!-- svg test -->
  <!-- <div id="target" style="width:1920px;height:1080px;"></div> -->
</div>

CSS

body {
  margin: 0;
  background-color: black;
}

#container {
  position: absolute;
  width: 100%;
  height: 100%;
  background-repeat: repeat;
  display: flex;
  align-items: center;
  justify-content: center;
}

#target {
  max-width: 80%;
  max-height: 80%;
  
  -webkit-mask-mode: alpha;
  mask-mode: alpha;
  mask-repeat: no-repeat;
  mask-size: 100% 100%;
  
  /* svg test */
  
  /* background-repeat: no-repeat;
  background-size: 100% 100%; */
}

JavaScript

(function() {
  const container = document.querySelector('#container');
  const containerBg = `<svg xmlns="http://www.w3.org/2000/svg" width="30" height="30"><circle fill="rgba(255,255,255,0.1)" cx="15" cy="15" r="10" /></svg>`;
  container.style.backgroundImage = `url('data:image/svg+xml;utf8,${encodeURIComponent(containerBg)}')`;

  const target = document.querySelector('#target');

  function setTargetBg() {
    const svgWidth = target.offsetWidth,
      svgHeight = target.offsetHeight,
      padding = Math.floor(Math.min(target.offsetWidth, target.offsetHeight) * 0.2),
      fill = 'white',
      patch = 0.2;

    const targetMask = `
  <svg xmlns="http://www.w3.org/2000/svg"
    xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1"
    width="${svgWidth}"
    height="${svgHeight}" viewBox="0 0 ${svgWidth} ${svgHeight}">
    <defs>
      <linearGradient id="mask-bottom-to-top" x1="0" x2="0" y1="0" y2="1">
        <stop offset="0%" stop-color="transparent" />
        <stop offset="100%" stop-color="${fill}" />
      </linearGradient>
      <linearGradient id="mask-top-to-bottom" x1="0" x2="0" y1="0" y2="1">
        <stop offset="0%" stop-color="${fill}" />
        <stop offset="100%" stop-color="transparent" />
      </linearGradient>
      <linearGradient id="mask-rigth-to-left" x1="0" x2="1" y1="0" y2="0">
        <stop offset="0%" stop-color="transparent" />
        <stop offset="100%" stop-color="${fill}" />
      </linearGradient>
      <linearGradient id="mask-left-to-right" x1="0" x2="1" y1="0" y2="0">
        <stop offset="0%" stop-color="${fill}" />
        <stop offset="100%" stop-color="transparent" />
      </linearGradient>
    </defs>
    <path fill="url(#mask-bottom-to-top)" d="M0,0 L${svgWidth},0 L${svgWidth - padding + patch},${padding + patch} L${padding - patch},${padding + patch} Z"></path>
    <path fill="url(#mask-top-to-bottom)" d="M0,${svgHeight} L${padding - patch},${svgHeight - padding - patch} L${svgWidth - padding +...