Using css :hover with map() method only working on first element - css

I am creating an app in React and I'm building the menu using an array and the map() method.
I have my navigation buttons displaying correcting and when hovering over the button, the colour changes, however, the transition only works on the first button, when you hover over the other buttons only the colour changes.
Here is my code:
const buttons = ["Button 1", "Button 2", "Button 3", "Button 4", "Button 5"];
{buttons.map((name) => (
<NavButton
key={name}
onMouseEnter={() => setHovered(name)}
onMouseLeave={() => setHovered(!name)}
onClick={() => handleToggle(name)}
className={classNames("george", {
// active: navButtonClicked === name && activeButton === true, //If you just want to make the clicked button have the class active
// active: activeButton === true, //If you want to make all buttons active
// hovered: hovered === name,
})}
>
{name}
</NavButton>
))}
CSS
const NavButton = styled.div`
//Border
border-radius: 100%;
//Colour
color: white;
background: #3498db;
//Positioning
position: absolute;
top: 25px;
left: 25px;
z-index: 1;
//Sizing
width: 60px;
height: 60px;
//Text
text-align: center;
line-height: 60px;
//Transitions
transition: transform ease-out 200ms;
&:hover {
background-color: blue;
transition-duration: 50ms;
transform: scale(1.2, 1.2) translate3d(0, 0, 0);
}
&:nth-child(1) {
//Positioning
z-index: 2;
}
&.active :nth-child(2) {
//Positioning
transition-duration: 50ms;
transform: translate3d(0, 85px, 0);
}
&.active :nth-child(3) {
transition-duration: 100ms;
transform: translate3d(0, 170px, 0);
}
&.active :nth-child(4) {
transition-duration: 150ms;
transform: translate3d(0, 255px, 0);
}
&.active :nth-child(5) {
transition-duration: 200ms;
transform: translate3d(0, 340px, 0);
}
`;
Am i not understanding something correctly?

Related

How to reverse animation when prop is false styled components

I am passing a open prop to styled component to create animations for the hamburger icon.
This is the code
const StyledBurger = styled.button`
display: flex;
flex-direction: column;
justify-content: center;
border: 0;
background-color: ${colors.cobaltBlue};
border-radius: 2.7px;
cursor: pointer;
div {
width: 27px;
height: 3px;
margin: 1.5px;
transition: all 0.2s linear;
border-radius: 1.4px;
background-color: ${colors.white};
:first-child {
${({ open }) => open && firstOpenAnimation};
}
:nth-child(2) {
opacity: ${({ open }) => (open ? '0' : '1')};
}
:nth-child(3) {
${({ open }) => open && seconOpenAnimation}
}
}
`;
const firstOpenKeyframe = keyframes`
50% {
transform: translateY(6px) rotate(0);
}
100% {
transform: translateY(6px) rotate(45deg);
}
`;
const secondOpenKeyframe = keyframes`
50% {
transform: translateY(-6px) rotate(0);
}
100% {
transform: translateY(-6px) rotate(-45deg);
}
`;
const firstCloseKeyFrame = keyframes`
50% {
transform:translateY(0) rotate(-45deg);
}
100% {
transform:translateY(-6px) rotate(-45deg) ;
}
`;
const firstOpenAnimation = css`
animation: 0.3s linear ${firstOpenKeyframe} forwards;
`;
const seconOpenAnimation = css`
animation: 0.3s linear ${secondOpenKeyframe} forwards;
`;
const firstCloseAnimation = css`
animation: 0.3s linear ${firstCloseKeyFrame} forwards;
`;
export default StyledBurger;
Basically what I want is if the menu is not open to reverse the animation that was created after the first click.
I tried doing a conditional render of animation keyframe based on the prop open but what happens is when the page loads it immediately creates the animation of not is opened because it satisfies false.
What can I do to fix this and create the opposite animation when unClicked
Make few corrections and it should all work properly.
use state to toggle open and send it as prop to your styled component
use ternary for animation (not just &&) ${({ open }) => (open ? firstOpenAnimation : firstCloseAnimation)}.
implement missing close second animation
working copy of your code is here
Working code snippet
const StyledBurger = styled.button`
display: flex;
flex-direction: column;
justify-content: center;
border: 0;
background-color: red;
border-radius: 2.7px;
cursor: pointer;
height: 30px;
div {
width: 27px;
height: 3px;
margin: 1.5px;
transition: all 0.2s linear;
border-radius: 1.4px;
background-color: white;
:first-child {
${({ open }) =>
open !== null && (open ? firstOpenAnimation : firstCloseAnimation)}
}
:nth-child(2) {
opacity: ${({ open }) => (open ? "0" : "1")};
}
:nth-child(3) {
${({ open }) =>
open !== null && (open ? seconOpenAnimation : secondCloseAnimation)}
}
}
`;
const firstOpenKeyframe = keyframes`
50% {
transform: translateY(6px) rotate(0);
}
100% {
transform: translateY(6px) rotate(45deg);
}
`;
const secondOpenKeyframe = keyframes`
50% {
transform: translateY(-6px) rotate(0);
}
100% {
transform: translateY(-6px) rotate(-45deg);
}
`;
const firstCloseKeyFrame = keyframes`
50% {
transform:translateY(0) rotate(-45deg);
}
100% {
transform:translateY(0) rotate(0) ;
}
`;
const secondCloseKeyFrame = keyframes`
50% {
transform:translateY(0) rotate(-45deg);
}
100% {
transform:translateY(0) rotate(0) ;
}
`;
const firstOpenAnimation = css`
animation: 0.3s linear ${firstOpenKeyframe} forwards;
`;
const seconOpenAnimation = css`
animation: 0.3s linear ${secondOpenKeyframe} forwards;
`;
const secondCloseAnimation = css`
animation: 0.3s linear ${secondCloseKeyFrame} forwards;
`;
const firstCloseAnimation = css`
animation: 0.3s linear ${firstCloseKeyFrame} forwards;
`;
export default function App() {
const [open, setOpen] = useState(null);
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<StyledBurger onClick={() => setOpen(prev => !prev)} open={open}>
<div />
<div />
<div />
</StyledBurger>
</div>
);
}

