<div class="metallicss">ほげほげ</div>
.metallicss {
  --convexity: 50%;
  border-radius: 64px;
  background: #c0c0c0;
  padding: 1em;
  --seed: 12;
  font-size: 3em;
  --metal: gold;
  width: 50%;
  text-align: center;
}
const base = [
    tag("rect", {
      props: {
        fill: "url(#gradient)",
        height: 1024,
        width: 1024,
        x: 0,
        y: 0
      }
    }),
    tag("rect", {
      props: {
        filter: "url(#texture)",
        height: 1024,
        style: "mix-blend-mode: luminosity; opacity: 0.5",
        width: 1024,
        x: 0,
        y: 0
      }
    }),
    tag("rect", {
      props: {
        filter: "url(#texture)",
        height: 1024,
        style: "mix-blend-mode: screen; opacity: 0.25",
        width: 1024,
        x: 0,
        y: 0
      }
    })
  ],
  defs = tag("defs", {
    inner: [
      tag("linearGradient", {
        inner: [
          tag("stop", { props: { offset: "35%", ["stop-color"]: "#b0b0b0" } }),
          tag("stop", { props: { offset: "40%", ["stop-color"]: "#efefef" } }),
          tag("stop", { props: { offset: "45%", ["stop-color"]: "#909090" } }),
          tag("stop", { props: { offset: "49%", ["stop-color"]: "#707070" } }),
          tag("stop", { props: { offset: "51%", ["stop-color"]: "#303030" } }),
          tag("stop", { props: { offset: "60%", ["stop-color"]: "#909090" } }),
          tag("stop", { props: { offset: "70%", ["stop-color"]: "#505050" } }),
          tag("stop", { props: { offset: "100%", ["stop-color"]: "#505050" } })
        ],
        props: { id: "gradient", x1: 0, x2: 0, y1: 0, y2: 1 }
      })
    ]
  }),
  serializer = new XMLSerializer(),
  xmlns = "http://www.w3.org/2000/svg";
let blocked = document.body.className.indexOf("block-metallicss") !== -1;

function tag(name, { inner, props }) {
  const elem = document.createElementNS("http://www.w3.org/2000/svg", name);

  props && Object.entries(props).forEach((prop) => elem.setAttribute(...prop));
  inner?.forEach((innerElem) => elem.append(innerElem));

  return elem;
}

function sheen({ offset, radii: { x: rx, y: ry }, stroke, vertical, x, y }) {
  const margin = offset / (vertical ? x : y) / 2,
    size = offset / 3 / (vertical ? x : y),
    diff = 1024 - margin * 2 + size * 2;

  return tag("rect", {
    props: {
      "stroke-width": size,
      fill: "none",
      height: vertical ? 1024 + size : diff,
      rx,
      ry,
      stroke,
      width: vertical ? diff : 1024 + size,
      x: vertical ? margin - size : -size / 2,
      y: vertical ? -size / 2 : margin - size
    }
  });
}

export const unblock = () => {
    blocked = false;
  },
  metallicss = (elem) => {
    const { offsetWidth: width, offsetHeight: height } = elem,
      { backgroundColor: background, borderRadius } = getComputedStyle(elem),
      depthValue = getComputedStyle(elem).getPropertyValue("--convexity"),
      seed = getComputedStyle(elem).getPropertyValue("--seed") || 23,
      metal = getComputedStyle(elem).getPropertyValue("--metal").replace(/ /g, ""),
      rawDepth =
        depthValue === "0%" || depthValue === " 0%"
          ? 0
          : (depthValue && parseInt(depthValue)) || 20,
      lustre = `filter: ${
        {
          copper: "brightness(0.85) sepia(0.5) saturate(2) hue-rotate(-33.75deg)",
          gold: "brightness(0.95) sepia(1) saturate(1.5)",
          iron: "",
          silver: "brightness(1.125)"
        }[metal || "iron"]
      }`,
      depth = rawDepth * ((height > width ? width : height) / 640),
      absDepth = Math.abs(depth),
      x = width / (64 * (absDepth / 10 + 1)),
      y = height / (64 * (absDepth / 10 + 1)),
      radius = parseInt(borderRadius),
      radii = {
        x: height / 2 < radius ? 512 * (y / x) : radius * (1024 / width),
        y: width / 2 < radius ? 512 * (x / y) : radius * (1024 / height)
      },
      inverse = depth < 0,
      fill = background === "rgba(0, 0, 0, 0)" ? "gray" : background;

    elem.style.backgroundImage = `url('data:image/svg+xml;utf8,${encodeURIComponent(
      serializer.serializeToString(
        tag("svg", {
          inner: [
            tag("filter", {
              inner: [
                tag("feImage", {
                  props: {
                    preserveAspectRatio: "none",
                    height: 1024,
                    width: 1024,
                    href: `data:image/svg+xml;utf8,${encodeURIComponent(
                      serializer.serializeToString(
                        tag("svg", {
                          props: { height: 2048, width: 2048, xmlns },
                          inner: [
                            tag("rect", {
                              props: {
                                fill: "white",
                                height: 2048,
                                width: 2048
                              }
                            }),
                            tag("g", {
                              inner: Array.from({ length: 24 })
                                .map((_, index) =>
                                  sheen({
                                    offset: Math.pow(
                                      3,
                                      index % 2 === 0 ? index / 4 : (index - 1) / 4
                                    ),
                                    radii,
                                    stroke: Math.ceil(index / 2) % 2 === 0 ? "red" : "white",
                                    vertical: index % 2 === 0,
                                    x,
                                    y
                                  })
                                )
                                .reverse(),
                              props: { transform: "translate(512,512)" }
                            })
                          ]
                        })
                      )
                    )}`,
                    result: "image"
                  }
                }),
                tag("feGaussianBlur", {
                  props: {
                    ["color-interpolation-filters"]: "sRGB",
                    in: "image",
                    result: "blur",
                    stdDeviation: `${4 * (y / x)},${6 * (x / y)}`
                  }
                }),
                tag("feDisplacementMap", {
                  props: {
                    ["color-interpolation-filters"]: "sRGB",
                    in: "SourceGraphic",
                    in2: "blur",
                    result: "displacement",
                    scale: 50 + Math.abs(rawDepth) > 100 ? 100 : 50 + Math.abs(rawDepth),
                    xChannelSelector: "R",
                    yChannelSelector: "G"
                  }
                })
              ],
              props: {
                filterUnits: "userSpaceOnUse",
                height: 2048,
                id: "noise",
                width: 2048,
                x: 0,
                y: 0
              }
            }),
            tag("filter", {
              inner: [
                tag("feTurbulence", {
                  props: {
                    ["color-interpolation-filters"]: "sRGB",
                    baseFrequency: 0.005,
                    result: "turbulence",
                    seed,
                    type: "fractalNoise"
                  }
                }),
                tag("feDisplacementMap", {
                  props: {
                    ["color-interpolation-filters"]: "sRGB",
                    in2: "turbulence"
                  }
                })
              ],
              props: {
                filterUnits: "userSpaceOnUse",
                height: 1024,
                id: "texture",
                width: 1024,
                x: 0,
                y: 0
              }
            }),
            defs,
            tag("g", { inner: base, props: { filter: "url(#noise)" } }),
            inverse &&
              tag("rect", {
                props: {
                  fill: "#20222480",
                  height: 1024,
                  opacity: `${rawDepth > -25 ? 25 : rawDepth * -1}%`,
                  width: 1024,
                  x: 0,
                  y: 0
                }
              }),
            tag("rect", {
              props: {
                fill,
                height: 1024,
                opacity: 0.5,
                style: "mix-blend-mode: overlay",
                width: 1024,
                x: 0,
                y: 0
              }
            })
          ],
          props: {
            preserveAspectRatio: "none",
            style: `transform: scale(1, ${inverse ? "-" : ""}1); ${lustre}`,
            viewBox: "256 256 512 512",
            xmlns
          }
        })
      )
    )}')`;
    elem.style.backgroundSize = "100% 100%";
    elem.style.border = "none";
    elem.style.boxShadow = `inset #ffffff80 0px ${
      inverse ? "-" : ""
    }4px 8px, inset ${
      {
        copper: "#402020",
        gold: "#604000",
        iron: "#202020",
        silver: "#404040"
      }[metal || "iron"]
    }${inverse ? "" : "c0"} 0px ${inverse ? "" : "-"}8px 16px ${
      inverse ? "" : ", #00000030 1px 2px 2px, #00000020 2px 4px 4px"
    }`;
    elem.style.color = `#${
      inverse
        ? `${
            {
              copper: "100000",
              gold: "302000",
              iron: "000000",
              silver: "101010"
            }[metal || "iron"]
          }c0`
        : "ffffffe0"
    }`;
    elem.style.textRendering = "geometricPrecision";
    elem.style.textShadow = inverse
      ? "white .5px .5px 1px"
      : "black -.5px -.5px 1px";
    elem.style.transform = "translateZ(0)";
    elem.style.transition = "none";
  },
  traverse = () =>
    !blocked &&
    Array.from(document.querySelectorAll(".metallicss"))
      .filter(
        (elem) =>
          window.getComputedStyle(elem).getPropertyValue("display") != "none"
      )
      .forEach(metallicss);

if (document.readyState !== "loading") traverse();
else document.addEventListener("DOMContentLoaded", traverse);

export default metallicss;

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.