prosource

'@-Keyframe' CSS 애니메이션을 동적으로 만드는 방법은?

probook 2023. 9. 15. 21:07
반응형

'@-Keyframe' CSS 애니메이션을 동적으로 만드는 방법은?

디브를 회전하고 특정 위치에서 정지해야 하는 요구사항이 있습니다(값은 서버에서 받을 것입니다).

네이티브 JS를 회전하고 정지하려고 했는데 CPU를 크게 소모하고 있습니다.

CSS 애니메이션으로 회전할 수는 있지만 애니메이션을 멈출 위치를 동적으로 설명하는 클래스를 만들어야 합니다.뭐 이런 거.

@-webkit-keyframes spinIt {
    100% {
        -webkit-transform: rotate(A_DYNAMIC_VALUE);
    }
}
@-moz-keyframes spinIt {
    100% {
        -webkit-transform: rotate(A_DYNAMIC_VALUE);
    }
}

여기 한가지 참고 사항이 있습니다.

http://jsfiddle.net/bVkwH/8/

스타일시트 규칙을 동적으로 삽입하여 헤드의 이전 스타일을 재정의할 수 있습니다.이렇게 하면 단일 작업에 대해 라이브러리를 추가하지 않을 수 있습니다.

var style = document.createElement('style');
style.type = 'text/css';
var keyFrames = '\
@-webkit-keyframes spinIt {\
    100% {\
        -webkit-transform: rotate(A_DYNAMIC_VALUE);\
    }\
}\
@-moz-keyframes spinIt {\
    100% {\
        -webkit-transform: rotate(A_DYNAMIC_VALUE);\
    }\
}';
style.innerHTML = keyFrames.replace(/A_DYNAMIC_VALUE/g, "180deg");
document.getElementsByTagName('head')[0].appendChild(style);

동적을 생성하는 것은 쉽지 않다고 생각합니다. 왜냐하면 그것들은 하드 코딩이 되어야 하기 때문입니다.

전환은 자바스크립트가 수행하는 CSS 변경에 우아하게 대응할 수 있기 때문에 작업하기가 조금 더 쉽습니다.

그러나 CSS 전환이 제공할 수 있는 복잡성은 상당히 제한적입니다. 여러 단계로 구성된 애니메이션은 달성하기가 어렵습니다.

이것은 CSS @keyframe 애니메이션이 해결해야 할 문제이지만 전환과 같은 수준의 동적 응답성을 제공하지는 못합니다.

하지만 이 링크들은 당신에게 도움이 될지도 모릅니다.

Link1 : 많은 작은 단계를 가진 @-webkit-keyframe 애니메이션을 생성하는 도구이것은 완화 공식을 무제한으로 선택할 수 있는 문을 열어줍니다.

링크2는 애니메이션을 만들 수 있는 UI를 제공하고 CSS 코드로 내보내기 때문에 기본으로 가져가시는 것이 큰 도움이 될 것입니다.

그런 것 같다. 이것. 해결책은 분명 당신에게 도움이 될 것입니다.동적 키프레임에 사용됩니다.

이에 대한 업데이트된 (2019) 답변을 공유하겠습니다.

네, CSS Variables(모든 최신 브라우저에서 지원)를 사용하여 자바스크립트 없이 가능합니다.

--lightScaleStart: 0.8;

.light {
    animation: grow 2s alternate infinite ease-in-out;
}

.light.yellow {
    --lightScaleEnd: 1.1;
}

.light.red {
    --lightScaleEnd: 1.2;
}

@keyframes grow {
  from {
    transform: scale(var(--lightScaleStart));
  }
  to {
    transform: scale(var(--lightScaleEnd));
  }
}

CSS 변수가 있는 Codepen Dynamic CSS 애니메이션 데모 참조

편집: 여기 그것에 대한 CSS 트릭 기사도 있습니다.

Alex Grande의 답변은 몇 개의 키프레임에 아주 적합합니다.하지만 키프레임을 계속 동적으로 추가하고 싶다고 하면 웹 페이지가 정말 빨리 지연됩니다.이 문제를 해결하려면 새 DOM 요소 생성을 중지하기만 하면 됩니다.대신, 1개의 새로운 DOM 스타일시트를 생성하고, 그것을 사용하여 다시 사용합니다.insertRule프레임마다 더 키프레임을 더 되지 않는 . 애니메이션 프레임마다 새로운 키프레임을 생성하는 경우와 같이 더 많은 키프레임을 원하는 경우에는 더 이상 사용되지 않는 이전 키프레임을 삭제하는 시스템을 설정해야 합니다.이것은 어떻게 이와 같은 것을 성취할 수 있는지에 대한 좋은 시작입니다.

