I have created a simple animated wavy line to use as a divider on one of my websites. Looks perfect in safari but it displays strange in Chrome.
Here's the safari screenshot:
Here's the chrome screenshot:
The safari one is perfect for me, but it seems chrome isn't liking it.
I have tried adding ALL vendor prefixes to the start of the selectors and various places but I cant seem to fix the issue.
Can anyone please tell me where I'm going wrong?
Here's a CODEPEN and here's a code snippet:
.wavy-line {
width: 150px;
height: 50px;
overflow: hidden;
margin: 0 auto 0 auto;
}
.wavy-line:before {
content: attr(data-text);
position: relative;
top: -35px;
color: rgba(0,0,0,0);
width: calc(100% + 27px);
font-size: 4em;
text-decoration-style: wavy;
text-decoration-color: #25173A;
text-decoration-line: underline;
animation: animate .9s linear infinite;
-webkit-animation: animate .9s linear infinite;
}
#keyframes animate {
0% { left: -0px; }
100% { left: -30px;}
}
#-webkit-keyframes animate {
0% { left: -0px; }
100% { left: -30px;}
}
.wavy-line-green:before { text-decoration-color: #56AE5F; }
.wavy-line-blue:before { text-decoration-color: #1FB5D1; }
.wavy-line-yellow:before { text-decoration-color: #F9B930; }
<div class="wavy-line wavy-line-green" data-text="xxxxxxxxxxxxxx"></div>
<div class="wavy-line wavy-line-blue" data-text="xxxxxxxxxxxxxx"></div>
<div class="wavy-line wavy-line-yellow" data-text="xxxxxxxxxxxxxx"></div>
I will consider a previous answer to draw the waves using CSS and then you can easily animate them. You simply need to adjust the CSS variable to control the shape:
.wave {
--c:red; /* Color */
--t:5px; /* Thickness */
--h:50px; /* Height */
--w:120px; /* Width */
--p:13px; /* adjust this to correct the position when changing the other values*/
margin:5px auto;
width:calc(var(--w)*4);
height:calc(var(--h) + 10px);
overflow:hidden;
position:relative;
}
.wave:before {
content:"";
position:absolute;
padding:5px 0;
top:0;
left:0;
width:200%;
bottom:0;
background:
radial-gradient(farthest-side at 50% calc(100% + var(--p)), transparent 47%, var(--c) 50% calc(50% + var(--t)),transparent calc(52% + var(--t))),
radial-gradient(farthest-side at 50% calc(0% - var(--p)), transparent 47%, var(--c) 50% calc(50% + var(--t)),transparent calc(52% + var(--t)));
background-size:var(--w) var(--h);
background-position:calc(var(--w)/2) calc(-1*(var(--h)/2)),0px calc(var(--h)/2);
background-repeat:repeat-x;
background-origin:content-box;
animation:move 3s infinite linear;
}
#keyframes move {
to {
transform:translateX(-50%);
}
}
<div class="wave"></div>
<div class="wave" style="--w:140px;--h:40px;--p:13px; --t:8px;--c:purple"></div>
<div class="wave" style="--w:100px;--h:30px;--p:14px;--t:10px;--c:green;"></div>
<div class="wave" style="--w: 64px;--h: 22px;--p: 11px;--t: 7px;--c: orange;"></div>
Related
Trying to smoothly animate a div's background image #bg2 over a short pixel distance (while a clip path animates over it). I'm not able to get the image to move smoothly, it jitters and judders. The clip path animation is fine.
I've tried different easing (linear / ease-in-out etc) suggested in another SO thread, and also extending the distance it needs to move, but it still seems to jump pixel by pixel (sort of), rather than move smoothly. (Although, extending the move distance isn't an option in the actual use case).
How can smooth movement of the cat background image #bg2 be accomplished? Thanks.
** Edit: It's totally smooth for me in Firefox, for me it's jittery in Chrome 91.0.4472.114 on Mojave 10.14.6, and less jittery in Safari. For other it seems to be smooth on Chrome also. Hmmm...
var clickTag = "#";
#main-container {
position: absolute;
width: 970px;
height: 250px;
left:-200px;
box-sizing: border-box;
background: #333;
overflow:hidden; perspective: 800px;
border:1px solid #ccc;
}
div, img {
position: absolute;
background-repeat:no-repeat;
width: 970px;
height: 250px;
z-index: 4;
background-size: 970px 250px;
}
#bg2{
width: 970px;
height: 250px;
z-index:2;
background-image:url('https://i.stack.imgur.com/6EcDu.jpg');
-webkit-clip-path: circle(9% at 682px 110px);
clip-path: circle(9% at 682px 110px);
transform: translateY(20px);
background-position: -5px -10px;
}
#bg2{animation: grow 2.5s 2.5s cubic-bezier(0.215, 0.610, 0.355, 1.000) forwards;-webkit-animation: groww 2.5s 2.5s cubic-bezier(0.215, 0.610, 0.355, 1.000) forwards;}
#-webkit-keyframes groww {
0% {opacity:1;transform: translateY(20px);clip-path: circle(9% at 682px 110px);-webkit-clip-path: circle(9% at 682px 110px);background-position: -5px -10px;}
100% {opacity:1;transform: translateY(-4px);clip-path: circle(15% at 682px 128px);-webkit-clip-path: circle(15% at 682px 128px);background-position: 0px 0px;}
}
#keyframes grow {
0% {opacity:1;transform: translateY(20px);clip-path: circle(9% at 682px 110px);background-position: -5px -10px;}
100% {opacity:1;transform: translateY(-4px);clip-path: circle(15% at 682px 128px);background-position: 0px 0px;}
}
<a href="javascript:window.open(window.clickTag)">
<div id="main-container" class="animate">
<div id="bg2"></div>
</div>
</a>
I'm a bit curious about why having a large banner while not displaying it all.
Anyways, I provide another way of animating, basically just changing the height. Hopefully that could give some ideas.
I removed the width to make it slightly more responsive.
The animation somewhat jittery in this solution, but I guess that it depends on your bezier curve. So perhaps that's the issue all along?
var clickTag = "#";
#main-container {
position: relative;
height: 250px;
box-sizing: border-box;
border: 1px solid #ccc;
background-color: #333;
}
#bg2 {
position: absolute;
left: 75%;
top: 50%;
transform: translate(-50%, -50%);
height: 40%;
aspect-ratio: 1;
border-radius: 50%;
background-image: url('https://i.stack.imgur.com/6EcDu.jpg');
background-position: right 25% center;
animation: grow 2.5s 2.5s cubic-bezier(0.215, 0.610, 0.355, 1.000) forwards;
}
#keyframes grow {
to { height: 80%; }
}
<a href="javascript:window.open(window.clickTag)">
<div id="main-container">
<div id="bg2"></div>
</div>
</a>
I'm trying to create a repeated background existing out of two parts. Each part is a gradient and while the one moves up, the other moves down.
The best I got is this:
html {
background: black;
color: #4c4c4c;
}
body {
margin: 30vh auto;
max-width: 80vw;
}
.wave {
background: none;
height: 1rem;
width: 50%;
position: absolute;
z-index: 2;
animation: move 700ms 0ms steps(2) infinite both;
}
.color::after,
.color::before {
content: "";
position: absolute;
left: 0;
right: 0;
height: 100%;
top: 0;
}
.color {
background-image: linear-gradient(#fe0000 50%, #6531ff 0 100%);
}
.color::after {
background: linear-gradient(to bottom, #f4e04d, #3bceac 20%, rgba(22, 22, 22, 0) 100%), linear-gradient(to right, #042a2b 3rem, transparent 3rem, transparent 6rem);
}
.wave,
.color::after,
.color::before {
background-size: 5rem 1rem;
background-repeat: repeat-x;
}
#keyframes move {
0% {
margin-top: -3rem;
}
100% {
margin-top: -3.25rem;
}
}
<div class="color wave"></div>
I get why this doesn't work, but not sure how to proceed.
Since it is difficult to describe, here is an image of what I'm looking for:
At first (position 1), all odd blocks are higher than the even blocks. After the first animation, it's the other way around (position 2) and so on.
Maybe like below:
.box {
height:100px;
background:linear-gradient(red,blue,yellow,red) 0 0/100% 200%;
animation:y 2s linear infinite;
}
.box::after {
content:"";
display:block;
height:100%;
background:linear-gradient(green,lightblue,pink,green) 0 0/100% 200%;
animation:inherit;
animation-direction: reverse;
-webkit-mask:linear-gradient(90deg,#fff 50%,transparent 0) 0 0/20% 100%;
}
#keyframes y {
to {
background-position:0 -200%;
}
}
<div class="box"></div>
UPDATE: This is an interesting problem. I'm surprised to find that I don't have an obvious or particularly elegant solution to having a gradient running vertically while repeating with horizontal gaps.
Far more elusive than I initially expected.
Best I could come up with is to put one of the gradients in a pseudo element and apply a mask-image. This won't work in IE, but it appears to be supported everywhere else.
See updated demo below.
If I understand what you're trying to do, I think you could accomplish it by animating the background positions:
.demo {
height: 200px;
background-image:
linear-gradient(#f4e04d, #3bceac 20%, rgba(22, 22, 22, 0) 100%);
animation: move 0.7s infinite alternate;
background-size: 3rem;
position: relative;
}
.demo::before {
content: '';
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
background: linear-gradient(#042a2b, transparent);
/* This is the magic part: using a horizontal repeating-linear-gradient
to mask out "columns", allowing the container's background gradient to
show through */
-webkit-mask-image: repeating-linear-gradient(to right, black 0 3rem, transparent 3rem 6rem);
background-size: 3rem;
/* run the same animation in reverse to animate up instead of down */
animation: move 0.7s infinite alternate-reverse;
}
#keyframes move {
from {
background-position: 0 0;
}
to {
background-position:
0 200px;
}
}
<div class="demo"></div>
It's difficult to infer exactly what you're trying to do, but here's another sample (very similar to #ray hatfield's answer) that will move the first background down while the second background moves up:
.sample {
width: 250px;
height: 50px;
position: relative;
background-image: linear-gradient(to bottom, #f4e04d, #3bceac 20%, rgba(22, 22, 22, 0) 100%), linear-gradient(to right, #042a2b 3rem, transparent 3rem, transparent 6rem);
animation: move 1s infinite linear;
}
#keyframes move {
0%, 100% {
background-position: 0 -75px, 0 0;
}
50% {
background-position: 0 0, 0 -75px;
}
}
<div class="sample"></div>
I have an image of a butterfly, something like this.
I am trying to figure out if there is any way to make it look like its wings are opening and closing with a 3D CSS transform/translate or animation, but without having to split the image up into parts (it can be a background image of a div though if that helps).
Yes, using background applied to two elements where each one will show only one half and then you simply rotate both on the Y axis.
.box {
width:300px;
margin:20px;
display:flex;
perspective:500px;
}
.box::before,
.box::after{
content:"";
padding-top:56%; /* ratio based on your image */
flex:1; /* half the main element size */
background-image:url(https://i.imgur.com/DgMoHC5.jpg);
background-size:200% 100%; /* twice bigger than the pseudo element to get half the image*/
animation:left 1s linear infinite alternate;
transform-origin:right;
}
.box::after {
background-position:right; /* get the right part of the image */
animation-name:right;
transform-origin:left;
}
#keyframes left{
to {transform:rotateY(60deg)}
}
#keyframes right{
to {transform:rotateY(-60deg)}
}
<div class="box"></div>
A more realistic animation with some translation:
.box {
width: 300px;
margin: 20px;
display: flex;
perspective: 500px;
}
.box::before,
.box::after {
content: "";
padding-top: 56%;
flex: 1;
background-image: url(https://i.imgur.com/DgMoHC5.jpg);
background-size: 200% 100%;
animation: left 0.5s linear infinite alternate;
transform-origin: right;
}
.box::after {
background-position: right;
animation-name: right;
transform-origin: left;
}
#keyframes left {
from {
transform: translateZ(80px) rotateY(-30deg)
}
to {
transform:translateZ(0px) rotateY(50deg)
}
}
#keyframes right {
from {
transform: translateZ(80px) rotateY(30deg)
}
to {
transform:translateZ(0px) rotateY(-50deg)
}
}
<div class="box"></div>
I'm trying to create a rainbow animation with CSS variables and HSL. I've got the following code, however in Chrome it just snaps between both states.
#keyframes rainbow {
from {
--accent-bright: hsl(0,87%,48%);
--accent-dark: hsl(0,94%,48%);
--accent-verydark: hsl(0,88%,33%);
}
to {
--accent-bright: hsl(359,87%,48%);
--accent-dark: hsl(359,94%,48%);
--accent-verydark: hsl(359,88%,33%);
}
}
.rainbow, .rainbow *, .rainbow > * {
animation-name: rainbow;
animation-duration: 3.6s;
animation-iteration-count: infinite;
}
[...]
#topBar {
height: 56px;
width:100vw;
position:fixed;
top:0;
background-image: linear-gradient(to right, var(--accent-bright),var(--accent-dark));
color: var(--text-onaccent);
}
If I change the hue in one of the keyframes to someething more noticible, you can see the gradient flipping.
The property background-image is not animatable
However... opacity is animatable.
This means that you can create an ::after pseudo-element, exactly overlapping your original element and animate the pseudo-element's opacity so that it fades into view.
Remember to apply pointer-events: none to the pseudo-element, so that, as far as interactivity goes, the pseudo-element remains entirely insubstantial.
Working Example:
N.B. I have introduced yellow to make the animation more visible.
.rainbow {
--accent-bright: hsl(0, 87%, 48%);
--accent-dark: hsl(0, 94%, 48%);
--accent-verydark: hsl(0, 88%, 33%);
position: relative;
width: 100px;
height: 100px;
background-image: linear-gradient(to right, var(--accent-bright), var(--accent-dark));
color: var(--text-onaccent);
}
.rainbow::after {
--accent-bright: hsl(359, 87%, 48%);
--accent-dark: yellow;
--accent-verydark: hsl(359, 88%, 33%);
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-image: linear-gradient(to right, var(--accent-bright), var(--accent-dark));
pointer-events: none;
animation: rainbow 3.6s infinite;
}
#keyframes rainbow {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
<div class="rainbow"></div>
I'm trying to animate a line that underlines from left to right on 'mouseenter' and then to disappear from left to right on 'mouseleave' instead of the current behaviour where it disappears right to left.
Example of what I'm trying to achieve (but with animations not transitions):
https://jsfiddle.net/1gyksyoa/
I have tried to reverse the 'draw' animation but this doesn't achieve what I'm trying to accomplish.
#keyframes draw-reverse {
100% {
width: 0;
background-color: red;
}
0% {
width: 47px;
background-color: red;
}
}
I have put together this to give a better understanding of the problem;
https://jsfiddle.net/Lq560be9/
Currently, I have the line animating from left to right as desired on 'mouseenter', but on 'mouseleave' it disappears from right to left, whereas I am trying to get the line to also disappear from left to right.
But the problem isn't animation's ability it's the properties that you're animating. Instead of animating the width of an object you should animate its "X" position using translate. (this is much more performant too)
Simply put you need to MOVE the bar from left to center to right instead of trying to scale it.
(there's lots of code here to show the different states the only one you really need to follow is .ex4)
document.querySelector('#animate').addEventListener('mouseenter', function(){
this.classList.toggle('over');
})
document.querySelector('#animate').addEventListener('mouseleave',function(){
this.classList.toggle('out');
})
.example {
margin: 30px auto;
padding: 10px;
background: #dadada;
max-width: 50%;
position: relative;
}
.example:after {
content:'';
position: absolute;
width: 50%;
height: 5px;
background-color: #333;
left:0;
bottom:0;
}
.ex1:after {
transform: translateX(-100%);
}
.ex3:after {
transform: translateX(200%);
}
.ex4 {
overflow: hidden;
}
.ex4:after {
transform: translateX(-100%);
}
.ex4.over:after {
animation: animate-in 1s ease-in-out 1 normal forwards;
}
.ex4.out:after {
animation: animate-out 1s ease-in-out 1 normal forwards;
}
#keyframes animate-in {
0% {
transform: translateX(-100%);
}
100% {
transform: translateX(0);
}
}
#keyframes animate-out {
0% {
transform: translateX(0);
}
100% {
transform: translateX(200%);
}
}
<div class="example ex1">Object State 1</div>
<div class="example ex2">Object State 2</div>
<div class="example ex3">Object State 3</div>
<div id="animate" class="example ex4">Full example (hover)</div>
As a follow on from above, an alternative solution without using the translate property.
The new animation for mouseleave is;
#keyframes draw-reverse {
0% {
width: 47px;
}
25% {
width: calc(100% - 16px);
}
26% {
width: auto;
right: 8px;
left: 8px;
}
100% {
width: auto;
right: 8px;
left: calc(100% - 8px);
}
}
Full solution can be seen here - https://jsfiddle.net/1wq25tg7/