CSS/HTML Animation Circle to Square. Which property/attribute determines the Shape? - css

In the included example found on codepen from CSS-Tricks , which
property in the css code determines the shape of the div?
I understand most of the css properties here. I am just wondering what
determines the shape, and if there is a way to describe/or make other
shapes. For example a star or triangle.
I am new to css and would like to learn the language, especially
animation tricks.
.element {
height: 250px;
width: 250px;
margin: 0 auto;
background-color: red;
animation-name: stretch;
animation-duration: 1.5s;
animation-timing-function: ease-out;
animation-delay: 0;
animation-direction: alternate;
animation-iteration-count: infinite;
animation-fill-mode: none;
animation-play-state: running;
}
#keyframes stretch {
0% {
transform: scale(.3);
background-color: red;
border-radius: 100%;
}
50% {
background-color: orange;
}
100% {
transform: scale(1.5);
background-color: yellow;
}
}
body,
html {
height: 100%;
}
body {
display: flex;
align-items: center;
justify-content: center;
}
<div class="element"></div>

The shape here is determined by border-radius, which can be used to round out the edges of an HTML element (turning a box into a rounded rectangle), or with enough radius (or border-radius: 50%), it can transform a square element into a circle. There's no similar way to produce other shapes (triangle, star, etc), though there are many outside-the-box and creative ways to do this, like using borders to make a CSS triangle.

Related

Is it possible to use transform: scaleX() without affecting the border-radius?

I am trying to generate a simple expanding bar animation. Everything works find and I control it to my liking, except for the changing border-radius which is affected by the scaleX() transformation. Is there a way to avoid this effect?
I assumed using an absolute unit for border-radius would suffice but it doesn't. scaleX() still affects it.
Important note:
I want to use scaleX() rather than working with the width property because the elements i am working on come with various changing widths and I want to have only one animation to work with them all.
div {
width: 200px;
height: 20px;
background-color: pink;
border-radius: 10px;
animation: expand;
animation-duration: 10s;
animation-iteration-count: infinite;
}
#keyframes expand {
from {
transform: scaleX(0.1);
}
to {
transform: scaleX(1);
}
}
<div />
I want to use scaleX() rather than working with the width property because the elements i am working on come with various changing widths and I want to have only one animation to work with them all.
Don't specify the to and your animation will work with any width:
.bar {
width: 200px;
height: 20px;
background-color: pink;
border-radius: 10px;
animation: expand;
animation-duration: 10s;
animation-iteration-count: infinite;
}
#keyframes expand {
from {
width:20px;
}
}
<div class="bar"></div>
<div class="bar" style="width:100px"></div>
<div class="bar" style="width:40px"></div>

Is it possible to play an animation in both directions with a single #keyframes rule?

I would like to use a single #keyframes rule to animate an element from one state to another and then to get back to the original state when I do an action (with the same animation). I saw that using animation-direction: reverse; is a way to play the animation in reverse. However, when I try to use it, the transitions on my element disappear. If I set a new #keyframes with the reversed state it works fine.
What is the point of animation-direction in this case? I am misunderstanding something?
Is there a way to play an animation in both directions with a single #keyframes rule without loosing the transitions? I can't use transition, I need animation.
Here is a example to play with (hover the squares):
div {
width: 100px;
height: 100px;
animation: fade 0.6s ease-in-out forwards;
margin: 15px;
display: inline-flex;
align-items: center;
justify-content: center;
color: white;
}
#box-1:hover {
animation: fade 0.6s ease-in-out forwards;
animation-direction: reverse;
}
#box-2:hover {
animation: fadeReverse 0.6s ease-in-out forwards;
}
#keyframes fade {
0% { background: red; }
100% { background: blue; }
}
#keyframes fadeReverse {
0% { background: blue; }
100% { background: red; }
}
<div id="box-1">:(</div>
<div id="box-2">:)</div>
It's because you apply the same animation to the element on hover as the animation that is on the default state of the element.
So the element already had that animation with the default direction but then you apply it again with the reverse. But it won't work. I don't really know why this happens. But applying the same animation on an element twice, won't work. So you need 2 different keyframes.
You can use a reverse animation or duplicate the existing one and use it with direction: reverse
Read more here
restart animation
more info here
another article here
If you REALLY want to use just 1 animation this can be solved with javascript by removing and adding an 'animate-me' class . But it still wouldn't be ideal
div {
width: 100px;
height: 100px;
animation: fade 0.6s ease-in-out forwards;
margin: 15px;
display: inline-flex;
align-items: center;
justify-content: center;
color: white;
}
#box-1:hover {
animation: fade2 0.6s ease-in-out forwards;
animation-direction: reverse;
}
#box-2:hover {
animation: fadeReverse 0.6s ease-in-out forwards;
}
#keyframes fade {
0% { background: red; }
100% { background: blue; }
}
#keyframes fade2 {
0% { background: red; }
100% { background: blue; }
}
#keyframes fadeReverse {
0% { background: blue; }
100% { background: red; }
}
<div id="box-1">:(</div>
<div id="box-2">:)</div>

