I'm trying to recreate a marquee tag using CSS animations. Works fine in Chrome and Firefox, but for some reason in Safari(12.0.1), the animation either won't play or won't play correctly until I switch tabs.
Here's my CSS:
.marquee{
width:100%;
background-color:rgba(56, 38, 48, .8);
white-space:nowrap;
overflow:hidden;
box-sizing:border-box;
height:51px;
}
.marquee p {
display: inline-block;
padding-left: 100%;
animation: marquee 120s linear -3s infinite;
-webkit-animation: marquee 120s linear -3s infinite;
color: white;
}
#-keyframes marquee {
0% { transform: translate(0,0); }
100% { transform translate(-100%, 0); }
}
#-webkit-keyframes marquee {
0% { -webkit-transform: translate(0, 0); }
100% { -webkit-transform: translate(-100%, 0); }
}
HTML: This is a React application. Before the component mounts, it fetches a group of tickers and their values, then feeds them into a component that renders them:
componentWillMount(){
const params = {
method:'POST',
body:'key=1234567',
headers: {
"Content-type":"application/x-www-form-urlencoded; charset=UTF-8"
},
}
fetch('/tickers', params)
.then(res => res.json())
.then(data => {
const tickers = Object.assign({}, data)
this.setState({tickers})
console.log(this.state.tickers)
}
)
.catch(err => {
console.log(`could not fetch: ${err}`)
})
}
The tickers then get fed into this component where the marquee effect is being applied:
const Tickerbar = (props) => {
const displayNameStyle = {
color:'white',
}
const midStyle = {
color:'#CDBFBF',
marginRight:'20px'
}
const displayNames = Object.keys(props.tickers)
const displayNameAndMid = displayNames.map(cusip => {
return(
<span key={cusip}>
<span style={displayNameStyle}>
<b>{cusip.split('/').join('.')}:</b>
</span>
<span style={midStyle}>
<b>{(props.tickers[cusip]).toFixed(2)}</b>
</span>
</span>
)
})
return(
<div className="marquee">
<p>
{displayNameAndMid}
</p>
</div>
)
}
For reference, I am running macOS High Sierra 10.13.6
EDIT: I made a separate HTML markup using the same CSS, and it works fine. So I believe the problem has to do with getting the data from the database and rendering it to the component
EDIT: I seem to have some success adding by adding a 1 second delay to the animation time. I guess this gives the component time to fetch the tickers and render the animation.
Related
With below code I can have a transition but two issues
the transition seem to be going the wrong way than what i defined (right to left instead of left to right).
It is supposed to transition the old widget while the new one enters but it is replacing immediately the old one with the new one then the transition begins.
by swapping .fadeEnterActive with .fadeExitActive I had the second issue fixed. but the entering element now starts with .fadeEnterDone className for some reasons.
Can one spot the issue?
how can i fix that
import { useRef, useState } from "react";
import { SwitchTransition, CSSTransition } from "react-transition-group";
import PayContainer from "../payContainer";
import PersonalInfoForm from "../persnalInfoForm";
import styles from './drawer_container.module.scss'
export default function DrawerContainer() {
const [state, setState] = useState('pay-fill');
const payRef = useRef(null);
const personalInfoRef = useRef(null);
const previewRef = useRef(null);
const nodeRef = () => {
switch (state) {
case 'pay-fill':
return payRef
case 'personalinfo-fill':
return personalInfoRef
case 'preview':
return previewRef
default:
return null;
}
}
const setActiveState = (curState: string) => {
setState(curState)
}
const getWidget = () => {
switch (state) {
case 'pay-fill':
return <PayContainer setState={setActiveState}/>
case 'personalinfo-fill':
return <PersonalInfoForm />
case 'preview':
return <div>preview nigga</div>
default:
return <div>default</div>;
}
}
return <div className="w-full h-full">
<SwitchTransition mode={'out-in'}>
<CSSTransition
key={state}
nodeRef={nodeRef()}
addEndListener={(done: () => void) => {
nodeRef()?.current?.addEventListener("transitionend", done, false);
}}
// in={focus}
timeout={500}
classNames={{
enterActive: styles.fadeEnterActive,
enterDone: styles.fadeEnterDone,
exitActive: styles.fadeExitActive,
exitDone: styles.fadeExitDone
}}
>
<div ref={nodeRef()} className={['w-full h-full', styles.fade].join(' ')}>
{getWidget()}
</div>
</CSSTransition>
</SwitchTransition>
</div>;
}
styles
.fadeEnterActive {
opacity: 0;
transform: translateX(-100%);
}
.fadeEnterDone {
opacity: 1;
transform: translateX(0%);
}
.fadeExitActive {
opacity: 1;
transform: translateX(0%);
}
.fadeExitDone {
opacity: 0;
transform: translateX(100%);
}
.fadeEnterActive,
.fadeExitActive {
transition: opacity 500ms, transform 500ms;
}
.fade {
}
By looking at the react-transition-group documentation, I am guessing that the problem is occurring because the starting point of the transition for fade-enter and fade-exit is not defined. And also the styles of fadeEnterActive and fadeExitActive that you provided seem to be in opposite directions.
This code should work.
React snippet
<SwitchTransition mode={'out-in'}>
<CSSTransition
key={state}
nodeRef={nodeRef()}
addEndListener={(done: () => void) => {
nodeRef()?.current?.addEventListener("transitionend", done, false);
}}
// in={focus}
timeout={500}
classNames={{
enterActive: styles.fadeEnterActive,
enter: styles.fadeEnter,
exitActive: styles.fadeExitActive,
exit: styles.fadeExit
}}
>
<div ref={nodeRef()} className={['w-full h-full', styles.fade].join(' ')}>
{getWidget()}
</div>
</CSSTransition>
</SwitchTransition>
Styles
.fadeEnter {
opacity: 0;
transform: translateX(-100%);
}
.fadeEnterActive {
opacity: 1;
transform: translateX(0%);
}
.fadeExit {
opacity: 1;
transform: translateX(0%);
}
.fadeExitActive {
opacity: 0;
transform: translateX(100%);
}
.fadeEnterActive,
.fadeExitActive {
transition: opacity 500ms, transform 500ms;
}
So sometimes I would group 2 selectors in the className at the same time like <div className="slectorA selectorB" /> which would render .selectorA .selectorB { (...) } in the CSS file if I am not mistaken.
I was wondering how to do that if I were to use a CSS module. Define styles = './App.module.css' then how would I do the same call as before? Here is an example of what I am trying to do in my code.
App.js
import styles from "./App.module.css";
const manageBackgroundImage = (temperature) => {
if (temperature > 16) return "{styles.weather_box.warm}";
else return "{styles.weather_box.cold}";
//(...more else ifs here...)
};
export default function App() {
const temperature = 17;
return (
<div>
<div className={manageBackgroundImage(temperature)}></div>
</div>
);
}
App.module.css
.weather_box {
display: grid;
width: 40%;
height: inherit;
}
.weather_box.cold {
background-image: url('../../assets/cold.png');
transition: 0.6s ease-out;
}
.weather_box.warm {
background-image: url('../../assets/warm.png');
transition: 0.6s ease-out;
}
App.js
import styles from "./App.module.css";
const manageBackgroundImage = (temperature) => {
if (temperature > 16) return `${styles.weather_box} ${styles.warm}`;
else return `${styles.weather_box} ${styles.cold}`;
};
I've currently made a carousel component, I'm passing my data to it but I would like to add a transition between switching the data.
I've heard a lot of people recommending react-spring so I thought I'd give it a try. I'm currently trying to implement the useTransition hook, but it's not working as desired.
I simply want to fade in/out only the data when the user presses the "left" / "right" buttons. Currently it starts to fade my content, but then creates a clone of my carousel, and doesn't fade... I'm not sure what I'm doing wrong or if this is the correct hook I should be using?
Ultimately I would prefer a stagger animation when the content fades
in with some delay between each element. For example: the title, then price, then
desciption, etc, would fade in but with a 300ms delay between each
element.
Here's what I currently have:
const mod = (n: any, m: any) => ((n % m) + m) % m;
const CarouselContainer: React.FC = () => {
const [index, setIndex] = useState(0);
const handlePrev = useCallback(() => {
setIndex(state => mod(state - 1, data.length));
}, [setIndex]);
const handleNext = useCallback(() => {
setIndex(state => mod(state + 1, data.length));
}, [setIndex]);
const transitions = useTransition([index], (item: number) => item, {
from: { opacity: 0 },
enter: { opacity: 1 },
leave: { opacity: 0 }
});
return (
<>
{transitions.map(({ item, props, key }) => (
<Carousel
prevClick={handlePrev}
icon={data[item].icon}
title={data[item].title}
price={data[item].price}
description={data[item].description}
href={data[item].href}
nextClick={handleNext}
style={props}
key={key}
/>
))}
</>
);
};
There's quite a lot of code so I'm providing a CodeSandBox, forks are appretiated! :)
When the mount and unmount happens during the transition, there is a moment when the new and the old element is in the dom simultaneously. Most of the time I use absolute positioning with transition for this reason. This way the change blend in well.
For this you have to change to position: absolute here:
const StyledWrapper = styled.div`
position: absolute;
display: grid;
grid-template-columns: auto auto 20% 20% 1fr auto auto;
grid-template-rows: 3em 1fr auto 1fr 3em;
grid-gap: 0;
`;
I would try to add some movement to it:
const transitions = useTransition([index], (item: number) => item, {
from: { opacity: 0, transform: 'translateX(-420px)' },
enter: { opacity: 1, transform: 'translateX(0px)' },
leave: { opacity: 0, transform: 'translateX(420px)' }
});
And here is your modified code:
https://codesandbox.io/s/empty-rgb-xwqh1
Next you will want to handle the direction of the movement, according to the button pressed. Here is an example for that: https://codesandbox.io/s/image-carousel-with-react-spring-usetransition-q1ndd
I'm new to React and I'm looking for some help.
I'm trying to build a simple login page. The page gives users three options ('sign in with email', 'sign in with Google', or 'sign up') and displays a component based on the option chosen.
I wanted to add a simple cross-fade as these components enter and exit the DOM so I turned to react-transition-group.
The problem, however, is my components don't exit and enter properly. The old component appears to disappear instantly rather than fade out, two copies of the 'new' component are stacked on top of each other. One fades out and the other fades in. The old and new don't elegantly cross-fade into each other as I would like.
Example:
Initial login page
On click, two copies of the 'new' component appear, one fades in and the other fades out
transition completes and container now holds the new component as desired
I've looked over the docs for react-transition-group but I can't quite figure out what I'm doing wrong.
Here's my main component:
class LoginPage extends React.Component {
constructor(props) {
super(props);
this.state = {
display: "loginInitial"
}
};
handleEmailLogin = () => {
this.setState(() => ({
display: "emailLogin"
}))
};
handleGoogleLogin = () => {
console.log("Logging in with google!")
this.props.startGoogleLogin()
};
handleEmailSignUp= () => {
this.setState(() => ({
display: "emailSignUp"
}))
};
handleBackToStart = () => {
this.setState(() => ({
display: "loginInitial",
}))
}
displayBox = () => {
if (this.state.display === "loginInitial") {
return <LoginPageInitial
handleEmailLogin={this.handleEmailLogin}
handleGoogleLogin={this.handleGoogleLogin}
handleEmailSignUp={this.handleEmailSignUp}
/>
} else if (this.state.display === "emailSignUp") {
return <LoginPageEmailSignUp
handleBackToStart={this.handleBackToStart}
/>
} else if (this.state.display === "emailLogin") {
return <LoginPageEmailLogin
handleBackToStart={this.handleBackToStart}
/>
}
}
render() {
return (
<div className="box-layout">
<div className="box-layout__box">
<h1 className="box-layout__title">My app</h1>
<p>Subtitle goes here blah blah blah blah.</p>
<TransitionGroup>
<CSSTransition
classNames="fade"
timeout={600}
key={this.state.display}
>
{this.displayBox}
</CSSTransition>
</TransitionGroup>
</div>
</div>
)
};
}
const mapDispatchToProps = (dispatch) => ({
startGoogleLogin: () => dispatch(startGoogleLogin())
})
export default connect(undefined, mapDispatchToProps)(LoginPage)
And here's the relevant CSS:
.box-layout {
align-items: center;
background: url('/images/bg.jpg');
background-size: cover;
display: flex;
justify-content: center;
height: 100vh;
width: 100vw;
}
.box-layout__box {
background: fade-out(white,.15);
border-radius: 3px;
text-align: center;
width: 30rem;
padding: $l-size $m-size
}
.box-layout__title {
margin: 0 0 $m-size 0;
line-height: 1;
}
// FADE
// appear
.fade-appear {
opacity: 0;
z-index: 1;
}
.fade-appear.fade-appear-active {
opacity: 1;
transition: opacity 600ms linear;
}
// enter
.fade-enter {
opacity: 0;
z-index: 1;
}
.fade-enter.fade-enter-active {
opacity: 1;
transition: opacity 600ms linear;
}
// exit
.fade-exit {
opacity: 1;
}
.fade-exit.fade-exit-active {
opacity: 0;
transition: opacity 600ms linear;
}
I would be extremely appreciative if anyone can offer some advice. I've done a lot of googling but I can't find a solution to my problem.
[EDIT: MOSTLY SOLVED - I managed to solve the bulk of my problem. It appears I needed to place my 'key' prop in my component rather than component. Two versions of the 'new' component no longer appear and the container doesn't stretch. It does appear, however, that the 'old' component still doesn't fade out as I expected. It looks a lot better than it did though. I welcome any further insight on what I was/am doing wrong or how I can improve my code.)
I have few images which I need to zoom little bit (using CSS i.e. transform : scale(1.2);) on onMouseEnter and revert on onMouseLeave.
I have below code which is working.
CSS:-
.style {
transform : scale(1.2);
transition: transform .5s ease-out;
}
.shrink {
transform : scale(1);
transition: transform .5s ease-out;
}
Variable Declared in constructor:-
this.state = {
isHovered: false
};
JS Method:-
handleHover(){
this.setState({
isHovered: !this.state.isHovered
});
}
logical op in render method:-
const imgClass = this.state.isHovered ? 'profile-pic style' : 'profile-pic shrink';
And two images:-
<Image title ='one' src="pics/pic1.png" circle className={imgClass}
onClick={ () => this.props.methodRef('one')} height="70" width="100"
onMouseEnter={this.handleHover} onMouseLeave={this.handleHover}/>
<Image title ='two' src="pics/pic2.png" circle className={imgClass}
onClick={ () => this.props.methodRef('two') } height="70" width="100"
onMouseEnter={this.handleHover} onMouseLeave={this.handleHover}/>
This code is working perfectly as I am expecting it to be. But the problem is both the images are zooming in and out at the same time.
How can I differentiate mouse movement over different-different elements in ReactJs.
You can wrap the Image components into one of your own that you can control and add states to. Or maybe another way would be to have an array in your parent component like:
state: {
images:[{id: "image1", isHovered: false},
{id:"image2", isHovered: false}]
}
So you can have your ids in the components:
<Image id={this.state.images[0].id} ...rest />
then handleHover:
handleHover(e) => {
const images = [...this.state.images]; //copy your array
const index = images.findIndex(el => (el.id === e.target.id));
images[index].isHovered = !images[index].isHovered;
this.setState({images});
}
This is overly complex, though. You should wrap it inside another component and manage state from there.