I'm trying to make an animation for drawing a square border on hover.
It's working fine but when drawing the left side of the border the bottom of the border is jittering
Here's a link to the codepen https://codepen.io/Taggagii/pen/GRxYpXY to see the code and the jittering that's happening.
My approach is to just animate the ::before element to render the top and right sides and the ::after element to render the bottom and left sides. To animate both of them I'm just modifying their width and height attributes so it doesn't really make sense to me that only the bottom is jittery and not all the sides.
Note: This issue is present on Chrome but not on Firefox
html {
background: #f58442;
}
.center {
display: flex;
justify-content: center;
align-items: center;
text-align: center;
}
.border-renderer {
--border-size: 1px;
--animation-duration: 4s;
--border-z-index: -1;
--border-color: black;
--second-border-final-extent: calc(100% + 2 * var(--border-size));
--first-border-final-extent: calc(100% + var(--border-size));
--size: 200px;
position: relative;
display: inline-block;
background: #ccba87;
padding: 10px;
font-size: 5em;
margin-left: 35vw;
margin-top: 40vh;
}
.border-renderer::before,
.border-renderer::after {
content: '';
background: var(--border-color);
position: absolute;
z-index: var(--border-z-index);
}
.border-renderer::before {
top: calc(-1 * var(--border-size));
left: 0;
}
.border-renderer::after {
top: var(--first-border-final-extent);
right: calc(-1 * var(--border-size));
transform: translateY(-100%);
}
.border-renderer:hover::before {
animation-name: draw-box-top-right;
animation-duration: calc(var(--animation-duration) / 2);
animation-timing-function: ease;
animation-fill-mode: forwards;
}
.border-renderer:hover::after {
animation-name: draw-box-bottom-left;
animation-duration: calc(var(--animation-duration) / 2);
animation-delay: calc(var(--animation-duration) / 2);
animation-timing-function: ease;
animation-fill-mode: forwards;
}
#keyframes draw-box-top-right {
0% {
width: 0%;
height: var(--border-size);
}
50% {
width: var(--first-border-final-extent);
height: var(--border-size);
}
100% {
width: var(--first-border-final-extent);
height: var(--first-border-final-extent);
}
}
#keyframes draw-box-bottom-left {
0% {
width: var(--border-size);
height: var(--border-size);
}
50% {
width: var(--second-border-final-extent);
height: var(--border-size);
}
100% {
width: var(--second-border-final-extent);
height: var(--second-border-final-extent);
}
}
<div class="holder">
<div class="border-renderer">
<div class="center">Mouse over me</div>
</div>
</div>
Related
I have a simple scaling animation applied to a circle using keyframes.
There is an unexpected and undesirable line that scales with the circle in Chrome Version 85.0.4183.102 (Official Build) (64-bit) and not in Firefox or Safari.
I cannot remove it - do you know how to? I have tried adding border: 0 to the various divs unsuccessfully.
#parent { overflow: hidden; background: #F0F4FF; height: 500px; width: 100%; position: relative; user-select: none; margin-block-end: 5rem; z-index: 3; }
.child { width: 100%; height: 100%; }
.child .inner { background: radial-gradient(circle at center, #D90368 20%, #F0F4FF 20%); }
.inner { position: relative; left: 0; top: 0; animation: circle 2s linear infinite; display: block; height:100%; width: 100%; content: " "; }
#keyframes circle { 0% { transform: scale(0.5) } 50% { transform: scale(1.2) } 80% { transform: scale(0.95) } 100% { transform: scale(1.0) } }
<div id='parent'>
<div class='child'>
<span class='inner'></span>
</div>
</div>
I have tried to search SO however I find a lot of similar line / scale / keyframe posts but these are intentional line animation posts.
I had the line to on Chrome. So I edited the code a bit, and the line was gone. Not sure what the problem was, just a different solution:
The html:
<div id="parent">
<div class="child">
<div class="inner"></div>
</div>
</div>
And the CSS
#parent {
overflow: hidden;
background: #f0f4ff;
height: 500px;
width: 100%;
position: relative;
user-select: none;
margin-block-end: 5rem;
z-index: 3;
}
.child {
width: 100%;
height: 100%;
position: relative;
}
.inner {
background-color: #d90368;
width: 10rem;
height: 10rem;
position: absolute;
left: calc(50% - 5rem);
top: calc(50% - 5rem);
animation: circle 2s linear infinite;
display: block;
content: " ";
border-radius: 50%;
}
#keyframes circle {
0% {
transform: scale(0.5);
}
50% {
transform: scale(1.2);
}
80% {
transform: scale(0.95);
}
100% {
transform: scale(1);
}
}
I'm trying to load the progress bar up to a certain percentage. Whatever that percentage is, the progress bar will stop at that specific color animation specified in the keyframes.
How can i get it to work.
HTML
<div class="container">
<div class="progress-bar">
<span style="width:50%">
<span class="progress-value"></span>
</span>
</div>
<span><strong>CSS</strong></span>
<br/>
</div>
CSS
.container {
display: flex;
justify-content: center;
}
.progress-bar {
background-color: lightgray;
border-radius: 1.25em;
width: 300px;
height: 16px;
width: 50vw;
}
.progress-bar > span {
display: flex;
}
.progress-value {
background-color: #673ab7;
transition: 0.3s all linear;
border-radius: 1.25em;
height: 16px;
width: 50vw;
animation: progress-color 3s linear forwards;
-webkit-animation: progress-color 3s linear forwards;
}
/* animation */
#keyframes progress-color {
0% {
width: 0;
}
50% {
width: 30%;
background: purple;
}
100% {
background: green;
width: 100%;
}
}
#-webkit-keyframes progress-color {
0% {
width: 0;
}
50% {
width: 30%;
background:red;
}
100% {
background: green;
width: 100%;
}
}
Here's my codepen
https://codepen.io/mingsterism/pen/xJgePK
The problem is that where you have specified the animation is 100% completed under the #keyframes , there you must specify red as the color, which you have specified as the color you wish when the bar reaches 50%, while the rest of of the code is fine. Replace your piece of code with this one below and tell, is this what you want ?
#keyframes progress-color {
0% {
width: 0;
}
50% {
width: 30%;
background: green;
}
100% {
background: red;
width: 100%;
}
}
#-webkit-keyframes progress-color {
0% {
width: 0;
}
50% {
width: 30%;
background: green;
}
100% {
background: red;
width: 100%;
}
}
I have 2 images with transparent background and need to put one on top of each other with the same positioning:
1 spinning (underneath)
1 fixed (above)
I need to have the whole image composition to be centered and to have its size adjusted depending on the window size.
I used an ::after pseudo element for the fixed one but couldn’t get its position and size to follow the spinning one.
I suppose the background-size property should be involved but didn’t manage to use it properly.
Would appreciate any advice, even if it involves going with a totally different approach than the ::after pseudo class.
Many thanks.
body{
width: 100%;
height: 100%;
background-color: #000;
text-align: center;
color: #fff;
}
.main-container{
background-color: #00f;
width: 50%;
margin: 0 auto;
}
.engine-container{
}
.engine-complete{
position: relative;
width: 100%;
height: auto;
margin: 0 auto;
}
.engine-complete::after{
content: "";
position: absolute;
width: 191px;
height: 192px;
top: 1px;
left: 0;
background-image: url(https://image.ibb.co/jOqNma/engine1_crpd.png);
}
.engine-rotating{
width: 50%;
height: auto;
}
.spin {
animation-duration: 15s;
animation-name: spin;
animation-iteration-count: infinite;
animation-timing-function:linear;
animation-play-state: running;
}
#keyframes spin {
from {
transform:rotate(360deg);
}
to {
transform:rotate(0deg);
}
}
<div class="main-container">
<h1>spinning engine</h1>
<div class="engine-container">
<div class="engine-complete">
<img src="https://image.ibb.co/nwOKXF/engine1.png" width=191 height=192 class="engine-rotating spin"/>
</div>
</div>
</div>
Something like this?
EDIT: Instead of setting the image as a background using the ::after pseudo-class, I added the fixed image into the html. I also eliminated one of your containers.
I centred the animated image using text-align:center and centred the fixed image using position: absolute
I set both images to 30% width relative their parent .engine-container
The fixed image has a higher z-index than the animated image so that it always appears over it. The images also change size accordingly, relative to window size.
body {
width: 100%;
height: 100%;
background-color: #000;
text-align: center;
color: #fff;
}
.main-container {
background-color: #00f;
width: 50%;
margin: 0 auto;
}
.engine-container {
text-align: center;
position: relative;
}
.engine-rotating,
.engine-fixed {
width: 30%;
}
.engine-fixed {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) rotate(0deg);
z-index: 5000;
}
.spin {
animation-duration: 15s;
animation-name: spin;
animation-iteration-count: infinite;
animation-timing-function: linear;
animation-play-state: running;
}
#keyframes spin {
from {
transform: rotate(360deg);
}
to {
transform: rotate(0deg);
}
}
<div class="main-container">
<h1>spinning engine</h1>
<div class="engine-container">
<img src="https://image.ibb.co/nwOKXF/engine1.png" class="engine-rotating spin" />
<img src="https://image.ibb.co/jOqNma/engine1_crpd.png" class="engine-fixed" alt="">
</div>
</div>
UPDATE
Heres what I came up with:
A similar effect using ::after. I was able to achieve this by inserting the image url into the content: rule, rather than setting a background image.
body {
width: 100%;
height: 100%;
background-color: #000;
text-align: center;
color: #fff;
}
.main-container {
background-color: #00f;
width: 50%;
margin: 0 auto;
}
.engine-container{
text-align: center;
position: relative;
}
.engine-rotating{
}
.engine-container::after{
content: url('https://image.ibb.co/jOqNma/engine1_crpd.png');
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) rotate(0deg);
z-index: 5000;
}
.spin{
animation-duration: 15s;
animation-name: spin;
animation-iteration-count: infinite;
animation-timing-function: linear;
animation-play-state: running;
}
#keyframes spin{
from {
transform: rotate(360deg);
}
to {
transform: rotate(0deg);
}
}
<div class="main-container">
<h1>spinning engine</h1>
<div class="engine-container">
<img src="https://image.ibb.co/nwOKXF/engine1.png" class="engine-rotating spin" />
</div>
</div>
Set position for .engine-complete::after to relative
.engine-complete::after {position: relative}
body{
width: 100%;
height: 100%;
background-color: #000;
text-align: center;
color: #fff;
}
.main-container{
background-color: #00f;
width: 50%;
margin: 0 auto;
}
.engine-container{
}
.engine-complete{
position: relative;
width: 100%;
height: auto;
margin: 0 auto;
}
.engine-complete::after{
content: "";
position: relative; /* this was changed */
width: 191px;
height: 192px;
top: 1px;
left: 0;
background-image: url(https://image.ibb.co/jOqNma/engine1_crpd.png);
}
.engine-rotating{
width: 50%;
height: auto;
}
.spin {
animation-duration: 15s;
animation-name: spin;
animation-iteration-count: infinite;
animation-timing-function:linear;
animation-play-state: running;
}
#keyframes spin {
from {
transform:rotate(360deg);
}
to {
transform:rotate(0deg);
}
}
<div class="main-container">
<h1>spinning engine</h1>
<div class="engine-container">
<div class="engine-complete">
<img src="https://image.ibb.co/nwOKXF/engine1.png" width=191 height=192 class="engine-rotating spin"/>
</div>
</div>
</div>
I'm trying to make a strikethrough animation like the effect here:
The strike line appears from left to right and disappears from left to right.
#keyframes strike {
0% {
width: 0;
}
50% {
width: 100%;
}
100% {
width: 0;
}
}
.strike {
position: relative;
}
.strike:hover:after {
content: ' ';
position: absolute;
top: 50%;
left: 0;
width: 100%;
height: 1px;
background: black;
animation-name: strike;
animation-duration: 1s;
animation-timing-function: linear;
animation-iteration-count: 1;
animation-fill-mode: fill;
animation-direction: normal;
}
<div>
The text in the span <span class="strike">is what I want to strike out</span>.
</div>
Is there a way to achieve that only with CSS ?
You can use transforms and transform-origin in the keyframe animation to make strike-through apear from left to right and disapear from left to right.
The point is to scale the pseudo element on the X axis for 0 to 1 with a transform origin on the left then back to 0 with a transform origin on the right (similar to this hover effect see last example of the answer).
And here is an example with your markup :
#keyframes strike{
0% { transform-origin: 0% 50%;transform:scaleX(0); }
50% { transform-origin: 0% 50%;transform:scaleX(1); }
50.01% { transform-origin:100% 50%;transform:scaleX(1); }
100% { transform-origin:100% 50%;transform:scaleX(0); }
}
.strike {
position: relative;
}
.strike:hover:after {
content: ' ';
position: absolute;
top: 50%;
left: 0;
width: 100%;
height: 1px;
background: black;
animation: strike .75s ease-in-out forwards;
}
<div>
The text in the span <span class="strike">is what I want to strike out</span>.
</div>
Here is a sample using transition, where it on hover toggle left/right position.
.strike {
position: relative;
}
.strike::after {
content: ' ';
position: absolute;
top: 50%;
left: 0;
right: 100%;
height: 1px;
background: black;
}
.strike:hover::after {
right: 0;
left: 100%;
transition: right .5s .0s, left .5s .5s;
}
<div>
The text in the span <span class="strike">is what I want to strike out</span>.
</div>
I have a pretty simple animation that has borders that I created animate in width, in height, and then the center fades in.
The issue I'm having is I can't figure out how to animate from the center, rather than left to right (for the top and bottom borders) and top to bottom (for the side borders).
Is there any simple way to get the animation to happen from the middle?
Example of the code for the top and bottom animation:
#keyframes tb {
0% {width: 0;}
100% {width: 800px}
}
JSFiddle of the code.
You need to animate the left and top, too. For the horizontal bars, set the property left to 400px (50%) on the first keyframe, and to 0px on the last keyframe. Same goes for the vertical bars. Here is your fixed example:
#import url(https://fonts.googleapis.com/css?family=Montserrat:700);
html{
background: black;
}
#holder{
width: 800px;
display: block;
position: relative;
}
#follower {
display: block;
text-align: center;
padding: 20px;
font-family: 'Montserrat', sans-serif;
font-size: 30px;
line-height: 70px;
color: #fff;
background: rgba(255,255,255,.1);
animation: main 2s ease-out;
-webkit-animation: main 2s ease-out;
}
#keyframes main {
0% {opacity: 0}
50% {opacity: 0}
100%{opacity: 1}
}
#-webkit-keyframes main {
0% {opacity: 0}
50% {opacity: 0}
100%{opacity: 1}
}
#t, #b {
width: 800px;
height: 2px;
background: #fff;
position: absolute;
display: block;
animation: tb .5s 1 ease-out;
-webkit-animation: tb .5s 1 ease-out;
}
#t {
top: 0;
left: 0;
}
#b{
bottom: 0;
left: 0;
}
#r, #l {
width: 2px;
height: 110px;
background: #fff;
position: absolute;
display: block;
animation: rl 1s 1 ease-out;
-webkit-animation: rl 1s 1 ease-out;
}
#r{
left: 0;
top: 0;
}
#l {
right: 0;
top: 0;
}
#keyframes tb {
0% {
width: 0;
left: 400px;
}
100% {
width: 800px
left: 0;
}
}
#keyframes rl {
0% {height: 0}
50% {
height: 0;
top: 55px;
}
100% {
height: 110px;
top: 0;
}
}
<div id="holder">
<div id="t"></div>
<div id="b"></div>
<div id="r"></div>
<div id="l"></div>
<div id="follower">
Super Long Text Goest Here!
</div>
</div>
You can play around with your timing, and make it start at right point in your animation... using an animation-delay.
E.g.
#keyframes makeFatter {
0% {width: 0;}
100% {width: 800px}
}
#makeMeFat {
animation-name: makeFatter;
animation-duration: 5s;
animation-delay: -2.5s; /* Makes it start at 50% of your animation, i.e. width: 400px */
/* blah blah... rest of the CSS code */
}