var myReuseableStylesheet = document.createElement('style'),
    addKeyFrames = null;
document.head.appendChild( myReuseableStylesheet );
if (CSS && CSS.supports && CSS.supports('animation: name')){
    // we can safely assume that the browser supports unprefixed version.
    addKeyFrames = function(name, frames){
        var pos = myReuseableStylesheet.length;
        myReuseableStylesheet.insertRule(
            "@keyframes " + name + "{" + frames + "}", pos);
    }
} else {
    addKeyFrames = function(name, frames){
        // Ugly and terrible, but users with this terrible of a browser
        // *cough* IE *cough* don't deserve a fast site
        var str = name + "{" + frames + "}",
            pos = myReuseableStylesheet.length;
        myReuseableStylesheet.insertRule("@-webkit-keyframes " + str, pos);
        myReuseableStylesheet.insertRule("@keyframes " + str, pos+1);
    }
}

사용 예시:

addKeyFrames(
    'fadeAnimation',
    '0%{opacity:0}' + 
    '100%{opacity:1}'
);

그리고 알렉스 그란데, 나는 꽤 확신해요document.getElementsByTagName('head')[0]그리고.type = 'text/css' 이후로가 없었습니다.@keyframesIE10까지는 지원되지 않습니다.그냥...

이것은 이제 다음과 같은 새로운 Web Animations API로 쉽게 달성할 수 있습니다.

const anim = document.getElementById("foo").animate(
  [
    { transform: `rotate(${A_DYNAMIC_VALUE})` }
  ],
  { duration: 3000, iterations: Infinity }
);

// and later
anim.pause();

의 첫 번째 입니다..animate는 키프레임 목록을 가져오고 두 번째는 애니메이션 옵션(예: 지속 시간, 반복 횟수 등)을 가져옵니다.

CSSKeyframeRule에서 스타일을 변경할 수 있으며, 아래 코드와 같이 Chrome에서도 잘 작동합니다.도움이 되기를 바랍니다:)

<html>

<head>
	<style>
		#text {
			display: inline-block;
		}
	</style>
</head>

<body>
	<div id="text">TEXT</div>
	<script>
	
		// Dynamically create a keyframe animation
		document.styleSheets[0].insertRule('\
			@keyframes anim {\
				from { transform: rotateZ(0deg);   }\
				to   { transform: rotateZ(360deg); }\
			}'
		);
		var div = document.getElementById('text');
		div.style.animation = 'anim 1s linear forwards';
		
		// This function will change the anim
		function stopAtSomeDeg(d) {
			var ss = document.styleSheets[0];
			var anim;
			for (var i in ss.cssRules) {
				// Find your animation by name
				if (ss.cssRules[i].name === 'anim') {
					anim = ss.cssRules[i];
					break;
				}
			}
			var stopFrame = anim.cssRules[1]; // This indicates the second line of "anim" above.
			
			// Change any attributes
			stopFrame.style.transform = 'rotateZ(' + d + 'deg)';
		}
		
		stopAtSomeDeg(180);
	</script>
</body>
</html>

CSS 변수의 경우:당신은 의사를 사용할 수 있습니다.:root요소의 css 규칙 내에서 cs 변수를 선언한 다음, 자바스크립트를 사용하여 해당 변수를 조작합니다.

:root {--variable-name:property;}은로의다본다efht의 루트 요소입니다.<html> 다음 다음 다음과 함께 변수합니다. 그런 다음 JS를 사용하여 CSS 루트 변수/s의 값을 다음과 같이 변경합니다.

element.style.setProperty('--variable-name','value') 변수를 합니다. 된 된 --variable-name이름으로 새 값을 할당합니다. 너의 @keyframes 규칙,이름을 css칙과이트수다을다을칙수s:ee,과s,dfrom: { top: var(--top-position)}, 오프셋 규칙 내의 속성에 적용할 수 있습니다.예:

:root {
  --top-position-start: 0px;
  --left-position-start: 0px;
  --top-position-end: 200px;
  --left-position-end: 200px;
}

.element {
  top: var(--top-position-start);
  left: var(--left-position-start);
  animation: movePos 1s ease-in;
}

@keyframes movePos {
  from: {
    top: var(--top-position-start);
    left: var(--left-position-start);
  } 
  to: {
    top: var(--top-position-end);
    left: var(--left-position-end);
  }
}

그렇다면 JS는 다음과 같은 것을 원합니다.

let ran = getRandomInt(99);
let skew = ran + getRandomInt(10);
root.style.setProperty('--top-position-end', `${ran}vw`);
root.style.setProperty('--left-position-end', `${skew}vw`);

루트 요소에 CSS 변수를 사용하면 @keyframes 이벤트에 전달할 수 있습니다.

하여 된 를 로 하여 를 하십시오 를 하십시오 를 하여 하여 된 로 를 를 left그리고 html:root 스타일을 사용하여 CSS 내의 @keyframes로 전달했습니다.

let root = document.documentElement;
let rain = document.querySelectorAll('.drop');

function getMaxInt(max) {
  return Math.floor(Math.random() * Math.floor(max));
}

function getMinMaxInt(min, max) {
  return Math.random() * (max - min) + min;
}
// set an interval to drop the div from randomly positioned view widths on the screen
setInterval(() => {
  let ran = getMaxInt(86);
  let skew = ran + getMaxInt(10);
  let circle = `${getMinMaxInt(3,15)}px`;
  root.style.setProperty('--keyframeLeftStart', `${ran}vw`);
  root.style.setProperty('--keyframeLeftEnd', `${skew}vw`);  
  root.style.setProperty('--animationDuration', `${ getMaxInt(2500)}ms`); 
  root.style.setProperty('--width', circle);
  root.style.setProperty('--height', circle);
  root.style.setProperty('--red', getMinMaxInt(100, 255));
  root.style.setProperty('--green', getMinMaxInt(100, 255));
  root.style.setProperty('--blue', getMinMaxInt(100, 255));
}, getMaxInt(3500))
* {
  padding: 0;
  margin: 0;
  box-sizing: border-box;
}

/* here we define some css variables for the document :root 
   essentially, these will be the first iteration of the elements style
   then JS will take voer and set the values from script */
:root {
  --keyframeTop: 0;
  --keyframeBottom: 98vh;
  --keyframeLeftStart: 2vw;
  --keyframeLeftEnd: 10vw;
  --animationDuration: 1s;
  --width: 5px;
  --height: 5px;
  --red: 100;
  --green: 100;
  --blue: 100;
}

body {
  width: 100vw;
  height: 100vh;
  background-color: #000;
}

#main {
  width: calc(100vw - var(--width));
  height: calc(100vh - var(--height));
  display: flex;
  justify-content: center;
  align-items: center;
  color: #fff;
}

.drop {
  width: var(--width);
  height: var(--height);
  border-radius: 50%;
  position: absolute;
  animation: dropping var(--animationDuration) ease-in infinite;
  top: var(--keyframeTop);
  left: var(--keyframeLeftStart);
  background-color: rgb(var(--red),var(--green), var(--blue));
}

@keyframes dropping {
  0% {
    top: var(--keyframeTop);
    left: var(--keyframeLeftStart);
    background-color: rgb(var(--red),var(--green), var(--blue));
  }
  50% {
    background-color: rgb(var(--green),var(--blue), var(--red));
  }
  100% {
    top: var(--keyframeBottom);
    left: var(--keyframeLeftEnd);
    background-color: rgb(var(--blue),var(--red), var(--green));
  }
}
<div id="main">
    <div class="drop"></div>
</div>

자바스크립트에서는 document.styleSheets로 스타일시트에 접근할 수 있습니다.모든 시트에는 규칙 및/또는 CSSRule 목록(브라우저에 따라 다름)과 CSSTyleSheet.insertRule() 메서드가 있습니다.

이 메서드를 사용하면 새 키프레임 원시를 문자열로 추가할 수 있습니다.

자바스크립트

function insertStyleSheetRule(ruleText)
{
    let sheets = document.styleSheets;

    if(sheets.length == 0)
    {
        let style = document.createElement('style');
        style.appendChild(document.createTextNode(""));
        document.head.appendChild(style);
    }

    let sheet = sheets[sheets.length - 1];
    sheet.insertRule(ruleText, sheet.rules ? sheet.rules.length : sheet.cssRules.length);
}

document.addEventListener("DOMContentLoaded", event =>
{
    insertStyleSheetRule("@keyframes spinIt { 0% { transform: rotate(-20deg); } 100% { transform: rotate(20deg); } }");

    insertStyleSheetRule("#box { " + 
        "animation: spinIt 1s infinite alternate cubic-bezier(0.5,0,0.5,1); " + 
        "width: 64px; height: 64px; background-color: red; border: 4px solid black; " + 
    "}");
});

html

<div id="box"></div>