I am unable to animate a popup during entry, but cannot animate during exit

The code below triggers the popup in react, which enters when a user clicks a new order button in the interface. There is a button that whne clicked, the popup exits, but without animating
export const NewOrder = () => {
const [selected, setSelected] = useState(false);
const newOrder = () => {
setSelected(!selected);
};
return (
<Fragment>
<div className='dashboard-main-neworder' onClick={newOrder}>
<img alt='New Order' src={addorder}></img>
<span>New Order</span>
</div>
{selected && <NewOrderForm />}
</Fragment>
);
};
This is the animation
#keyframes popup {
0% {
top: -100%;
opacity: 0;
}
70% {
top: 60%;
}
100% {
top: 50%;
opacity: 1;
}
}
assignment in class is here
.popup {
width: 55rem;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 999;
background: #ffffff;
border-radius: 1rem;
transition: all 0.2s ease-in-out;
animation: popup ease 0.5s;
That's kinda hard to do because when you unmount a component using react it just removes it from the tree, my suggestion would be using something like react-transition-group

CSS Transition timing of two separate elements off in Chrome

How can I fix this timing issue in chrome? In firefox, the closing animation goes smoothly but in chrome the two elements are off. I cannot place the elements in one container to transition.
notice the white border between the off canvas and the button in the slide. They are a bit off.
$(document).ready(function () {
var OffCanvasWidget = {
options: {
id: 'OffCanvasWidget',
trigger: $('[data-offcanvas-trigger]'),
close: $('[data-offcanvas-close]')
},
init: function () {
this.addListeners();
},
addListeners: function () {
var that = this;
this.options.trigger.on('click', function (event) {
event.preventDefault();
that.toggleOffCanvas();
});
},
toggleOffCanvas: function () {
$('body').toggleClass('offcanvas-show');
}
};
OffCanvasWidget.init();
});
.trigger {
transition: transform .7s ease;
display: inline-block;
transform: rotate3d(0, 0, 1, -90deg) perspective(1px) scale(1.001);
position: fixed;
right: -22px;
top: 30vh;
}
.offcanvas-show .trigger {
transform: translateX(-218px) rotate3d(0, 0, 1, -90deg) perspective(1px) scale(1.001);
}
.offcanvas {
transform: translateX(100%);
position: fixed;
transition: transform .7s ease;
top: 0;
right: 0;
bottom: 0;
left: auto;
width: 200px;
}
.offcanvas-show .offcanvas {
transform: translateX(0);
}
.trigger, .offcanvas {
background-color: black;
color: white;
padding: 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<a href="#" class="trigger" data-offcanvas-trigger>Follow us</a>
<div class="offcanvas">
</div>
Why not just make the 'tab' element a little wider so it 'underlaps' the tray enough so as to not notice any gap :)

Looking for improvement of slide down animation with angular.js

I do have a running code sample (http://jsfiddle.net/Fuunq/) which shows a slide down animation using angular.js (1.2.0). But there are two issues that I don't know how to solve:
a) When clicking on the 'Add item' link, the animation first moves down the 'Add item' link and then slides in the new item from the top. How can this be changed, that the 'Add item' link slides down together with the new appearing item?
b) How can I prevent that the items do fade in when the page gets loaded for the first time?
HTML
<div ng-controller="MyCtrl">
<div ng-repeat="item in items" class="animation-slide-down">
<div class="item">
<div>Name: {{item.name}}</div>
<div>Color: {{item.color}}</div>
</div>
</div>
Add item
</div>
CSS
.item {
margin-top: 5px;
padding: 15px;
background-color: #34ac54;
border: 1px solid black;
}
#-webkit-keyframes slide_down {
0% {
-webkit-transform: translateY(-100%);
opacity: 0;
z-index: -100;
}
99% {
z-index: -100;
}
100% {
-webkit-transform: translateY(0);
opacity: 1;
z-index: 0;
}
}
#keyframes slide_down {
0% {
transform: translateY(-100%);
opacity: 0;
z-index: -100;
}
99% {
z-index: -100;
}
100% {
transform: translateY(0);
opacity: 1;
z-index: 0;
}
}
.animation-slide-down.ng-enter {
-webkit-animation: slide_down 3s ease-in;
animation: slide_down 4s ease-in;
}
JS
var myApp = angular.module('myApp', ['ngAnimate']);
function MyCtrl($scope) {
$scope.name = 'foo';
$scope.items = [
{name: 'Item 1', color: 'blue'},
{name: 'Item 2', color: 'red'}
]
$scope.addItem = function() {
$scope.items.push({name: 'Another item', color: 'black'})
}
}
Thanks for your help!
a) as far as i know this can only be achieved with a negative margin-top transitions to your target value 5px. There is one problem with this: you have to know the exact height of one item.
#-webkit-keyframes slide_down {
0% {
margin-top: -68px;
opacity: 0;
z-index: -100;
}
99% {
z-index: -100;
}
100% {
margin-top:5px;
opacity: 1;
z-index: 0;
}
}
b) you can use the $animate service. The service has an enabled method, so you may disable or enable the animations at any time. here is your controller code that disables the animation on start and after the start enables the animation. the trick is the $timeout service. with that you defer activating the animations until the next digest cycle happens:
function MyCtrl($scope, $animate, $timeout) {
$animate.enabled(false);
$scope.name = 'foo';
$scope.items = [
{name: 'Item 1', color: 'blue'},
{name: 'Item 2', color: 'red'}
]
$scope.addItem = function() {
$scope.items.push({name: 'Another item', color: 'black'})
}
$timeout(function(){
$animate.enabled(true);
});
}
here is the working example:
http://jsfiddle.net/CKF47/

