简体   繁体   中英

Why do css variable animations not work in web-components

I've successfully created a css variable animations, using the experimental @property feature.

IMPORTANT: this only works in Chrome, Opera or Edge compatibility table

 document.addEventListener('DOMContentLoaded', () => { const rangeInput = document.querySelector('#scale'); const htmlElement = document.querySelector('#html-element'); rangeInput.addEventListener('change', (e) => { htmlElement.style.setProperty( '--html-element-scale', (e.target.value / 100).toFixed(2) ); }); });
 @property --html-element-background-color { syntax: '<color>'; inherits: false; initial-value: #00ff00; } @property --html-element-rotate { syntax: '<angle>'; inherits: false; initial-value: 0deg; } @property --html-element-scale { syntax: '<number>'; inherits: false; initial-value: 1; } #html-element { transform: rotate(var(--html-element-rotate)) scale(var(--html-element-scale)); border: 1px solid #000; height: 100px; width: 100px; background-color: var(--html-element-background-color); animation: anim 1s ease-in infinite alternate; } @keyframes anim { 100% { --html-element-rotate: 180deg; --html-element-background-color: #ff00ff; } }
 <div id="html-element">HTML Element</div> <div id="range-container"> <input type="range" id="scale" name="scale" min="0" max="100" value="100" /> <label for="scale">Scale</label> </div>

But when wrapping it inside of a web-component, only the css values are changed, but the values of the css var's are not animated. Furthermore the rotation doesn't work, until you change the scale slider or alternatively ad a :host {--html-element-scale: 1} as default value... which is weird.

 const html = ` <style> @property --web-component-background-color { syntax: '<color>'; inherits: false; initial-value: #00ff00; } @property --web-component-rotate { syntax: '<angle>'; inherits: false; initial-value: 0deg; } @property --web-component-scale { syntax: '<number>'; inherits: false; initial-value: 1; } #web-component { transform: scale(var(--web-component-scale)) rotate(var(--web-component-rotate)); border: 1px solid #000; height: 100px; width: 100px; background-color: var(--web-component-background-color); animation: anim 1s ease-in infinite alternate; } @keyframes anim { 100% { --web-component-rotate: 180deg; --web-component-background-color: #ff00ff; } } </style> <div id="web-component">Web Component</div> <div id="range-container"> <input type="range" id="scale" name="scale" min="0" max="100" value="100" /> <label for="scale">Scale</label> </div>`; customElements.define( 'web-component', class WebComponent extends HTMLElement { shadowRoot = this.attachShadow({ mode: 'open' }); constructor() { super(); let template = document.createElement('template'); template.innerHTML = html; this.shadowRoot.appendChild(template.content.cloneNode(true)); } connectedCallback() { const rangeInput = this.shadowRoot.querySelector('#scale'); const webComponent = this.shadowRoot.querySelector('#web-component'); rangeInput.addEventListener('change', (e) => { webComponent.style.setProperty( '--web-component-scale', (e.target.value / 100).toFixed(2) ); }); } } );
 <web-component></web-component>

Last but not least, if you copy the stylesheet from the web-component into the regular dom, so that the web-component inherits the css, it works again.

The question is, is this a bug due to the experimental stage of the feature or am I doing something wrong with implementing it in a web-component?

It looks like @property definitions do not work inside of web-components. I'm not sure if this is intended or a bug, I will report it as an issue to the css-houdini project.

However, if you're interested in what a working version would look like if you only want to use globally defined css variables for animations (which is quite limited in it's use case for a web-component)

 const html = ` <style> #web-component { transform: rotate(var(--html-element-rotate)) scale(var(--html-element-scale)); border: 1px solid #000; height: 100px; width: 100px; background-color: var(--html-element-background-color); animation: anim 1s ease-in infinite alternate; } @keyframes anim { 100% { --html-element-rotate: -180deg; --html-element-background-color: #0000ff; } } </style> <div id="web-component">Web Component</div> <div id="range-container"> <input type="range" id="scale" name="scale" min="0" max="100" value="100" /> <label for="scale">Scale</label> </div>`; document.addEventListener('DOMContentLoaded', () => { const rangeInput = document.querySelector('#scale'); const htmlElement = document.querySelector('#html-element'); rangeInput.addEventListener('change', (e) => { htmlElement.style.setProperty( '--html-element-scale', (e.target.value / 100).toFixed(2) ); }); }); customElements.define( 'web-component', class WebComponent extends HTMLElement { shadowRoot = this.attachShadow({ mode: 'open' }); constructor() { super(); let template = document.createElement('template'); template.innerHTML = html; this.shadowRoot.appendChild(template.content.cloneNode(true)); } connectedCallback() { const rangeInput = this.shadowRoot.querySelector('#scale'); const webComponent = this.shadowRoot.querySelector('#web-component'); rangeInput.addEventListener('change', (e) => { webComponent.style.setProperty( '--html-element-scale', (e.target.value / 100).toFixed(2) ); }); } } );
 @property --html-element-background-color { syntax: '<color>'; inherits: false; initial-value: #00ff00; } @property --html-element-rotate { syntax: '<angle>'; inherits: false; initial-value: 0deg; } @property --html-element-scale { syntax: '<number>'; inherits: false; initial-value: 1; } #html-element { transform: rotate(var(--html-element-rotate)) scale(var(--html-element-scale)); border: 1px solid #000; height: 100px; width: 100px; background-color: var(--html-element-background-color); animation: anim 1s ease-in infinite alternate; } @keyframes anim { 100% { --html-element-rotate: 180deg; --html-element-background-color: #ff00ff; } }
 <web-component></web-component> <div id="html-element">HTML Element</div> <div id="range-container"> <input type="range" id="scale" name="scale" min="0" max="100" value="100" /> <label for="scale">Scale</label> </div>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM