How do I make this animation smoother in CSS? - html

I'm a novice to web development, and I'd like to make a circle rotate the orientation of its linear gradient smoothly, but there is a jump in between each orientation.
I expected it to be smooth, since I used steps and set the animation-timing-function to linear, but there is a jump in between each step of the animation.
I'm not quite sure how to display the code here, if anyone has any tips for a beginner I would appreciate it.
Edit: Here is the code :)
/* The animation: */
#keyframes gradientShift {
0% {background-image: linear-gradient(to right, rgb(0, 4, 255), rgb(0, 162, 255));}
25% {background-image: linear-gradient(rgb(0, 4, 255), rgb(0, 162, 255));}
50% {background-image: linear-gradient(to right, rgb(0, 162, 255), rgb(0, 4, 255));}
75% {background-image: linear-gradient(rgb(0, 162, 255), rgb(0, 4, 255));}
100% {background: linear-gradient(to right, rgb(0, 4, 255), rgb(0, 162, 255));}
}
/* The other styles*/
.circle-wrapper {
background-image: linear-gradient(to right, rgb(0, 4, 255), rgb(0, 162, 255));
animation: gradientShift;
animation-duration: 2s;
animation-iteration-count: infinite;
animation-timing-function: linear;
margin-top: 28vh;
width: 12vh;
height: 12vh;
margin-left: 35vh;
border-radius: 100px;
position: absolute;
padding: 3px;
z-index: 1000;
}
<div class="circle-wrapper">
<div class="circle-module"> </div>
</div>

That is because CSS cannot handle transitions in background images. Basically your CSS animation is "stepped" and will have 5 distinct frames with no interpolation in between.
Seeing that you are only rotating the angle of the gradient and not performing and color changes, you can simply set the linear-gradient on a pseudo-element and rotate it instead:
/* The animation: */
#keyframes rotate {
0% {
transform: rotate(0);
}
100% {
transform: rotate(360deg);
}
}
/* The other styles*/
.circle-wrapper {
margin-top: 28vh;
width: 12vh;
height: 12vh;
margin-left: 35vh;
border-radius: 100px;
position: absolute;
padding: 3px;
z-index: 1000;
overflow: hidden;
}
.circle-wrapper::before {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-image: linear-gradient(to right, rgb(0, 4, 255), rgb(0, 162, 255));
animation: rotate;
animation-duration: 2s;
animation-iteration-count: infinite;
animation-timing-function: linear;
content: '';
}
.circle-wrapper>* {
position: relative;
}
<div class="circle-wrapper">
<div class="circle-module"> </div>
</div>

There is no way in css to animate the background-image property.
You see the CSS Animated Properties to know what are the animatable css properties.
But it still possible with javascript, you can use setInterval() with a very small amount of time to change your rotation degree:
let circle = document.getElementsByClassName("circle-wrapper")[0]
let rotateDeg = 0
setInterval(function() {
circle.style.backgroundImage = "linear-gradient(" + ++rotateDeg + "deg, rgb(0, 4, 255), rgb(0, 162, 255))"
}, 2000/360)
.circle-wrapper {
background-image: linear-gradient(to right, rgb(0, 4, 255), rgb(0, 162, 255));
margin-top: 28vh;
width: 12vh;
height: 12vh;
margin-left: 35vh;
border-radius: 100px;
position: absolute;
padding: 3px;
z-index: 1000;
}
<div class="circle-wrapper">
<div class="circle-module"> </div>
</div>

Related

CSS Marquee With Fade In/Out Effect