Animation on click

I just started fooling around with CSS. Im trying to make an animation (menu drop down) that should trigger on a button click. I found a good example, but in triggers on the hoover event and changes the style of a couple of divs.
I guess I need to set the style when my button is clicked, and then change it back when it is clicked again. But I cant get it to work.
Here is the CSS:
/* Static state */
#container {
width: 400px;
height: 400px;
position: relative;
border: 1px solid #ccc;
}
.parent1 {
/* overall animation container */
height: 0;
overflow: hidden;
-webkit-transition-property: height;
-webkit-transition-duration: .5s;
-webkit-perspective: 1000px;
-webkit-transform-style: preserve-3d;
-moz-transition-property:height;
-moz-transition-duration: .5s;
-moz-perspective: 1000px;
-moz-transform-style: preserve-3d;
-o-transition-property: all;
-o-transition-duration: .5s;
-o-transform: rotateX(-90deg);
-o-transform-origin: top;
transition-property: height;
transition-duration: .5s;
perspective: 1000px;
transform-style: preserve-3d;
}
.parent2 {
/* full content during animation *can* go here */
}
.parent3 {
/* animated, "folded" block */
height: 56px;
-webkit-transition-property: all;
-webkit-transition-duration: .5s;
-webkit-transform: rotateX(-90deg);
-webkit-transform-origin: top;
-moz-transition-property: all;
-moz-transition-duration: .5s;
-moz-transform: rotateX(-90deg);
-moz-transform-origin: top;
-o-transition-property: all;
-o-transition-duration: .5s;
-o-transform: rotateX(-90deg);
-o-transform-origin: top;
transition-property: all;
transition-duration: .5s;
transform: rotateX(-90deg);
transform-origin: top;
}
/* Hover states to trigger animations */
#container:hover .parent1 { height: 111px; }
#container:hover .parent3 {
-webkit-transform: rotateX(0deg);
-moz-transform: rotateX(0deg);
-o-transform: rotateX(0deg);
transform: rotateX(0deg);
height: 111px;
}
And here is what I been working on.....
<script>
function fold()
{
var element = document.getElementById('parent1');
element.style.height= 111;
element = document.getElementById('parent3');
var prop = getTransformProperty(element);
element.style[prop] = 'rotateX(0deg)';
element.style.height= 111;
}
function getTransformProperty(element)
{
// Note that in some versions of IE9 it is critical that
// msTransform appear in this list before MozTransform
var properties = [
'transform',
'WebkitTransform',
'msTransform',
'MozTransform',
'OTransform'
];
var p;
while (p = properties.shift()) {
if (typeof element.style[p] != 'undefined') {
return p;
}
}
return false;
}
</script>
Any ideas?
You could save a lot of time and effort using -
jQuery UI accordion
<script>
$(function() {
$(".accordion").show().accordion({
heightStyle: "content",
collapsible: true,
active: false,
animate: {
duration: 1000,
easing: 'easeOutBounce'
},
});
})
</script>
Note that you can style this plugin any way you like,
.accordion {/* some style*/}
.ui-accordion-content {/* some style*/}
.accordion h6 {/* some style*/}
Here is a fiddle that shows how I've abused the accordion widget.
HERE IT IS EASY : JSFiddle
HTML
<ul>
<li>Something</li>
<li>Something Else</li>
<li>Another Thing</li>
<li>Or This</li>
</ul>
<br>
<br>
<h3>
Dropdown Example -
Amir Mehdi
</h3>
Javascript
$("div , li").click(function () {
$("ul").slideToggle(120);
});

Resources