I have some problems with rendering animation on my nextjs app with a tailwind. Namely, I have just a simple animation that makes the logo smaller on scroll, but it seems it lags on Android devices. I have tested from 2 different iPhones, a few laptops and three android phones (Samsung Note10, Flex 4 and some Xioami). Only on android happens that is lagging.
So what I'm doing is (first check scroll position) (it shouldn't be a problem)
useEffect(() => {
window.addEventListener('scroll', stickNavbar);
return () => window.removeEventListener('scroll', stickNavbar);
}, []);
useEffect(() => {
offsetX < 1024 ? offsetY > 40 ? setScroll(true) : setScroll(false) : undefined
offsetX >= 1024 ? offsetY > 76 ? setScroll(true) : setScroll(false) : undefined
}, [offsetY, offsetX])
const stickNavbar = () => {
if (window !== undefined) {
setOffsetY(window.scrollY)
setOffsetX(screen.width)
}
};
and ofc, I'm checking when position is true to assign the class. I made my CSS class in order to test those performance issues:
${scroll ? 'w-8 scrolled' : ''}
So here is the final CSS:
.nav {
.logo{
//transition-delay: 0.15s;
transition-property: all;
transition-timing-function: ease-in-out;
transition-duration: 0.3s;
top: -1.5rem;
&.scrolled{
margin-top: 2.15rem;
margin-left: 0.75rem;
}
#include desktop(){
transition-delay: 0s;
}
}
}
As you see, I have commented delay; causing a delay could be a possible fix to avoid that much lag. But is there any other things that I should look for?
Here is the demo of the app enter link description here
Related
import React from "react";
import "./sass/stages.css";
import fitness from "../../images/fitness.webp";
import { useState } from "react";
function Stages() {
const [change,setChange] = useState(false);
const [displayText,setDisplayText] = useState(false);
const changevalueonScrool = () => {
const scrollvalue = document.documentElement.scrollTop;
if(scrollvalue > 250){
setChange(true);
}
if(scrollvalue > 650){
setDisplayText(true) (true);
}
}
window.addEventListener("scroll",changevalueonScrool);
<div className={change ? "stageText opacity-Yposition" : "stageText"}>
<span>GROW YOUR</span>
<span>BUSINESS</span>
<span>ONLINE</span>
</div>
.stageText{
margin-top:3%;
transform: translateY(-50%);
opacity: 0;
transition: all 0.6s cubic-bezier(.165,.84,.44,1);
}
.opacity-Yposition{
opacity: 1;
transform: translateY(0);
}
I wanted to run the memories when I reached the desired height when the scroll scroll was scrolled down in the reaction.This request works very well on my web site, but the height I give on my web site shows changes in tablet and phone design, because the screen sizes on the tablet and mobile side are much longer, so the animations are coming very late.What is the way to solve this
I am using CSS Animations to create animations for a vertical image reel in my React app, however, the animation uses a variable that gets set in CSS by Javascript using the setProperty function.
So essentially, I have a fixed size reel with 10 slides and each slide has it's own animation (this is to handle where the image starts).
$margin: 25px;
$max-images-in-view: 10;
$speed: 90;
$offset: calc($speed * 1000ms);
.slide {
animation-iteration-count: infinite;
animation-timing-function: linear;
animation-duration: #{$speed}s;
#for $i from 1 through 10 {
&:nth-child(#{$i}) {
animation-delay: calc(
1000ms * $speed/$max-images-in-view * (#{$i} + 1) - $offset
);
animation-name: slide-animation-#{$i};
top: 100%;
#keyframes slide-animation-#{$i} {
from {
top: 100%;
opacity: 1;
}
to {
top: calc(
100% - $max-images-in-view * (var(--image-reel-image-height) + $margin)
);
opacity: 1;
}
}
}
}
}
The --image-reel-image-height variable gets set by the react component upon load and after the screen size updates.
const calculateCSSImageHeight = () => {
const imgEl = document.getElementsByClassName(Styles.imageContainer).item(0)
if (isBrowser)
document.documentElement.style.setProperty(
'--image-reel-image-height',
`${imgEl?.clientHeight ?? 0}px`
)
}
useEffect(() => {
calculateCSSImageHeight()
if (typeof window !== 'undefined') window.addEventListener('resize', calculateCSSImageHeight)
return () => {
window.removeEventListener('resize', calculateCSSImageHeight)
}
})
This seems to work perfectly fine for Chrome, but Safari doesn't seem to regenerate/update the animation after the component updates the CSS variable. For example, if I set --image-reel-height to '300px' as a default value, it animates as though the image height is 300px but the animation never updates after the variable has been updated.
Why isn't Safari picking up the CSS variable changes?
So I'm making a music website with a playhead that I've animated to move along the screen and loop back.
.playhead {
position: absolute;
border-left: 0.2em solid;
min-height: calc(100% - var(--display-border-width));
border-color: red;
animation: play-animation 4s linear infinite;
}
#keyframes play-animation {
0% {
left: 0%;
}
100% {
left: 100%
}
}
Now while the playhead is moving, I want to access its position value, or how far along the screen it is (offsetX), so I can play the notes or whatever at that position.
So if it halfway across the screen, and the screen is 1000px wide, I want to access the 500px value during the animation.
I've tried using useEffect and useRef together, but that only gets called when the animation stops or starts, but not while it is running. So the value stays the same during the animation
I've tried setting up a seperate setInterval for calculating the position only, like so:
useEffect(() => {
if (props.play) {
const markers = (playTime * 1000) / frameRate;
const percentToAdd = 100 / markers;
const id = setInterval(() => {setProgress((prev) => (prev + percentToAdd) % 100)}, frameRate);
setIntervalID(id);
} else {
if (intervalID !== 0) {
clearInterval(intervalID);
}
}
}, [props.play]);
But this is out of sync for some reason. And plus, I'd rather the position values come from the playhead directly.
Is there any way to do this? Thanks!
I've built a navigation that hides whenever the user scrolls down and comes back into view when the user scrolls up. This works perfectly on Chrome and Safari but not on Firefox. On Firefox the navigation does not do anything except when I hover over it with the inspect element tool.
Running React 16.9. I've tried the following things.
Tested on newest versions of chrome and firefox.
Tried using a requestAnimationFrame
Using rotate3d so the gpu takes over
Checked if scroll event fires ( it does. )
Tried same animation with opacity instead of changing top
Some code:
// The event listener is added
componentDidMount = () => {
window.addEventListener('scroll', throttle(this.handleScroll, 100));
window.addEventListener('keyup', this.handleKeyPress);
}
// What the event fires
handleScroll = () => {
const { currentNodeType } = this.props;
if (currentNodeType === 'landing_page') {
this.setState({ navScrolled: window.scrollY > (window.innerHeight - 125) });
} else {
this.setState({ navScrolled: window.scrollY > 285 });
}
const { prevScrollpos } = this.state;
const currentScrollPos = window.pageYOffset;
const visible = !!(prevScrollpos > currentScrollPos || window.scrollY < 30);
this.setState({
prevScrollpos: currentScrollPos,
visible,
});
}
A class is then added or removed to the navigation depending on if its visible
// The classes
.nav-hidden {
transition: all 0.333s ease-out;
top: -125px;
}
.nav-visible {
transition: all 0.333s ease-out;
top: 0;
}
I can't post images because of rep needed. ( this is my first question on stack overflow )
behaviour on chrome - desired behaviour
https://imgur.com/WkhlS4Y.gif
behaviour on firefox - undesired behaviour
https://imgur.com/hoEOP4x.gif
I hope I've been clear enough. Thanks in advance!
Fixed this by using margin instead of top.
.nav-hidden {
transition: all 0.333s ease-out;
top: 0;
margin-top: -125px;
}
.nav-visible {
transition: all 0.333s ease-out;
top: 0;
}
Hope this helps!
Problem statement
To move the square along the perimeter of the viewport on click of the button as can be seen in the example:
https://codepen.io/vineetrok/pen/XRowdB
What do I need?
I'm using this code in combination with the transition property in the CSS. I think combination of transition and setInterval() is causing a delay. Is there a better and efficient method to accomplish this only using javascript?
Following is my code:
HTML
<div class="box" style="left:0;top:0"></div>
<button type="button" name="button" onclick="init()">Start!</button>
CSS
.box{
transition: all 1s linear;
}
JS
var elem = document.querySelector(".box");
var viewportWidth = window.innerWidth;
var viewportHeight = window.innerHeight;
var dimension = elem.clientWidth;
var deltaX = viewportWidth - dimension;
var deltaY = viewportHeight - dimension;
function move(x,y){
if(x <=0 && y==0){
elem.style.left=(deltaX)+"px";
}
else if(x==(deltaX) && y==0){
elem.style.top=(deltaY)+"px";
}
else if(x==(deltaX) && y==(deltaY)){
elem.style.left="0px";
}
else if(x==0 && y==(deltaY)){
elem.style.top="0px";
}
}
function getCoordinates(elem){
return {
x: elem.getBoundingClientRect().left,
y: elem.getBoundingClientRect().top
}
}
var init = function(){
var clearTimer = 1;
var startTimer = setInterval(function(){
move(getCoordinates(elem).x,getCoordinates(elem).y )
}, 1000);
clearTimer++;
if(clearTimer>=4){
clearInterval(startTimer);
}
}
I would generally say that using both css and javascript to manage a transition is going to cause trouble. Part of the problem is that javascript timers aren't very precise. If you set a timer for 1 second it doesn't actually sleep for exactly one second. The exact amount of time it sleeps can vary depending on how busy the CPU is, what the user is doing, etc. It is very easy for the javascript timer to take longer than the CSS animation.
Since you are using jQuery I would use the jQuery.animate function to run things. It has a callback function that is invoked when the animation completes, and you can use that to execute the next step of the animation without any timers at all. That will make sure there aren't any delays. It should also be fairly performant. CSS animations are usually the slowest in terms of computer performance, so I expect jQuery.anmiate to probably be a bit better. There are other libraries out there designed for high performance animations, but unless performance actually becomes a problem, I wouldn't worry about it. Right now your issue is likely the imprecise timing of the timeout method, and not any performance issues.
Here's my go at it (I developed something from scratch instead of reusing your code) :
let box=document.getElementById("box"),
isLeft = false,
isTop = false
const toggleLeft = () => {
box.style.left = (isLeft=!isLeft) ? "calc( 100% - 50px )" : "0";
setTimeout(toggleTop, 2000);
}
const toggleTop = () => {
box.style.top = (isTop=!isTop) ? "calc( 100% - 50px )" : "0";
setTimeout(toggleLeft, 2000);
}
setTimeout(toggleLeft, 1000)
#box {
width: 50px;
height: 50px;
background: #00f;
position: absolute;
top: 0;
left: 0;
-webkit-transition: all 2s ease-in-out;
transition: all 2s ease-in-out;
}
<div id="box"></div>
And a more condensed and recursive version :
let box=document.getElementById("box"),
is = { left : false, top : false }
const toggle = what => {
box.style[what] = (is[what]=!is[what]) ? "calc( 100% - 50px )" : "0";
setTimeout(()=>toggle(what==="left"?"top":"left"), 2000);
}
setTimeout(()=>toggle("left"), 100)
#box {
width: 50px;
height: 50px;
background: #00f;
position: absolute;
top: 0;
left: 0;
-webkit-transition: all 2s ease-in-out;
transition: all 2s ease-in-out;
}
<div id="box"></div>