CSS Animations using just Opacity and Transform - css

I read an interesting article the other day and I've been trying to apply it in my workflow.
https://blog.gyrosco.pe/smooth-css-animations-7d8ffc2c1d29#.5a2q978fv
One of the concepts that are mentioned is the idea of only animating elements with opacity and transform. I've been implementing this idea over the last few days and find it pretty awesome.
One issue I've come across is if an element is at opacity 0 the containing parent will still apply the space of the child element. I tried to remove the space with scaling the child element to almost nothing but the space is still persistent.
I was curious if anyone has worked in this manner and has advice on how to animate a parent element to grow with the child element?
function showHiddenBox() {
let hiddenBox = document.querySelector('.hiddenbox')
hiddenBox.setAttribute('data-state', hiddenBox.getAttribute('data-state') === 'hidden' ? 'visible' : 'hidden');
}
.parentbox {
width: 200px;
background-color: #564d49;
}
.showingbox {
display: flex;
align-content: flex-start;
align-items: center;
justify-content: center;
width: 100%;
height: 100px;
background-color: #63cdff;
}
.hiddenbox {
width: 100%;
height: 100px;
transition: all 1s;
background-color: pink;
}
.hiddenbox[data-state="hidden"] {
opacity: 0;
transform: scaleY(.1) translateY(-50px);
transform-origin: top;
}
.hiddenbox[data-state="visible"] {
opacity: 1;
}
<div class="parentbox">
<div class="showingbox">
<button onclick="showHiddenBox()">Click Me</button>
</div>
<div class="hiddenbox" data-state="hidden"></div>
</div>
To further explain myself I've created this snippet. I want to create an animation with just opacity and transform where the brown of the parent element doesn't show but the parent will expand when the child is created.

function showHiddenBox() {
let hiddenBox = document.querySelector('.hiddenbox')
hiddenBox.setAttribute('data-state', hiddenBox.getAttribute('data-state') === 'hidden' ? 'visible' : 'hidden');
}
.parentbox {
width: 200px;
background-color: #564d49;
}
.showingbox {
display: flex;
align-content: flex-start;
align-items: center;
justify-content: center;
width: 100%;
height: 100px;
background-color: #63cdff;
}
.hiddenbox {
width: 100%;
height: 100px;
transition: all 1s;
background-color: pink;
}
.hiddenbox[data-state="hidden"] {
max-height: 0;
transform: scaleY(.1) translateY(-50px);
transform-origin: top;
}
.hiddenbox[data-state="visible"] {
max-height: 300px;
}
<div class="parentbox">
<div class="showingbox">
<button onclick="showHiddenBox()">Click Me</button>
</div>
<div class="hiddenbox" data-state="hidden"></div>
</div>
Use max-height instead of opacity. Over exaggerate the max-height. Depends on how it will work for you. Is this what you want?

Related

CSS only - Make an animation happen in 3 steps

Code sandbox link: https://codesandbox.io/s/thirsty-moon-853e2k?file=/src/App.js:0-278
I want the pink circle to move in steps but it keeps moving in continuous fashion:
I tried using steps(3) steps(3,end) but none of that is working:
.Spinner {
height: 100vh;
width: 100vw;
background-color: gray;
display: flex;
align-items: center;
justify-content: center;
}
.DotLoader {
display: flex;
flex-direction: row;
column-gap: 0.5rem;
position: relative;
}
.DotLoader section {
height: 1rem;
aspect-ratio: 1;
border-radius: 50%;
background-color: #e5e4e5;
}
.DotLoader div {
position: absolute;
height: 1rem;
aspect-ratio: 1;
border-radius: 50%;
background-color: pink;
left: 3rem;
animation: moveSpinner 1s steps(3, end) infinite;
}
#keyframes moveSpinner {
0% {
left: 0;
}
50% {
left: 1.5rem;
}
100% {
left: 3rem;
}
}
<div class="Spinner">
<div class="DotLoader">
<div></div>
<section></section>
<section></section>
<section></section>
</div>
</div>
Can someone help me understand this and fix it?
.DotLoader div {
animation: moveSpinner 1s steps(3) infinite;
}
#keyframes moveSpinner {
0% {
left: 0;
}
100% {
left: 112%;
}
}
From what I understand... If you want to make the pink circle "move and stop" on each gray circles, you can simply delete steps(3, end). There is no need for it it just smoothly slides from one dot to another.
But if the request is making pink one just jump instead of slide, then you do not need another <div> for that, just create animations for your <section> elements individually. Light them up as pink and make them gray again.

How to make an element disappear and stay gone after hovering over it?