데모: https://jsfiddle.net/axd7nteu/

원하는 애니메이션이 포함된 새 스타일시트를 만들 수 있습니다.예:

function addAnimation(keyframe){
     var ss=document.createElement('style');
     ss.innerText=keyframe;
     document.head.appendChild(ss);
}

이렇게 하면 애니메이션과 함께 새 스타일시트가 만들어집니다.
이 방법은 Chrome에서만 테스트 된 방법입니다.

자바스크립트로 한 통화에서 @keyframe을 설정하고 append(), Object.assign(), template 문자열사용하여 사용합니다.

document.body.append(
  Object.assign(document.createElement("style"), {
    textContent: `@keyframes coolrotate { from { transform: scale(1, 1) translate(-0.1em, 0)} to { transform: scale(-1, 1) translate(0, 0) }} small { display: inline-block; font-size:2.3em; animation: 1s infinite alternate coolrotate } body {font-size: x-large}`
  }),
  Object.assign(document.createElement("span"), {
    innerHTML: `<span>c</span><small>o</small><span>o</span><small>L</small><small>...</small>`,
    style: "font-weight: 1000; font-size: 3.3em;"
  })  
)

user7892745는 나를 위해 작동하지 않아 약간의 조정이 필요합니다.

1° "pos"는 무엇이 되어야 하는지 이해할 수 없지만 콘솔 로그에 "정의되지 않음"이라고 표시되어 ", pos"를 제거했습니다.

2° "myReuseableStylesheet.insertRule" 오류 "not function"을 사용하여 "inner"를 사용했습니다."InsertRule" 대신 HTML"

3° 마침내 "document.head.append Child(내 재사용 가능 스타일시트)"를 끝에 이동했습니다.

하지만 이 후에는 잘 작동하고 내가 찾고 있는 것과 정확합니다. 감사합니다 사용자 7892745 :D

내가 가지고 있던 문제일 수도 있어요, 내가 그것을 사용하는 방식으로 오세요.

이것은 내가 그것과 함께 사용했던 대본입니다.

var getclass = document.getElementsByClassName("cls");
var countclass = getclass.length;
for (var i=0; i <countclass; i++ ){
    getclass[i].addEventListener('mouseover', function(){
        // get the data-name value to show element whose id are the same
        var x=  this.getAttribute("data-name"); 
        var y =document.getElementById(x);
            y.style.display="block";
            // because the element to show have fixed width, but different text length, they have different height
            // so I need to get the highness, then use the value of height to define the 100% value of animation
            // or the longer ones will be cutted an the shorten have a lot of empty space a the end
        var yHeig= Math.round(parseInt(getComputedStyle(y).getPropertyValue('height')));
            yHeig_ = yHeig - 10; // to shorten a bit the time from end and new passage
        console.log(yHeig+" - "+ yHeig_);
        addKeyFrames(
                'showMe',
                '0%{top:35px;}' + 
                '100%{top:-'+ yHeig_ +'px;}'
            );
        y.style.animation="showMe 7s linear infinite";

    },false);

    getclass[i].addEventListener('mouseout', function(){
        var x=  this.getAttribute("data-name");
        document.getElementById(x).style.display="none";
    },false);
}

html marquee coold가 같은 일을 하기에는 쉬워 보이지만 잘 작동하지 않는다는 것을 알고 있습니다.

를 생성할 수 있습니다.<style>요소, 당신이 원하는 CSS에 그것의 내용을 설정하라, 이 경우, 당신의 애니메이션의 선언과 그것을 에 추가하라.<head>그 페이지의

또한 다른 사람들이 제안한 것처럼 여러 가지 애니메이션을 만들어야 한다면 한 개의 애니메이션을 재사용하는 것이 더 나을 것입니다.<style>태그를 여러 개 생성하지 않고 를 사용하여 새 스타일을 추가합니다.

마지막으로 ES6의 템플릿 리터럴/스트링을 사용할 수 있다면 코드가 훨씬 깨끗해 보일 것입니다.

let dynamicStyles = null;

function addAnimation(body) {
  if (!dynamicStyles) {
    dynamicStyles = document.createElement('style');
    dynamicStyles.type = 'text/css';
    document.head.appendChild(dynamicStyles);
  }
  
  dynamicStyles.sheet.insertRule(body, dynamicStyles.length);
}

addAnimation(`
  @keyframes myAnimation { 
    0% { transform: rotate(0); }
    20% { transform: rotate(${ 360 * Math.random() }deg); }
    60% { transform: rotate(${ -360 * Math.random() }deg); }
    90% { transform: rotate(${ 360 * Math.random() }deg); }
    100% { transform: rotate(${ 0 }deg); }
  }
`);

