admin管理员组

文章数量:1122796

I have a custom HTML element I made that creates a repeating background pattern which I animate in. I need the ability to dynamically set the color of this pattern with a CSS variable that lives in the parent/main document scope.

I know this is possible, but I think the complication is that I am setting the BG pattern as a CSS background image string.

customElements.define(
  'svg-background',
  class extends HTMLElement {
    connectedCallback() {
      setTimeout(() => {
        // wait till <template> is parsed as DOM
        let svg = this.querySelector('template')
          .innerHTML.replaceAll(/(\n\s*)|(\<!-- .*? --\>)/g, '') //remove linebreaks & indentations after linebreaks, and comments
          .replaceAll('"', "'") //replace double quotes
          .replaceAll('#', '%23'); //escape #
        Object.assign(this.style, {
          backgroundImage: `url("data:image/svg+xml;utf8,${svg}")`,
        });
      });
    }
  },
);

function toggleColor(){
  document.documentElement.classList.toggle('theme-blue')
}
:root{
  --hex-color: red;
}

:root.theme-blue{
  --hex-color: blue;
}

svg-background {
  position: fixed;
  bottom: 0;
  left:0;
  width: 100vw;
  height: 800px;
  transform: translateZ(0);
  pointer-events: none;
  z-index: -1;
}
<button type="button" onclick="toggleColor()">Toggle Color</button>

<svg-background>
  <template>
    <svg xmlns="" viewBox="0 0 90 800">
      <defs>
        <style>
          use {
            animation: 0.4s fade-in-hex;
            animation-fill-mode: both;
            fill: var(--app-theme-hex);
          }
          @keyframes fade-in-hex {
            from {opacity: 0;}
            to {opacity: 1;}
          }
          #hex-col use:nth-child(1) {animation-delay: 0.9s;}
          #hex-col use:nth-child(2) {animation-delay: 0.8s;}
          #hex-col use:nth-child(3) {animation-delay: 0.7s;}
          #hex-col use:nth-child(4) {animation-delay: 0.6s;}
          #hex-col use:nth-child(5) {animation-delay: 0.5s;}
          #hex-col use:nth-child(6) {animation-delay: 0.4s;}
          #hex-col use:nth-child(7) {animation-delay: 0.3s;}
          #hex-col use:nth-child(8) {animation-delay: 0.2s;}
          #hex-col use:nth-child(9) {animation-delay: 0.1s;}
        </style>
        <path id="hex" d="M0 25.980762113533157L15 0L45 0L60 25.980762113533157L45 51.96152422706631L15 51.96152422706631Z" />
      </defs>
      <!-- We repeat a pattern of 3 columns. One in the middle, and then two on either side that are cut in half so they line up when they meet -->
      <g id="hex-col">
        <use href="#hex" transform="translate(25 25) scale(.2)" />
        <use href="#hex" transform="translate(21 115) scale(.3)" />
        <use href="#hex" transform="translate(18 205) scale(.4)" />
        <use href="#hex" transform="translate(15 295) scale(.5)" />
        <use href="#hex" transform="translate(12 385) scale(.6)" />
        <use href="#hex" transform="translate(10 475) scale(.7)" />
        <use href="#hex" transform="translate(8 565) scale(.8)" />
        <use href="#hex" transform="translate(4 655) scale(.9)" />
        <use href="#hex" transform="translate(0 750)" />
      </g>
      <use href="#hex-col" transform="translate(45 -51)" />
      <use href="#hex-col" transform="translate(-45 -51)" />
    </svg>
  </template>
</svg-background>

I have a custom HTML element I made that creates a repeating background pattern which I animate in. I need the ability to dynamically set the color of this pattern with a CSS variable that lives in the parent/main document scope.

I know this is possible, but I think the complication is that I am setting the BG pattern as a CSS background image string.

customElements.define(
  'svg-background',
  class extends HTMLElement {
    connectedCallback() {
      setTimeout(() => {
        // wait till <template> is parsed as DOM
        let svg = this.querySelector('template')
          .innerHTML.replaceAll(/(\n\s*)|(\<!-- .*? --\>)/g, '') //remove linebreaks & indentations after linebreaks, and comments
          .replaceAll('"', "'") //replace double quotes
          .replaceAll('#', '%23'); //escape #
        Object.assign(this.style, {
          backgroundImage: `url("data:image/svg+xml;utf8,${svg}")`,
        });
      });
    }
  },
);

function toggleColor(){
  document.documentElement.classList.toggle('theme-blue')
}
:root{
  --hex-color: red;
}

:root.theme-blue{
  --hex-color: blue;
}

svg-background {
  position: fixed;
  bottom: 0;
  left:0;
  width: 100vw;
  height: 800px;
  transform: translateZ(0);
  pointer-events: none;
  z-index: -1;
}
<button type="button" onclick="toggleColor()">Toggle Color</button>

<svg-background>
  <template>
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 90 800">
      <defs>
        <style>
          use {
            animation: 0.4s fade-in-hex;
            animation-fill-mode: both;
            fill: var(--app-theme-hex);
          }
          @keyframes fade-in-hex {
            from {opacity: 0;}
            to {opacity: 1;}
          }
          #hex-col use:nth-child(1) {animation-delay: 0.9s;}
          #hex-col use:nth-child(2) {animation-delay: 0.8s;}
          #hex-col use:nth-child(3) {animation-delay: 0.7s;}
          #hex-col use:nth-child(4) {animation-delay: 0.6s;}
          #hex-col use:nth-child(5) {animation-delay: 0.5s;}
          #hex-col use:nth-child(6) {animation-delay: 0.4s;}
          #hex-col use:nth-child(7) {animation-delay: 0.3s;}
          #hex-col use:nth-child(8) {animation-delay: 0.2s;}
          #hex-col use:nth-child(9) {animation-delay: 0.1s;}
        </style>
        <path id="hex" d="M0 25.980762113533157L15 0L45 0L60 25.980762113533157L45 51.96152422706631L15 51.96152422706631Z" />
      </defs>
      <!-- We repeat a pattern of 3 columns. One in the middle, and then two on either side that are cut in half so they line up when they meet -->
      <g id="hex-col">
        <use href="#hex" transform="translate(25 25) scale(.2)" />
        <use href="#hex" transform="translate(21 115) scale(.3)" />
        <use href="#hex" transform="translate(18 205) scale(.4)" />
        <use href="#hex" transform="translate(15 295) scale(.5)" />
        <use href="#hex" transform="translate(12 385) scale(.6)" />
        <use href="#hex" transform="translate(10 475) scale(.7)" />
        <use href="#hex" transform="translate(8 565) scale(.8)" />
        <use href="#hex" transform="translate(4 655) scale(.9)" />
        <use href="#hex" transform="translate(0 750)" />
      </g>
      <use href="#hex-col" transform="translate(45 -51)" />
      <use href="#hex-col" transform="translate(-45 -51)" />
    </svg>
  </template>
</svg-background>

Share Improve this question asked Nov 21, 2024 at 22:17 Chris BarrChris Barr 33.9k28 gold badges102 silver badges150 bronze badges 2
  • I'm not familiar with custom html elements, but could you just give it a css class and assign the style, including the css variable, in the css class? – mykaf Commented Nov 21, 2024 at 22:21
  • 1 Maybe move everything to shadowDOM, that way you don't need the <template>, setTimeout and all replace stuff; and you can use currentColor. Maybe even generate the SVG (columns) client-side instead of a static SVG, that will make it easier to adjust spacing, scale etc. as well. – Danny '365CSI' Engelman Commented Nov 22, 2024 at 9:32
Add a comment  | 

1 Answer 1

Reset to default 2

I would use it as a mask instead and control the color using the background

customElements.define(
  'svg-background',
  class extends HTMLElement {
    connectedCallback() {
      setTimeout(() => {
        // wait till <template> is parsed as DOM
        let svg = this.querySelector('template')
          .innerHTML.replaceAll(/(\n\s*)|(\<!-- .*? --\>)/g, '') //remove linebreaks & indentations after linebreaks, and comments
          .replaceAll('"', "'") //replace double quotes
          .replaceAll('#', '%23'); //escape #
        Object.assign(this.style, {
          mask: `url("data:image/svg+xml;utf8,${svg}")`,
        });
      });
    }
  },
);

function toggleColor(){
  document.documentElement.classList.toggle('theme-blue')
}
:root{
  --hex-color: red;
}

:root.theme-blue{
  --hex-color: blue;
}

svg-background {
  position: fixed;
  bottom: 0;
  left:0;
  width: 100vw;
  height: 800px;
  transform: translateZ(0);
  pointer-events: none;
  z-index: -1;
  background: var(--hex-color)
}
<button type="button" onclick="toggleColor()">Toggle Color</button>

<svg-background>
  <template>
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 90 800">
      <defs>
        <style>
          use {
            animation: 0.4s fade-in-hex;
            animation-fill-mode: both;
            fill: #000;
          }
          @keyframes fade-in-hex {
            from {opacity: 0;}
            to {opacity: 1;}
          }
          #hex-col use:nth-child(1) {animation-delay: 0.9s;}
          #hex-col use:nth-child(2) {animation-delay: 0.8s;}
          #hex-col use:nth-child(3) {animation-delay: 0.7s;}
          #hex-col use:nth-child(4) {animation-delay: 0.6s;}
          #hex-col use:nth-child(5) {animation-delay: 0.5s;}
          #hex-col use:nth-child(6) {animation-delay: 0.4s;}
          #hex-col use:nth-child(7) {animation-delay: 0.3s;}
          #hex-col use:nth-child(8) {animation-delay: 0.2s;}
          #hex-col use:nth-child(9) {animation-delay: 0.1s;}
        </style>
        <path id="hex" d="M0 25.980762113533157L15 0L45 0L60 25.980762113533157L45 51.96152422706631L15 51.96152422706631Z" />
      </defs>
      <!-- We repeat a pattern of 3 columns. One in the middle, and then two on either side that are cut in half so they line up when they meet -->
      <g id="hex-col">
        <use href="#hex" transform="translate(25 25) scale(.2)" />
        <use href="#hex" transform="translate(21 115) scale(.3)" />
        <use href="#hex" transform="translate(18 205) scale(.4)" />
        <use href="#hex" transform="translate(15 295) scale(.5)" />
        <use href="#hex" transform="translate(12 385) scale(.6)" />
        <use href="#hex" transform="translate(10 475) scale(.7)" />
        <use href="#hex" transform="translate(8 565) scale(.8)" />
        <use href="#hex" transform="translate(4 655) scale(.9)" />
        <use href="#hex" transform="translate(0 750)" />
      </g>
      <use href="#hex-col" transform="translate(45 -51)" />
      <use href="#hex-col" transform="translate(-45 -51)" />
    </svg>
  </template>
</svg-background>

本文标签: javascriptHow to use a CSS variable inside a custom HTML elementStack Overflow