So here is my code...
I understand how to make the text disappear by making it transparent but i want it to stay gone after hovering over it so it doesnt come back - how do I accomplish this?
.disappear {
margin-top: 60px;
text-align: center;
transition: all 5s ease .3s;
font-family: Bungee Spice;
}
.disappear:hover {
color: transparent;
}
you need to use onmouseover and remove() like this
function bye() {
const dis = document.getElementById("dis");
dis.remove();
}
* {
padding: 0;
margin: 0;
/* border: 1px solid red; */
overflow-x: hidden;
}
div {
height: 50vh;
width: 100vw;
display: flex;
justify-content: center;
align-items: center;
font-size: xx-large;
overflow: auto;
background: lightblue;
}
<div class="div">
<h2 onmouseover="bye()" id="dis">will go on hover</h2>
</div>
I don't think it's possible to make it run smoothly with pure CSS, so far, this is what I think is close to what you want to accomplish. So before hover, the animation to make it gone is already set, but the animation is not running yet, the animation will run only if the element is hovered. The problem here is that when it's hovered then it's unhovered before it's gone, the element will be half gone as the animation is paused.
.container {
width: 100%;
height: 800px;
background: #dddddd;
}
.disappear {
margin-top: 60px;
text-align: center;
font-family: Bungee Spice;
background: yellow;
animation: example 5s linear forwards;
animation-play-state: paused;
}
.disappear:hover {
animation-play-state: running;
}
#keyframes example {
from {opacity: 1}
to {opacity: 0}
}
<div class="container">
not disappear
<div class="disappear">
DISAPPEAR
</div>
</div>
The better way would be to use javascript and use onmouseover to add the animation instead of using :hover, the difference is that when you onmouseout, the function is still executed (the animation persists). This is with JS:
function fade(elm) {
elm.style.animation = "example 5s linear forwards";
}
.container {
width: 100%;
height: 800px;
background: #dddddd;
}
.disappear {
margin-top: 60px;
text-align: center;
font-family: Bungee Spice;
background: yellow;
}
#keyframes example {
from {
opacity: 1
}
to {
opacity: 0
}
}
<div class="container">
not disappear
<div class="disappear" onmouseover="fade(this)">
DISAPPEAR
</div>
</div>

Multiple rotation directions using CSS rotateX()

I've got a simple display that flips over on click. I want to add a little bounce to the movement by rotating a few degrees in the opposite direction before rotating the full 180 degrees to reveal the opposite side.
RotateX() will accept more than one instance inline, but it calculates the end result and does not show both directions. ie:
transform: rotateX(-10deg) rotateX(190deg)
this results in the object rotating 180deg.
I've tried comma separating them, as well as just putting two sets of degress in the parens, with similar results.
I've tried putting both steps into #keyframes, but animation doesn't seem to work with my on-click event in javascript.
I've also tried having each direction of rotation in a separate class that are both activated via classlist.toggle, but still do not see both directions of rotation.
here's a codepen with the above mocked up:
https://codepen.io/Boreetos22/pen/WNrJEvR
I'd appreciate any insight. Thanks!
Transitions probably won't get what you want since you can't fake the bounce with multiple steps. #keyframes will work but you can't simply toggle the class. You need to add one and then add another to reset it.
Also, you'll need multiple animations (forward and back) that you change on over/out and click.
let sides = document.querySelector('.sides');
sides.addEventListener( 'click', function(e) {
if(sides.classList.contains('flip-forward')){
sides.classList.remove('flip-forward');
sides.classList.add('flip-backward');
}else{
sides.classList.add('flip-forward');
sides.classList.remove('flip-backward');
}
});
* {
padding: 0;
margin: 0;
}
h2 {
margin-top: 12px;
font-size: 30px;
}
body {
height: 100vh;
width: 100vw;
display: flex;
justify-content: center;
align-items: center;
}
.container {
display: flex;
justify-content: center;
height: 60px;
width: 400px;
perspective: 1000px;
}
#keyframes myAnimationFwrd {
/* has bounce */
24% {
transform: rotateX( -40deg)
}
36% {
transform: rotateX( 0)
}
100% {
transform: rotateX( 190deg)
}
}
#keyframes myAnimationBkwrd {
/* no bounce add more steps to enable */
0% {
transform: rotateX( 190deg)
}
100% {
transform: rotateX( 0deg)
}
}
.flip-forward {
animation: myAnimationFwrd 1s forwards;
}
.flip-backward {
animation: myAnimationBkwrd 1s forwards;
}
.sides {
height: 100%;
width: 100%;
display: flex;
justify-content: center;
position: relative;
transform-style: preserve-3d;
cursor: pointer;
}
.red, .black {
text-align: center;
color: white;
height: 100%;
width: 100%;
border-radius: 30px;
box-shadow: 2px 2px 4px black;
position: absolute;
backface-visibility: hidden;
}
.red {
background-color: darkred;
z-index: 2;
}
.black {
background-color: black;
z-index: 1;
transform: rotateX(180deg);
}
<div class="container">
<div class="sides">
<div class="red">
<h2>PLAYER ONE'S TURN</h2>
</div>
<div class="black">
<h2>PLAYER TWO'S TURN</h2>
</div>
</div>
</div>