document.getElementById("circle").style.animation = 'myAnimation 3s infinite';
html,
body {
  height: 100vh;
}

body {
  display: flex;
  justify-content: center;
  align-items: center;
  margin: 0;
}

#circle {
  width: 100px;
  height: 100px;
  box-shadow:
    0 0 48px -4px rgba(0, 0, 0, .25),
    0 0 0 4px rgba(0, 0, 0, .02);
  border-radius: 100%;
  position: relative;
  overflow: hidden;
}

#circle::before {
  content: '';
  position: absolute;
  top: 0;
  left: 50%;
  transform: translate(-2px);
  border-left: 4px solid #FFF;
  height: 24px;
  box-shadow: 0 -4px 12px rgba(0, 0, 0, .25);
}
<div id="circle"></div>

아니면 더 좋음:

let dynamicStyles = null;

function addAnimation(name, body) {
  if (!dynamicStyles) {
    dynamicStyles = document.createElement('style');
    dynamicStyles.type = 'text/css';
    document.head.appendChild(dynamicStyles);
  }
  
  dynamicStyles.sheet.insertRule(`@keyframes ${ name } {
    ${ body }
  }`, dynamicStyles.length);
}

addAnimation('myAnimation', `
  0% { transform: rotate(0); }
  20% { transform: rotate(${ 360 * Math.random() }deg); }
  60% { transform: rotate(${ -360 * Math.random() }deg); }
  90% { transform: rotate(${ 360 * Math.random() }deg); }
  100% { transform: rotate(${ 0 }deg); }
`);

document.getElementById("circle").style.animation = 'myAnimation 3s infinite';
html,
body {
  height: 100vh;
}

body {
  display: flex;
  justify-content: center;
  align-items: center;
  margin: 0;
}

#circle {
  width: 100px;
  height: 100px;
  box-shadow:
    0 0 48px -4px rgba(0, 0, 0, .25),
    0 0 0 4px rgba(0, 0, 0, .02);
  border-radius: 100%;
  position: relative;
  overflow: hidden;
}

#circle::before {
  content: '';
  position: absolute;
  top: 0;
  left: 50%;
  transform: translate(-2px);
  border-left: 4px solid #FFF;
  height: 24px;
  box-shadow: 0 -4px 12px rgba(0, 0, 0, .25);
}
<div id="circle"></div>

CSS data URI를 이용하여 자바스크립트로 간단한 아이디어를 찾았습니다.

해결책

function addNewCSS(css_text) {
  css_text = encodeURIComponent(css_text);
  const url = `data:text/css,${css_text}`;
  const link = document.createElement("link");
  link.rel = "stylesheet";
  link.href = url;
  document.head.appendChild(link);
}

기능은 CSS 코드를 텍스트로 받아들이고 스타일로 추가합니다.

일해

CSS 텍스트를 URI 인코딩 형식으로 변환합니다(데이터 URL로 전달).그런 다음 href를 URL로 하고 관계를 "stylesheet"로 하는 링크 태그를 생성합니다(여기서 rel 속성은 필수이며 추가되지 않으면 작동하지 않습니다). 마지막으로 링크 태그를 헤드 태그에 추가합니다.

function addNewCSS(css_text) {
  css_text = encodeURIComponent(css_text);
  const url = `data:text/css,${css_text}`;
  const link = document.createElement("link");
  link.rel = "stylesheet";
  link.href = url;
  document.head.appendChild(link);
}

const duration = 1;
const colour = ["#2196F3", "#E91E63"];
const css_data = `
  @keyframes change{
    0% {
      background: ${colour[0]};
    }
    100% {
      background: ${colour[1]};
    }
  }
  body {
    animation: change ${duration}s linear infinite alternate;
  }
`;

addNewCSS(css_data);
<html>
  <head></head>
  <body>
    <h1>Wait to see JS adding background color animation</h1>
  </body>
</html>

결론

저는 모든 브라우저에서 테스트하지는 않았지만 크롬에서 작동하며, 헤드 태그 끝에 추가됨에 따라 헤드 태그의 다른 태그보다 우선 순위를 얻습니다. 값을 자주 변경할 계획이라면 새 태그를 추가하는 대신 편집을 시도하십시오.href이전에 추가된 태그의.

언급URL : https://stackoverflow.com/questions/18481550/how-to-dynamically-create-keyframe-css-animations

반응형