CSS - Jumpy Scale Transition Issue

I have a square wrapper with a circle inside, like on this fiddle
https://jsfiddle.net/Lazarus97/3bntmd8g/1/
<div class="card">
<div class="circle">
<p>
SOME
<br>
Text Test
</p>
</div>
</div>
<style>
body {
display: flex;
min-width: 100vw;
min-height: 100vh;
justify-content: center;
align-items: center;
margin: 0;
padding: 0;
}
.card {
width: 200px;
height: 200px;
background: #eee;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
text-align: center;
}
.circle {
background: red;
width: 150px;
height: 150px;
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
color: #fff;
transform: translateY(80px) scale(1);
transition: transform .3s ease-in; /* SAME AS ITS CHILD */
}
.circle:hover {
transform: translateY(0px) scale(3);
}
.circle * {
transition: transform .3s ease-in; /* SAME AS ITS PARENT */
}
.circle:hover *{
transform: scale(0.333333333); /* I got this number like this --> 1 / scale(3) 1/3 = 0.333333333 */
}
</style>
but notice how the text inside the circle jumps as you hover the circle, it gets bigger then smaller again, even though I did the math correctly, and created the same transition easing motion.
it should remain the original size during the transition.
Does anybody knows why this happens and is there a way to fix this?
I tried to fix it with the different transition easing motions.
"...why this happens...":
The content of your .circle scales as the .circle scale. That means that you correctly calculated that at the end of the transition, if the circle is 3 times bigger, the content needs to be 3 times smaller to stay the original size. During the transition though, at 0.5 of the transition (0.15 seconds in your case) - the circle is 2 times bigger than it originally were, while the content is 1/3 smaller (that is 2/3=0.6̅), but ALSO 2 times bigger (so it's actually 4/3=1.3̅), as it scales with the circle.
"...is there a way to fix this...":
You either need to make those two objects independent, or find the equation to calculate how smaller does the content need to be at every point in time to be exactly the same size as originally if it scales with it's parent and then apply the results to an animation property with #keyframes at every %. But that is not perfect and would probably have stuttering effect on slower devices.
At first, when you scale the element you scale all its content, and you are doing two animations, both are initiated with :hover and both are ease-in which increase the effect, you can do it softly decreasing the max scale and turning to linear the second animation, that hides very much the effect but stills not being the best.
.circle:hover {
transform: translateY(0px) scale(2);
}
.circle * {
transition: transform .3s linear; /* SAME AS ITS PARENT */
}
You should decrease de min scale too.
.circle:hover *{
transform: scale(0.5);
}
In case you decide still using scale(3), you can use calc() to the best match.
.circle:hover *{
transform: scale(calc(1/3));
}

CSS Transition after animation ends

I have a css transition that moves an element on hover and an animation that rotates the element on hover too. There's a delay on the animation equal to the transition duration so that after it's transitioned to it's correct position, the animation starts. And it works nice, however, when we mouse off, the animation stops but it doesn't transition back down.
Is it possible to get it to transition back after we mouse off and the animation ends?
You can see an example here: http://codepen.io/jhealey5/pen/zvXBxM
Simplified code here:
div {
width: 200px;
height: 200px;
margin: 40px auto;
background-color: #b00;
position: relative;
&:hover {
span {
transform: translateY(-60px);
animation-name: rotate;
animation-duration: 1s;
animation-delay: .5s;
animation-iteration-count: infinite;
animation-direction: alternate;
}
}
}
span {
position: absolute;
width: 20px;
height: 20px;
background-color: #fff;
bottom: 10px;
left: 0;
right: 0;
margin: auto;
transition: .5s;
}
#keyframes rotate {
from {
transform: translateY(-60px) rotate(0);
}
to {
transform: translateY(-60px) rotate(-90deg);
}
}
I have forked your project and adapted it so it works. You can find it here.
What I have changed is the following:
I give the white square a start position of top: 150px and let it, on hover of div, get a top: 0. The span gets a transition: top .5s and with that it goes to top: 0; on hover and back to top: 150px; when the mouse leaves.
I have removed the translateY(-60px); from the animation, because that would move it even more up when the animation would start.
Here's your new CSS:
div {
width: 200px;
height: 200px;
margin: 40px auto;
background-color: #b00;
position: relative;
&:hover {
span {
top: 0px;
animation: rotate 1s infinite .5s alternate;
animation-direction: alternate;
}
}
}
span {
position: absolute;
width: 20px;
height: 20px;
background-color: #fff;
bottom: 10px;
left: 0;
right: 0;
top: 150px;
margin: auto;
transition: top .5s;
}
#keyframes rotate {
from {
transform: rotate(0);
}
to {
transform: rotate(-90deg);
}
}
Edit: The problem is that an animation is time-based and not action-based, which means that as soon as you trigger an animation, a timer starts running and it will run through all the keyframes until the set time has passed. Hover-in and hover-out have no effect, except that the timer can be stopped prematurely, but the animation will not continue (or reversed, which you wanted) after that. transition is action-based, which means it gets triggered every time an action (for example :hover) is happening. On :hover, this means it takes .5s to go to top:0 and when the hover ends, it takes .5s to got to top:150px.
I hope the above addition makes sense :)
As you can see, I also cleaned up a bit in your animation-name: etc., since it can be combined into one line.
As Harry pointed out, the problem is that you are animating/transitioning the same property, in this case transform. It looks like the current versions of Chrome/FF will allow the animation to take control of the property, thereby breaking the transition. It seems like the only way to work around this is to transition/animation a different property. Since you need to continue rotating the element, you could translate/position the element by changing the bottom property instead. I know that doesn't produce the exact same results, but nonetheless, it does move the element (just not relative to the parent element).
Updated Example
div:hover span {
bottom: 80px;
}
As an alternative, you could also wrap the span element, and then translate that element instead.
In the example below, the .wrapper element is transitioned to translateY(-60px) on hover, and then the child span element is rotated and maintains the animation.
Example Here
div {
width: 200px;
height: 200px;
margin: 40px auto;
background-color: #b00;
position: relative;
}
div:hover .wrapper {
transform: translateY(-60px);
}
div:hover .wrapper span {
animation-name: rotate;
animation-duration: 1s;
animation-delay: .5s;
animation-iteration-count: infinite;
animation-direction: alternate;
}
.wrapper {
display: inline-block;
transition: .5s;
position: absolute;
bottom: 10px;
left: 0;
right: 0;
text-align: center;
}
.wrapper span {
display: inline-block;
width: 20px;
height: 20px;
background-color: #fff;
}
#keyframes rotate {
from {
transform: rotate(0);
}
to {
transform: rotate(-90deg);
}
}
<div>
<span class="wrapper">
<span></span>
</span>
</div>