I am trying to make a CSS marquee whose text fades in from the right edge and fades out on the left edge. Only the letters on the edges should turn transparent. I'd call it an "opacity mask" that is feathered onto the left/right edges.
I can find CSS marquee code samples but none with such a fade in/out effect. I'd also like the background to be completely transparent, with just the text having the edge effects.
I've tried adding a gradient to the container but, in hind sight, that doesn't seem to be the right path. Below is the code I've come up with thus far. Please assist, thanks!
#Bernard Borg: I've updated my code with the second new sample. Other than this not using opacity - and therefore being A) dependent on being hardcoded to the underlying background color and B) only working on a solid background - this is acceptable for my use case. Thanks! (Any idea how to cover the marquee with opacity rather than a color?)
div#container {
width: 60%;
height: 100%;
position: absolute;
background-color: #e6e9eb;
}
div#marquee-container {
overflow: hidden;
}
p#marquee {
animation: scroll-left 10s linear infinite;
}
#keyframes scroll-left {
0% {transform: translateX( 140%)}
100% {transform: translateX(-140%)}
}
div#marquee-cover {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 40px;
background: linear-gradient(to right, rgba(230, 233, 235, 1) 0%, rgba(230, 233, 235, 0) 15%, rgba(230, 233, 235, 0) 85%, rgba(230, 233, 235, 1) 100%);
}
<div id="container">
<div id="marquee-container">
<p id="marquee">The quick brown fox jumps over the lazy dog</p>
<div id="marquee-cover"/> <!--thanks Bernard Borg-->
</div>
</div>
For anyone coming to this question in the future - the answer to this question was a joint effort. Find the answer in the question.
This is the closest I was able to get to your updated question;
body {
margin: 0;
}
#container {
width: 100%;
height: 100vh;
background-color: grey;
display: flex;
align-items: center;
}
#marquee-container {
overflow: hidden;
position: relative;
display: flex;
justify-content: space-between;
align-items: center;
}
p#marquee {
font-family: 'Segoe UI', sans-serif;
font-size: 30px;
font-weight: bold;
height: 80%;
animation: scroll-left 5s linear infinite;
white-space: nowrap;
}
#first-cover,
#second-cover {
height: 100vw;
backdrop-filter: opacity(50%);
width: 30vw;
z-index: 100;
}
#first-cover {
background: linear-gradient(90deg, rgba(0, 0, 0, 0.8), rgba(128, 128, 128, 0.2));
}
#second-cover {
background: linear-gradient(-90deg, rgba(0, 0, 0, 0.8), rgba(128, 128, 128, 0.2));
}
#keyframes scroll-left {
0% {
transform: translateX(130%);
}
100% {
transform: translateX(-130%);
}
}
<div id="container">
<div id="marquee-container">
<div id="first-cover"></div>
<p id="marquee">The quick brown fox jumps over the lazy dog</p>
<div id="second-cover"></div>
</div>
</div>
For some reason backdrop-filter (specifically with opacity) isn't doing anything. Weird.
Edit:
You could probably define an image for the background of the marquee (with gradients on each side) and then use mix-blend-mode in some way to fade the text. Perhaps I'm overcomplicating this. ¯\(ツ)/¯
Animate the opacity property (cleaned up the code for better readability);
body {
margin: 0;
}
div#marquee-container {
width: 600px;
height: 150px;
background: linear-gradient(to right, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 1) 15%, rgba(255, 255, 255, 1) 85%, rgba(255, 255, 255, 0) 100%);
}
p#marquee {
text-align: right;
animation: scroll-left 10s linear infinite;
}
#keyframes scroll-left {
0% {
opacity: 0;
}
20% {
opacity: 1;
}
80% {
opacity: 1;
}
100% {
transform: translateX(-80%);
opacity: 0;
}
}
<div style="background-color: black; width: 100%; height: 100%;">
<div id="marquee-container">
<p id="marquee">Testing</p>
</div>
</div>
Side note: You don't need vendor prefixes for animation anymore.
div#container {
width: 100%;
height: 100%;
position: absolute;
background-color: grey;
}
div#marquee-container {
width: 600px;
height: 150px;
position: absolute;
top: 50%;
left: 50%;
transform: translateX(-50%) translateY(-50%);
background: linear-gradient(to right, rgba(255,255,255,0) 0%, rgba(255,255,255,1) 15%, rgba(255,255,255,1) 85%, rgba(255,255,255,0) 100%);
}
p#marquee {
width: 80%;
height: 80%;
--opacity: 0;
moz-animation: scroll-left 1s linear infinite;
-webkit-animation: scroll-left 1s linear infinite;
animation: scroll-left 10s linear infinite;
}
#-moz-keyframes scroll-left {
0% {-moz-transform: translateX( 100%);}
100% {-moz-transform: translateX(-100%);}
}
#-webkit-keyframes scroll-left {
0% {-webkit-transform: translateX( 100%)}
100% {-webkit-transform: translateX(-100%)}
}
#keyframes scroll-left {
0% {-moz-transform: translateX( 100%); -webkit-transform: translateX( 100%); transform: translateX( 100%); opacity: 0;}
30%{
opacity: 1;
}
60%{
opacity: 0;
}
100% {-moz-transform: translateX(-100%); -webkit-transform: translateX(-100%); transform: translateX(-100%);opacity: 0; }
}
}
<div id="container">
<div id="marquee-container">
<p id="marquee">Testing</p>
</div>
</div>

