[英]Achieve infinite text spinner, spinning text from bottom to top animation
I'm trying to implement an infinite from bottom to top spinning wheel.我正在尝试实现从底部到顶部的无限旋转轮。 So far I got the following:
到目前为止,我得到了以下信息:
What's working:什么工作:
What I want/what's incorrect:我想要什么/什么是不正确的:
I want the animation to be infinite, in other words, there's supposed to be no transition.我希望动画是无限的,换句话说,应该没有过渡。 When the animation reaches its last element, it must not jump back to its first, but smoothly attach it to its bottom to create a ongoing from bottom to top animation .
当动画到达它的最后一个元素时,它不能跳回它的第一个元素,而是将它平滑地附加到它的底部以创建一个从底部到顶部的持续动画。
How can I implement such behavior?我怎样才能实现这种行为? To achieve the given effect I used js - do I need some more js or fall back to plain css animation?
为了达到给定的效果,我使用了 js - 我需要更多的 js 还是回退到纯 css 动画?
class Spinner extends Component {
state = {
active: 0
};
interval;
componentDidMount() {
this.interval = setInterval(() => {
this.setState({active: this.state.active === this.props.content.length - 1 ? 0 : this.state.active + 1});
}, 1000);
}
componentWillUnmount() {
clearInterval(this.interval);
}
setPosition = () => {
const n = 100 / this.props.content.length;
return n * this.state.active * -1;
};
render() {
const style = {
transform: 'translateY(' + this.setPosition() + '%)'
};
return (
<div className="spinner--list d-inline-block align-self-start">
<ul className="p-0 m-0" style={style}>
{
this.props.content.map((item, index) => {
return (
<li key={index}>
<h1>{item}</h1>
</li>
);
})
}
</ul>
</div>
);
}
}
.spinner--list {
max-height: calc((10px + 2vw) * 1.5);
overflow: hidden;
}
.spinner--list ul {
list-style-type: none;
transition: transform 1s;
will-change: transform;
}
.spinner--container h1 {
font-size: calc(10px + 2vw);
line-height: 1.5;
margin: 0;
}
CSS solution by @keyframes
@keyframes
CSS 解决方案
body { color: black; padding: 0; margin: 0; } .text { padding: 20px 0; display: flex; position: relative; } .item-1, .item-2, .item-3 { position: absolute; padding: 20px 0; margin: 0; margin-left: 5px; animation-duration: 4s; animation-timing-function: ease-in-out; animation-iteration-count: infinite; } .item-1{ animation-name: anim-1; } .item-2{ animation-name: anim-2; } .item-3{ animation-name: anim-3; } @keyframes anim-1 { 0%, 8.3% { top: -50%; opacity: 0; } 8.3%,25% { top: 0%; opacity: 1; } 33.33%, 100% { top: 50%; opacity: 0; } } @keyframes anim-2 { 0%, 33.33% { top: -50%; opacity: 0; } 41.63%, 58.29% { top: 0%; opacity: 1; } 66.66%, 100% { top: 50%; opacity: 0; } } @keyframes anim-3 { 0%, 66.66% { top: -50%; opacity: 0; } 74.96%, 91.62% { top: 0%; opacity: 1; } 100% { top: 50%; opacity: 0; } }
<div class="text">This is a <div class="items"> <p class="item-1">test.</p> <p class="item-2">bug.</p> <p class="item-3">fail.</p> </div> </div>
Here's a solution without ul
and with automatic adjustment to a variable number of texts you want to spin.这是一个没有
ul
的解决方案,可以自动调整到您想要旋转的可变数量的文本。 The solution uses keyframes
and a little trick/illusion in CSS to create an infinite spinning animation on only two span
-s.该解决方案使用
keyframes
和 CSS 中的一个小技巧/幻觉来仅在两个span
-s 上创建无限旋转动画。 After every animation iteration , the text of each span changes using JS.每次动画迭代后,每个跨度的文本都使用 JS 更改。 The changed text depends on the
data-texts
attribute in your HTML.更改的文本取决于 HTML 中的
data-texts
属性。 In your ReactJS code, you can simply feed all the texts you want to spin inside these data-texts
attributes.在你的 ReactJS 代码中,你可以简单地在这些
data-texts
属性中输入你想要旋转的所有data-texts
。
const spinnerTexts = document.querySelectorAll('[class^="spinner__text--"]') const texts = spinnerTexts[0].dataset.texts.split(',') const textPositions = [0, 1] function initializeSpinnerTexts() { spinnerTexts.forEach((spinnerText, index) => { // Initialize the spinner texts' text spinnerText.innerText = texts[textPositions[index]] // Change text after every animation iteration spinnerText.addEventListener('animationiteration', e => { e.target.innerText = texts[++textPositions[index] % texts.length] }) }) } window.onload = initializeSpinnerTexts
* { margin: 0; padding: 0; } .spinner { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); overflow: hidden; } .spinner__text { position: relative; display: inline-block; /* width has to be set to be >= largest spinning text width */ width: 50px; } .spinner__text--top, .spinner__text--bottom { display: inline-block; animation: 1s ease 1.05s infinite running none; } .spinner__text--top { animation-name: spinTop; } /* Bottom text spinner has to be configured so that it is positioned right at the same position as the top one */ .spinner__text--bottom { position: absolute; top: 0; left: 0; opacity: 0; animation-name: spinBottom; } @keyframes spinTop { from { transform: translateY(0%); } to { transform: translateY(-100%); } } @keyframes spinBottom { from { opacity: 1; transform: translateY(100%); } to { opacity: 1; transform: translateY(0%); } }
<div class="spinner"> This is a <!-- Uses two spans to create an illusion of infinite spinning --> <div class="spinner__text"> <span class="spinner__text--top" data-texts="test., bug., fail."></span> <span class="spinner__text--bottom" data-texts="text., bug., fail."></span> </div> </div>
You can't add a delay between each animation iteration using keyframes
directly.您不能直接使用
keyframes
在每次动画迭代之间添加延迟。 However, you can adjust the values of the keyframes
and the value of animation-duration
such that it looks like there's a delay in between each iteration;但是,您可以调整
keyframes
的值和animation-duration
的值,使每次迭代之间看起来都有延迟; in actuality, you're making it so that nothing is happening during the end of each animation.实际上,您正在制作它,以便在每个动画结束时都不会发生任何事情。 Here's an example below (it's similar to the above one, but with slight adjustments to
animation-duration
and keyframes
.下面是一个示例(它类似于上面的示例,但对
animation-duration
和keyframes
稍作调整。
const spinnerTexts = document.querySelectorAll('[class^="spinner__text--"]') const texts = spinnerTexts[0].dataset.texts.split(',') const textPositions = [0, 1] function initializeSpinnerTexts() { spinnerTexts.forEach((spinnerText, index) => { // Initialize the spinner texts' text spinnerText.innerText = texts[textPositions[index]] // Change text after every animation iteration spinnerText.addEventListener('animationiteration', e => { e.target.innerText = texts[++textPositions[index] % texts.length] }) }) } window.onload = initializeSpinnerTexts
* { margin: 0; padding: 0; } .spinner { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); overflow: hidden; } .spinner__text { position: relative; display: inline-block; width: 50px; } .spinner__text--top, .spinner__text--bottom { display: inline-block; /* Changed animation duration */ animation: 5s ease 2s infinite running none; } .spinner__text--top { animation-name: spinTop; } .spinner__text--bottom { position: absolute; top: 0; left: 0; opacity: 0; animation-name: spinBottom; } @keyframes spinTop { 0% { transform: translateY(0%); } /* Spin finishes after 20% of animation duration (1s) */ 20% { transform: translateY(-100%); } /* Nothing from 20% until 100% of animation duration (4s) */ /* This makes it looks like there's a delay between each animation */ 100% { transform: translateY(-100%); } } @keyframes spinBottom { /* Similar to spinTop's logic */ 0% { opacity: 1; transform: translateY(100%); } 20% { opacity: 1; transform: translateY(0%); } 100% { opacity: 1; transform: translateY(0%); } }
<div class="spinner"> This is a <!-- Uses two spans to create an illusion of infinite spinning --> <div class="spinner__text"> <span class="spinner__text--top" data-texts="test., bug., fail."></span> <span class="spinner__text--bottom" data-texts="text., bug., fail."></span> </div> </div>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.