How to set absolute positionning in react component

i'm trying to create a custom button for my portfolio.
This button will be animated, the top part sliding in from left and the bottom part sliding in from right when hovered.
At the center of it will be the Category linked to this button.
Here an illustration :
How can i set my text in the center for every that i will create ? I can't use "position: absolute" property cause the reference would be the webpage and not the position where the custom component is declared...
Here my actual code :
CSS
const CatStyle = styled.div`
box-shadow: 0px 0px 2px 2px rgba(0,0,0,0.75);
height: 50px;
max-width: 150px;
background-color: white;
display: flex;
justify-content: center;
flex-direction: column;
cursor: pointer;
transition : background-color 0.5s ease-out;
:hover div{
display: flex;
}
.catContent {
position: relative;
align-self: center;
font-size: 1.5rem;
}
.topSlideAnimation {
display: none
height: 50%;
background-color: green;
}
.botSlideAnimation {
transition : background-color 0.5s ease-out;
display: none;
height: 50%;
background-color: blue;
}
`
JSX
const ButtonCat = (props) => (
<CatStyle>
<div className="topSlideAnimation"></div>
<div className="catContent">Hello</div>
<div className="botSlideAnimation"></div>
</CatStyle>
)
Not done any jsx so not sure what your catstyle tag would render, but if you can just render a button (or div), I would do the following
Make an outer container that is flex (for aligning text in center)
Make an inner container that is for the text (so you can position it relatively and add a z-index to it)
Add pseudo elements to your outer container for the animated bits (rather than having 2 empty divs)
* {
box-sizing: border-box;
}
.button {
display: inline-flex; /* make flex for centring */
justify-content: center; /* vertically centre */
align-items: center; /* horizontally centre */
position: relative; /* for adding absolute positioned children */
min-height: 50px; /* test value to show text is centred */
overflow: hidden; /* hide pseudo elements when not shown */
}
.button:before,
.button:after {
content: ''; /* make coloured animatable bits */
display: block;
height: 50%;
width: 100%;
position: absolute;
transition: all 1s ease-in;
z-index: 1;
}
.button:before {
top: 0;
right: 100%;
background: grey;
}
.button:hover:before {
right: 0;
}
.button:after {
top: 50%;
left: 100%;
background: darkgrey;
}
.button:hover:after {
left: 0;
}
.text {
position: relative; /* needs to have a higher z-index than the pseduo elements so text appears on top */
z-index: 2;
}
<button class="button"><span class="text">test content</span></button>

Unwanted effect with CSS animation hover happening a second time on each child

When applying a CSS transform based on a hover for my element which contains a title a summary and some other elements, all the children elements would move a second time when I hover over them inside the element.
Basically, the parent and its children(title, highlight...) will be animated a first time when I hover over it. (this is the intended behaviour).
But, if I hover over the title, it will apply the animation to the title individually, a second time. So, the title would be transformed a first time, let's say going up by 10px, and when I hover over it, it will go up again by 10 other pixels. The outer div (parent) will move only once. (Unwanted)
It is like I have applied their own animations to the parent and each one of the children.
I tried to apply transform: none; to all the children elements, but, it does not help in my case.
CSS:
.badge {
flex-basis: 50%;
transform: translateY(0);
transition-duration: 1s;
transition-property: transform;
transition-timing-function: ease-out;
transition-delay: 1s;
backface-visibility: hidden;
}
.badge:last-child {
flex-basis: 100%;
}
.badge :hover {
transform: translateY(-8px);
}
.badge__badge {
margin-bottom: 40px;
margin-right: 40px;
width: 99%;
height: 200px;
background-color: rgb(27, 139, 45);
border-radius: 8px;
color: aliceblue;
box-shadow: 0 4px 2px -2px rgba(0,0,0,0.4);
}
.badge__prime {
margin-left: 20px;
margin-right: auto;
}
.badge__content {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
position: relative;
}
.badge__icon {
width: 40px;
height: auto;
margin: 10px;
}
.badge__highlight {
margin-right: auto;
margin-left: 30px;
display: flex;
flex-direction: column;
}
JSX (React):
<div className="badge">
<div className="badge__badge"
style={{ backgroundColor: this.props.backgroundColor }}>
<div className="badge__content">
{this.props.prime ? <h4 className="badge__prime">PRIME</h4>
: <h4 className="badge__prime">Free</h4>}
<h2 className="badge__title">{this.props.titleBadge}</h2>
<div className="badge__highlight">
{this.props.highlightBadge.split('\n').map((i, key) => {
return <div key={key}>{i}</div>;
})}
</div>
</div>
<img className="badge__icon"alt="" src={this.props.iconBadge} />
</div>
</div>
Expected results: the parent div and all its children will animate once on hover and will come back to their state once the mouse is outside of the div.
Actual results: The parent div and all its children animate once on hover, and the children will animate again if the mouse is over one of them.
Link to a jsfiddle that shows my issue

Resources