CSS filter making element dissapear

I haven't found any good answers for this so I'm asking here; I have buttons on my website that i'm trying to mimic an OS X Lion style with, and I'm using keyframes to make an active button have a sort-of glow effect. However, using filter: brightness(x) for some reason is making my element disappear. Could it be because I'm using pseudo elements for the border? Or something else.
I tried using CSS filters to brighten a background gradient (I tried an image as well with the same results) and it ended up making the element disappear and show me my pseudo element (also I can't find the code snippet button anymore, is it gone?)
button {
padding: 5px 16px;
border-radius: 4px;
outline: none;
background: linear-gradient(to bottom, #fff 0 30%, #e2e2e2 70% 100%);
color: black;
border: none;
position: relative;
transform-style: preserve-3d;
letter-spacing: -0.3px;
text-shadow: -0.5px -0.5px 1px rgba(0, 0, 0, 0.1);
transition: 0s;
font-family: "Lucida Grande", sans-serif;
transform: scale(4);
margin: 200px;
}
button::after {
content: '';
position: absolute;
background: rgb(120, 120, 120);
width: calc(100% + 2px);
height: calc(100% + 2px);
left: -1px;
top: -1px;
transform: translateZ(-1px);
border-radius: 5px;
opacity: 1;
z-index: -1;
}
button:active {
background: linear-gradient(to bottom, rgb(188, 206, 233) 0, rgb(115, 158, 227) 50%, rgb(92, 145, 226) 51%, rgb(174, 215, 231) 100%);
animation: glow 1s infinite;
}
button:active::after {
content: '';
position: absolute;
background: linear-gradient(to bottom, rgb(89, 92, 169) 0 40%, rgb(80, 89, 142) 60% 100%);
width: calc(100% + 2px);
height: calc(100% + 2px);
left: -1px;
top: -1px;
transform: translateZ(-1px);
border-radius: 5px;
opacity: 1;
}
#keyframes glow {
0% {
filter: brightness(1.1);
}
50% {
filter: brightness(1.2);
}
100% {
filter: brightness(1.1);
}
}
<button>Button</button>
JSFiddle if there isn't a run snippet button
According to this answer, it seems that this is because filter overrides transform-style: preserve-3d, which then causes translateZ(-1px) to have unexpected result in this use case.
This could be avoided by refactor the styles without 3D transforms such as translateZ(-1px). While it might not be perfect, here is a possible example with the workaround.
This example moved styles on the original ::after to a ::before, and moved the button background style to a new ::after, as an alternative approach to the use of translateZ(-1px) to display the button background.
Hope this will help.
Example:
button {
padding: 5px 16px;
border-radius: 4px;
outline: none;
color: black;
border: none;
position: relative;
letter-spacing: -0.3px;
text-shadow: -0.5px -0.5px 1px rgba(0, 0, 0, 0.1);
transition: 0s;
font-family: "Lucida Grande", sans-serif;
transform: scale(2);
margin: 50px 100px;
}
button:active {
animation: glow 1s infinite;
}
button::before {
content: '';
position: absolute;
background: rgb(120, 120, 120);
width: calc(100% + 2px);
height: calc(100% + 2px);
left: -0.625px;
top: -0.625px;
border-radius: 5px;
opacity: 1;
z-index: -1;
}
button:active::before {
content: '';
position: absolute;
background: linear-gradient(to bottom, rgb(89, 92, 169) 0 40%, rgb(80, 89, 142) 60% 100%);
width: calc(100% + 2px);
height: calc(100% + 2px);
left: -0.625px;
top: -0.625px;
border-radius: 5px;
opacity: 1;
}
button::after {
content: '';
position: absolute;
inset: 0;
border-radius: 4px;
outline: none;
background: linear-gradient(to bottom, #fff 0 30%, #e2e2e2 70% 100%);
border: none;
transition: 0s;
z-index: -1;
}
button:active::after {
background: linear-gradient(to bottom, rgb(188, 206, 233) 0, rgb(115, 158, 227) 50%, rgb(92, 145, 226) 51%, rgb(174, 215, 231) 100%);
}
#keyframes glow {
0% {
filter: brightness(1.1);
}
50% {
filter: brightness(1.2);
}
100% {
filter: brightness(1.1);
}
}
<button>Button</button>

Data-text attribute on an h1 element doesn't show up when adding an animation to the element

I have an h1 element that I want to be invisible and then appear after a few seconds. The element has an ::after pseudo-element that displays a data-text attribute that shadows the h1 element. When I add the animation, I only see the h1 and not the pseudo-element as well. Here is my code
EDIT
adding the animation to the pseudo-element makes it appear, but now the data-text appears over the h1 element when originally it is supposed to go behind it. Here are some pic of what is happening. The first is what it is doing and the second is what I want.
EDIT 2
The problem can be recreated by removing the z-index on the pseudo-element.
<section class="wrapper">
<div class="content-wrapper">
<img class="flipInY" src="./img/neon-blue - flip.png" alt="logo-triangle">
<h1 class="name-ani" data-text="My Name">My Name</h1>
<h2 data-text="web-dev">Web Developer</h2>
</div>
</section>
.wrapper {
.content-wrapper {
z-index: 0;
position: relative;
display: grid;
justify-items: center;
margin-top: 20vh;
img {
width: 350px;
max-width: 100%;
padding: 0 32px;
// transform: rotate(180deg);
filter: brightness(85%);
position: relative;
}
h1 {
background: linear-gradient(
to bottom,
#ebf1f6 0%,
#abd3ee 50%,
#859ee2 51%,
#d5ebfb 100%
);
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
font-family: kimberly;
text-transform: uppercase;
font-size: 2.25rem;
transition: font-size 1s;
position: absolute;
top: 10%;
opacity: 0;
&::after {
background: none;
content: attr(data-text);
left: 0;
position: absolute;
text-shadow: 1px -1px 0 rgba(255, 255, 255, 0.5),
3px 1px 3px rgba(255, 0, 255, 0.85),
-3px -2px 3px rgba(0, 0, 255, 0.85),
1px -2px 0 rgba(255, 255, 255, 0.8);
z-index: -10;
opacity: 0;
}
}
.name-ani {
animation-name: name-ani;
animation-duration: 250ms;
animation-delay: 4.5s;
animation-fill-mode: forwards;
}
#keyframes name-ani {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
You need to apply the animation to the pseudo-element as well.
.name-ani,
.name-ani::after {
animation-name: name-ani;
animation-duration: 250ms;
animation-delay: 4.5s;
animation-fill-mode: forwards;
}
Edit: Getting rid of the position: absolute on the h1 by wrapping it and giving it an display: inline solved the stacking order for me as well.
<section class="wrapper">
<div class="content-wrapper">
<img class="flipInY" src="./img/neon-blue - flip.png" alt="logo-triangle">
<div class="h1-wrapper">
<h1 class="name-ani" data-text="My Name">My Name</h1>
</div>
<h2 data-text="web-dev">Web Developer</h2>
</div>
</section>
.wrapper {
.content-wrapper {
z-index: 0;
position: relative;
display: grid;
justify-items: center;
margin-top: 20vh;
img {
width: 350px;
max-width: 100%;
padding: 0 32px;
filter: brightness(85%);
position: relative;
}
.h1-wrapper {
position: absolute;
top: 10%;
}
h1 {
background: linear-gradient(to bottom,
#ebf1f6 0%,
#abd3ee 50%,
#859ee2 51%,
#d5ebfb 100%);
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
font-family: kimberly;
text-transform: uppercase;
font-size: 2.25rem;
transition: font-size 1s;
display: inline;
opacity: 0;
&::after {
background: none;
content: attr(data-text);
left: 0;
position: absolute;
text-shadow: 1px -1px 0 rgba(255, 255, 255, 0.5),
3px 1px 3px rgba(255, 0, 255, 0.85),
-3px -2px 3px rgba(0, 0, 255, 0.85),
1px -2px 0 rgba(255, 255, 255, 0.8);
z-index: -10;
opacity: 0;
}
}
.name-ani,
.name-ani::after {
animation-name: name-ani;
animation-duration: 250ms;
animation-delay: 4.5s;
animation-fill-mode: forwards;
}
#keyframes name-ani {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
}
}

Change background-image with CSS animation

How can I make this class change its background-image after 2 seconds of the div being in viewport? It's not changing for me:
.cover-gradient {
background-image: none;
}
.cover-gradient:after {
opacity: 1;
transition: 0.3s;
animation: fadeMe 2s linear;
}
#keyframes fadeMe {
0% {
background-image: none;
}
100% {
background-image: linear-gradient(to right, rgba(179, 49, 95, 0.5), rgba(58, 0, 117, 0.5));
}
}
Thanks.
When animating in CSS, you need to animate between two similar values.
For example, this will work:
max-height: 0px;
and
max-height: 100px;
and this will not:
max-height: none; and max-height: 100px;
However, for performance reasons, it's advisable to use opacity and transform properties when animating in CSS
.cover-gradient {
height: 100vh;
width: 100vw;
opacity: 0;
animation: fadeMe 0.3s linear;
animation-delay: 2s;
animation-fill-mode: forwards;
background-image: linear-gradient(to right, rgba(179, 49, 95, 0.5), rgba(58, 0, 117, 0.5));
}
#keyframes fadeMe {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
https://jsfiddle.net/hellogareth/j3ytzq52/22

Masking a circle and moving the mask with animation

I have a circular div that is vertically and horizontally centered in div. I am trying to achieve a css animation, that it seems like it's fading in from top to bottom.
I thought of making height 0 initially and moving to 50px, however as it is centered, it starts to getting created from the center. Instead, I want to it to get positioned to the initial position and it gets created from top to bottom. Just like there is a square only masking the circle and nothing else, and it moves to down.
#circle {
width: 80px;
height: 80px;
border-radius: 50px;
}
How can I add this a square mask to achieve the below effect?
Please note that background has a gradient, so I can't put a square and assign it a color directly, thus I thought I need to mask them.
How to achieve this effect?
What I have tried:
#keyframes example {
from {height: 0}
to {height: 80px}
}
As the circle is centered, it starts to expand from the middle. This is not what I want. That's why I thought of the mask
Edited answer:
I am able to achieve this with a combination of a image background and background-position animation.
This will not work if you set the background as a CSS color like #fff. it needs to be an image or a gradient. You also need to set background-repeat to no-repeat
The animation simply starts with the background out of the div display area then pulls the the background downward into the display area.
Kindly check the examples in full-screen.
Working snippet (jpeg image as object background):
body {
background: linear-gradient(135deg, rgba(244, 226, 156, 0) 0%, rgba(59, 41, 58, 1) 100%), linear-gradient(to right, rgba(244, 226, 156, 1) 0%, rgba(130, 96, 87, 1) 100%);
margin: 0 auto;
height: 120vh;
overflow: hidden;
}
.sun {
height: 400px;
width: 400px;
border-radius: 100vw;
margin: 5em auto;
animation-name: sunrise;
animation-duration: 10s;
animation-delay: .5s;
animation-timing-function: linear;
animation-iteration-count: 1;
background: url(https://image.ibb.co/eVdQ3Q/white.jpg);
background-repeat: no-repeat;
animation-fill-mode: forwards;
opacity: 0;
}
#keyframes sunrise {
from {
opacity: 1;
background-position: 0 -700px;
}
to {
opacity: 1;
background-position: 0 0px;
}
}
<div class="sun"></div>
Working snippet (gradient as object background):
body {
background: linear-gradient(135deg, rgba(244, 226, 156, 0) 0%, rgba(59, 41, 58, 1) 100%), linear-gradient(to right, rgba(244, 226, 156, 1) 0%, rgba(130, 96, 87, 1) 100%);
margin: 0 auto;
height: 120vh;
overflow: hidden;
}
.sun {
height: 400px;
width: 400px;
border-radius: 100vw;
margin: 5em auto;
animation-name: sunrise;
animation-duration: 10s;
animation-timing-function: linear;
animation-iteration-count: 1;
background: linear-gradient(white,white);
background-repeat: no-repeat;
animation-fill-mode: forwards;
opacity: 0;
}
#keyframes sunrise {
from {
opacity: 1;
background-position: 0 -700px;
}
to {
opacity: 1;
background-position: 0 0px;
}
}
<div class="sun"></div>