Animate block back and forth within div continuously with CSS3 keyframes
Asked Answered
S

3

7

I'm trying to animate a span that moves back and forth enclosed within a div using CSS3 keyframes. Ideally, I'd like the keyframes to look something like this:

@-webkit-keyframes backandforth {
     0% {text-align:left;} 50%{text-align:right;} 100%{text-align:left;}
}

Demo in JSFiddle

But since it's not possible to animate text-align, I've been searching for an alternative property that can be animated to reach the desired positioning. That's where I'm stuck at.

I tried setting the left property to 100% midway through the animation, but that ended up pushing the span off the div. I also tried animating the float property, but that didn't work.

Then I saw this question on moving text from left to right and tried the JSFiddle from the top answer. While it looks like the solution, it unfortunately did not work for me since I want my animation to move continuously at ease, and for the last few seconds of that animation, the span stalls.

Solatium answered 26/2, 2015 at 3:9 Comment(1)
something like so ? jsfiddle.net/dofykw02/2Addition
A
6

CSS Solution

you can play around the left position when the animation is at 50% like so :

because when you put it left: 100% it depend on the left corner of the span this is why it will go out the container div

@-webkit-keyframes backandforth {0%{left:0;} 50%{left:58%;} 100%{left:0;}}

Live Demo

I hope this fits your needs

JavaScript solution

var thisis = document.getElementById("wrapper");
var tyty = document.getElementById("move");
var witth = tyty.offsetWidth;

thisis.style.paddingRight = witth +"px";

Live Demo

with this JS whatever you change the text it will still in the container div

Addition answered 26/2, 2015 at 3:26 Comment(1)
Problem is, my program allows the span to dynamically change its width, so that wouldn't work out for all cases.Solatium
B
2

There is also a pure-CSS way to do it if you combine absolute positioning left with simultaneous transform: translate.

https://jsfiddle.net/cd7kjwy6/

* {
  box-sizing: border-box;
}
html {
  font-size: 16px;
}
.mt-2 {
  margin-top: 0.5rem;
}

/* ---------------- relevant CSS ---------------- */
.animated {
    position: relative;
    background-color: pink;
    max-width: 200px;
    overflow: hidden;
  line-height: 3rem;
    height: 3rem;
}

.animated__text {
  position: absolute;
  animation: 3s bounce ease-in-out infinite paused;
  white-space: nowrap;
  top: 0;
  padding: 0 0.5rem;
}

.animated:not(.animated--on-hover) .animated__text,
.animated.animated--on-hover:hover .animated__text {
  animation-play-state: running;
}

@keyframes bounce {
    0%, 5%, 95%, 100% {
        left: 0%;
        transform: translate(0, 0);
    }
    45%, 55% {
        left: 100%;
        transform: translate(-100%, 0);
    }
}
<div class="animated">
  <span class="animated__text">animate me!</span>
</div>
<div class="animated  mt-2">
  <span class="animated__text">Longcat is looooooooooooooooooong!</span>
</div>
<div class="animated  mt-2">
  <span class="animated__text">~</span>
</div>
<div class="animated  animated--on-hover  mt-2">
  <span class="animated__text">only on hover</span>
</div>

If you wanted to snap the "hover" variant back to the original position, you could use something like this (or JavaScript for a proper reset):

.animated.animated--on-hover:not(:hover) .animated__text {
  left: 0 !important;
  transform: translate(0, 0) !important;
}
Boeschen answered 13/9, 2020 at 12:51 Comment(0)
A
0

To infinitely animate a node back-and-forth use the alternate infinite values for the animate property which points to a @keyframes rule with only 1 keyframe, which represent the end-state (in the below case moving a div to the right-side).

Note that in the below example I intentionally did not use position but used the "new" (as of writing) container property which opens up the usage for container size units translateX(calc(100cqw - 100%))

The first div (top-most) is relative to the body element, and the second div is relative to the fieldset (its wrapper), because both the body and the fieldset has the container property applied.

body {
  container-type: size;
}

div {
 display: inline-block;
 outline: 1px solid red;
 animation: move 1s ease-in-out alternate infinite;
}

/* or inside a container */
fieldset {
  width: 50%;
  border: 2px dashed green;
  margin: 1em 0;
  padding: 0;
  container-type: inline-size;
}

@keyframes move {
  to { transform: translateX(calc(100cqw - 100%)) }
}
<div>I'm moving!</div>

<fieldset>
  <legend>Inside a container</legend>
  <div>I'm moving!</div>
</fieldset>
Allene answered 12/7, 2023 at 8:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.