Sync CSS keyframe color animations

Assuming I have three divs of unknown height of which one has an animated background color using a CSS keyframe animation (see http://css-tricks.com/color-animate-any-shape-2)
#-webkit-keyframes super-rainbow {
0% { background: #ffff00; }
20% { background: #ffcd00; }
40% { background: #c3d74b; }
60% { background: #c3d7d7; }
80% { background: #ffc39b; }
100% { background: #ffff00; }
}
#-moz-keyframes super-rainbow {
0% { background: #ffff00; }
20% { background: #ffcd00; }
40% { background: #c3d74b; }
60% { background: #c3d7d7; }
80% { background: #ffc39b; }
100% { background: #ffff00; }
}
Now, there are two other divs that have a white background. On hover I want those white divs to have an animated background color as well that is in sync with the permanent color animation. I am aware that a native sync isn’t supported (see How To Sync CSS Animations Across Multiple Elements?).
My first approach would be to have three divs that all have animated background colors and cover two of them with white divs, positioned relative. On hover those white divs would then turn transparent and reveal the divs with the animated background (see http://jsfiddle.net/Vzq4B)
#permanent {
height: 100px;
margin-bottom: 15px;
width: 100%;
-webkit-animation: super-rainbow 5s infinite linear;
-moz-animation: super-rainbow 5s infinite linear;
}
#hover {
position: relative;
top: -115px;
margin-bottom: -100px;
height: 100px;
width: 100%;
background: #fff;
}
#hover:hover {
background-color: transparent;
}
However, this approach will only work if I know the height of my elements, which I don’t since the content is variable.
Which other ways are there to achieve this effect for divs of unknown height?
Try placing your DIVs inside parent containers which run the animation. Child containers can then hold content and have a white background, which turns transparent using CSS on hover.
HTML:
<div id="container">
<div id="child">Your content.</div>
</div>
CSS:
#container { animation: super-rainbow 5s infinite linear; }
#child {background-color: white;}
#child:hover {background-color: transparent;}
Here’s a Fiddle http://jsfiddle.net/bejnar/Vzq4B/4/
Why don't you try this:
#hover:hover {
height: auto;
width: 100%;
outline: 1px solid #999; /* only style */
-webkit-animation: super-rainbow 5s infinite linear;
-moz-animation: super-rainbow 5s infinite linear;
cursor: pointer;
}
There is a link: http://jsfiddle.net/nmL9s/
Thanks...

Resources