Add css transition when onclick in react - css

Hihi, I want to add a transition when the lightbox is set to true and then when it's set to false but I'm now able to reach it.
I was able to add a transition when I hover the image but I can add it this.
Could anyone help me getting this??
import '../assets/scss/gallery.scss';
import { useState, useEffect } from 'react';
// import Gallery from 'react-grid-gallery';
function Images() {
const [imageToShow, setImageToShow] = useState('');
const [showLightbox, setShowlightbox] = useState(false);
const showImage = (image) => {
setImageToShow(image);
setShowlightbox(true);
};
// hide lightbox
const hideLightBox = () => {
setShowlightbox(false);
};
useEffect(() => {
// eslint-disable-next-line no-unused-expressions
showLightbox ? document.body.classList.add('of') : document.body.classList.remove('of');
}, [showLightbox]);
return (
<section>
<div className="container">
<div className="gallery">
<div className="gallery-item" data-category="business">
<button
type="button"
data-lightbox="example-set"
className="lightbox"
onClick={() => showImage('https://c4.staticflickr.com/9/8887/28897124891_98c4fdd82b_w.jpg')}
data-title="Click the right half of the image to move forward."
>
<img src="https://c4.staticflickr.com/9/8887/28897124891_98c4fdd82b_w.jpg" alt="gallery-images" className="hover-shadow" />
</button>
</div>
<div className="gallery-item" data-category="business">
<button
data-lightbox="example-set"
type="button"
className="lightbox"
onClick={() => showImage('https://c4.staticflickr.com/9/8887/28897124891_98c4fdd82b_w.jpg')}
data-title="Click the right half of the image to move forward."
>
<img src="https://c4.staticflickr.com/9/8887/28897124891_98c4fdd82b_w.jpg" alt="gallery-images" className="hover-shadow" />
</button>
</div>
</div>
</div>
{
showLightbox
? (
<div>
<button type="button" onClick={hideLightBox}>
<div id="lightbox">
<img id="lightbox-img" src={imageToShow} alt="test" />
</div>
</button>
</div>
)
: ''
}
</section>
);
}
export default Images;
#import './common';
.gallery {
display: flex;
justify-content: space-between;
&-item {
#include desktop {
margin: 10px;
transition: all 5s;
}
img.hover-shadow {
transition: 0.3s;
}
.hover-shadow:hover {
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
filter: brightness(70%);
-webkit-filter: brightness(70%);
-moz-filter: brightness(70%);
}
}
transition: all 5s;
}
.lightbox {
&:hover{
cursor: pointer;
}
border: none;
transition: all 5s;
}
#lightbox-img {
height: 50vh;
max-width: 90vw;
object-fit: cover;
transition: all 5s;
}
#lightbox {
z-index: 1;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(255, 255, 255, 0.5);
display: flex;
align-items: center;
justify-content: center;
vertical-align: bottom;
transition: all 5s;
}
.of {
overflow: hidden;
height: auto;
} b
I added the transition:all 5s to almost everyone to see if I get it that way but I didn't have luck :(

Related

Animate item to center on click

so I have this three button I need to find a way any of these two solution
make animation so that each time one button come in front and the
two other go to the back
or, when I click on a button it come to the front and the other go to the back
here is my code for the style
.index-environement-specialise-boutton-main {
width: 279px;
height: 76px;
border: 1px solid var(--color-text-primary);
border-radius: 46px;
text-align: center;
font-style: normal !important;
font-variant: normal !important;
font-weight: bold !important;
font-size: 32px !important;
line-height: 34px !important;
font-family: Poppins !important;
letter-spacing: 0.5px;
color: var(--color-text-primary);
opacity: 1;
margin-inline: 2.625rem;
position: relative;
box-shadow: 0px 0px 222px 150px rgba(193, 186, 243, 0.75);
-webkit-box-shadow: 0px 0px 222px 150px rgba(193, 186, 243, 0.75);
-moz-box-shadow: 0px 0px 222px 150px rgba(193, 186, 243, 0.75);
display: flex;
align-items: center;
justify-content: center;
}
.index-environement-specialise-boutton-main.b1 {
background: #C1BAF3 0% 0% no-repeat padding-box;
}
.index-environement-specialise-boutton-main.b2 {
background: #F8D6B5 0% 0% no-repeat padding-box;
}
.index-environement-specialise-boutton-main.b3 {
background: #F3B9C5 0% 0% no-repeat padding-box;
}
.index-environement-specialise-boutton-behind {
width: 176px;
height: 48px;
border: 1px solid var(--color-text-primary);
border-radius: 46px;
text-align: center;
font-style: normal !important;
font-variant: normal !important;
font-weight: bold !important;
font-size: 20px !important;
line-height: 21px !important;
font-family: Poppins !important;
letter-spacing: 0.5px;
color: var(--color-text-primary);
opacity: 1;
display: flex;
align-items: center;
justify-content: center;
}
.index-environement-specialise-boutton-behind.b1 {
background: #C1BAF3 0% 0% no-repeat padding-box;
}
.index-environement-specialise-boutton-behind.b2 {
background: #F8D6B5 0% 0% no-repeat padding-box;
}
.index-environement-specialise-boutton-behind.b3 {
background: #F3B9C5 0% 0% no-repeat padding-box;
}
.index-environement-specialise-boutton-main:hover,
.index-environement-specialise-boutton-behind:hover {
color: var(--color-text-primary);
}
.index-environement-specialise-col-right{
width:700px;
}
<div class="w-100 index-environement-specialise-col-right">
<a class="index-environement-specialise-boutton-behind b2"
role="button"
href="javascript:void(0)"
id="A2" runat="server" title="hôtesses">
hôtesses
</a>
<a class="index-environement-specialise-boutton-main b1"
role="button"
href="javascript:void(0)"
id="A3" runat="server" title="sitters">
sitters
</a>
<a class="index-environement-specialise-boutton-behind b3"
role="button"
href="javascript:void(0)" id="A4" runat="server"
title="vendeurs">
vendeurs
</a>
</div>
With some CSS flex positioning, with JS's getBoundingClientRect() method and some simple math — animate the buttons wrapper using CSS3 transition and transform (inside a .carousel container) by the center point of each button item in relation to the horizontal center of the carousel:
// DOM helpers:
const els = (sel, par) => (par || document).querySelectorAll(sel);
const el = (sel, par) => (par || document).querySelector(sel);
// Carousel:
const btnCarousel = (elCarousel) => {
const move = (evt) => {
const elButton = evt.target.closest("button");
if (!elButton) return; // do nothing
const elSlider = el(".carousel-slider", elCarousel);
const bcrButton = elButton.getBoundingClientRect();
const bcrCarousel = elCarousel.getBoundingClientRect();
const bcrSlider = elSlider.getBoundingClientRect();
const centerCarousel = bcrCarousel.width / 2;
const centerButton = bcrButton.width / 2;
const xButton = bcrButton.left;
const xSlider = bcrSlider.left;
const x = centerCarousel - xButton - centerButton + xSlider;
elSlider.style.translate = `${x}px 0`;
};
elCarousel.addEventListener("click", move);
};
els(".carousel").forEach(btnCarousel);
.carousel {
position: relative;
overflow: hidden;
}
.carousel-slider {
display: flex;
margin: 0 auto;
justify-content: center;
gap: 1rem;
transition: 0.5s;
}
<div class="carousel">
<div class="carousel-slider">
<button type="button">1 Button</button>
<button type="button">2 Btn</button>
<button type="button">3 Button longer text</button>
</div>
</div>
<div class="carousel">
<div class="carousel-slider">
<button type="button">1 Super Button</button>
<button type="button">2 Some Button</button>
<button type="button">3</button>
</div>
</div>
Add a .is-active on click, some more styles, a CSS transition-origin to the button's center-top and you're almost done:
// DOM helpers:
const els = (sel, par) => (par || document).querySelectorAll(sel);
const el = (sel, par) => (par || document).querySelector(sel);
// Carousel:
const btnCarousel = (elCarousel) => {
const elButtons = els("button", elCarousel);
const move = (evt) => {
const elButton = evt.target.closest("button");
if (!elButton) return; // do nothing
const elSlider = el(".carousel-slider", elCarousel);
const bcrButton = elButton.getBoundingClientRect();
const bcrCarousel = elCarousel.getBoundingClientRect();
const bcrSlider = elSlider.getBoundingClientRect();
const centerCarousel = bcrCarousel.width / 2;
const centerButton = bcrButton.width / 2;
const xButton = bcrButton.left;
const xSlider = bcrSlider.left;
const x = centerCarousel - xButton - centerButton + xSlider;
elSlider.style.translate = `${x}px 0`;
elButtons.forEach(el => el.classList.remove("is-active"));
elButton.classList.add("is-active");
};
elCarousel.addEventListener("click", move);
};
els(".carousel").forEach(btnCarousel);
/* QuickReset*/
*,
::before,
::after {
margin: 0;
box-sizing: border-box;
}
body {
font: 16px/1.5 sans-serif;
background: linear-gradient(90deg, rgba(244, 246, 255, 1) 0%, rgba(213, 208, 247, 1) 50%, rgba(244, 246, 255, 1) 100%);
}
.carousel {
position: relative;
overflow: hidden;
padding: 4rem 0;
}
.carousel-slider {
display: flex;
margin: 0 auto;
justify-content: center;
gap: 4rem;
transition: 0.5s;
}
.btn {
border: 0.1rem solid #455171;
padding: 0.4em 2.6em;
font-weight: 900;
font-size: 1rem;
border-radius: 2em;
cursor: pointer;
}
.carousel .btn {
transform-origin: center top;
transition: 0.5s;
}
.carousel .btn.is-active {
scale: 1.4;
}
.bg-1 {
background-color: #ecb9cc;
}
.bg-2 {
background-color: #c1baf3;
}
.bg-3 {
background-color: #f0d2be;
}
<div class="carousel">
<div class="carousel-slider">
<button type="button" class="btn bg-1">Hôtesses</button>
<button type="button" class="btn bg-2 is-active">Sitters</button>
<button type="button" class="btn bg-3">Vendeurs</button>
</div>
</div>

CSS transition animation causes residual border lines on the page

I made a pop-up window and used transition animation in CSS.
When I open the pop-up window, there is no problem with the transition animation, but when the pop-up window is closed, there will be residual border lines on the page.
This happens in Google Chrome.
Please click here for details:
https://codepen.io/lianflower/pen/zYKRPJb
<button data-modal-target="#modal">Open Modal</button>
<div class="modal" id="modal">
<div class="modal-header">
<div class="title">Example Modal</div>
<button data-close-button class="closebutton">×</button>
</div>
<div class="modal-body">
A wiki (/ˈwɪki/ (About this soundlisten) WIK-ee) is a hypertext publication collaboratively edited and managed by its own audience directly using a web browser. A typical wiki contains multiple pages for the subjects or scope of the project and may be either open to the public or limited to use within an organization for maintaining its internal knowledge base
</div>
</div>
<div id="overlay"></div>
*,*::after, *::before {
box-sizing: border-box;
}
.modal {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) scale(0);
transition: 500ms ease-in-out;
border: 1px solid black;
border-radius: 10px;
z-index: 10;
background-color: white;
width: 800px;
max-width: 80%;
}
.modal.active {
transform: translate(-50%, -50%) scale(1);
}
.modal-header {
padding: 10px 15px;
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid black;
}
.modal-header .title {
font-size: 1.25rem;
font-weight: bold;
}
.modal-header .close-button {
cursor: pointer;
border: none;
outline: none;
background: none;
font-size: 1.25rem;
font-weight: bold;
}
.modal-body {
padding: 10px 15px;
}
#overlay {
position: fixed;
opacity: 0;
transition: 200ms ease-in-out;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, .5);
pointer-events: none;
}
#overlay.active {
opacity: 1;
pointer-events: all;
}
var openModalButtons = document.querySelectorAll('[data-modal-target]');
var closeModalButtons = document.querySelectorAll('[data-close-button]');
var overlay = document.getElementById('overlay');
openModalButtons.forEach(button => {
button.addEventListener('click', () => {
var modal = document.querySelector(button.dataset.modalTarget);
openModal(modal)
})
});
closeModalButtons.forEach(button => {
button.addEventListener('click', () => {
var modal = button.closest('.modal');
closeModal(modal)
})
});
overlay.addEventListener('click', () => {
var modals = document.querySelectorAll('.modal.active');
modals.forEach(modal => {
closeModal(modal)
});
});
function openModal(modal) {
if (modal == null) return;
modal.classList.add('active');
overlay.classList.add('active')
}
function closeModal(modal) {
if (modal == null) return;
modal.classList.remove('active');
overlay.classList.remove('active')
}
You modal has a border, border: 1px solid black; That is causing this thing to happen. Put border on modal.active class instead and you are good to go.
Update: Set your borders only when the modal is active on any of the children components of modal in order to avoid these extra lines.
Codepen:https://codepen.io/emmeiWhite/pen/MWjQrJd
Full Code:
var openModalButtons = document.querySelectorAll('[data-modal-target]');
var closeModalButtons = document.querySelectorAll('[data-close-button]');
var overlay = document.getElementById('overlay');
openModalButtons.forEach(button => {
button.addEventListener('click', () => {
var modal = document.querySelector(button.dataset.modalTarget);
openModal(modal)
})
});
closeModalButtons.forEach(button => {
button.addEventListener('click', () => {
var modal = button.closest('.modal');
closeModal(modal)
})
});
overlay.addEventListener('click', () => {
var modals = document.querySelectorAll('.modal.active');
modals.forEach(modal => {
closeModal(modal)
});
});
function openModal(modal) {
if (modal == null) return;
modal.classList.add('active');
overlay.classList.add('active')
}
function closeModal(modal) {
if (modal == null) return;
modal.classList.remove('active');
overlay.classList.remove('active')
}
*,*::after, *::before {
box-sizing: border-box;
}
.modal { /* Removed border from is selector */
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) scale(0);
transition: 500ms ease-in-out;
border-radius: 10px;
z-index: 10;
background-color: white;
width: 800px;
max-width: 80%;
}
.modal.active {
transform: translate(-50%, -50%) scale(1);
border: 1px solid black; /*--- Added border here ---*/
}
.modal-header {
padding: 10px 15px;
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid black;
}
.modal-header .title {
font-size: 1.25rem;
font-weight: bold;
}
.modal-header .close-button {
cursor: pointer;
border: none;
outline: none;
background: none;
font-size: 1.25rem;
font-weight: bold;
}
.modal-body {
padding: 10px 15px;
}
.modal-body.active{ /* Add border on active class only */
border:1px solid blue;
}
#overlay {
position: fixed;
opacity: 0;
transition: 200ms ease-in-out;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, .5);
pointer-events: none;
}
#overlay.active {
opacity: 1;
pointer-events: all;
}
<button data-modal-target="#modal">Open Modal</button>
<div class="modal" id="modal">
<div class="modal-header">
<div class="title">Example Modal</div>
<button data-close-button class="closebutton">×</button>
</div>
<div class="modal-body">
A wiki (/ˈwɪki/ (About this soundlisten) WIK-ee) is a hypertext publication collaboratively edited and managed by its own audience directly using a web browser. A typical wiki contains multiple pages for the subjects or scope of the project and may be either open to the public or limited to use within an organization for maintaining its internal knowledge base
</div>
</div>
<div id="overlay"></div>

Why isn't my custom CSS transition working when updating the state of a parent React component?

I'm using functional components with hooks (state hooks mostly) and when I update the "local" state (state within the same component) my custom css transitions works fine. However, when I move this state to the parent component and update it from the child component the css transistion will not work. Instead the changes will render immediately. What am I doing wrong?
I have tried to search for a while but without success. I am making a navbar with a burger menu that will slide in a navigation list from the right when klicked.
This below will not work
import React, { useState, useEffect } from "react";
import "./navbar.css";
const Navbar = (props) => {
const [scrollState, setScrollState] = useState("top");
const [burgerOpen, setBurgerOpen] = useState(false); //updating this state transistions does not work!
const Burger = () => {
//const [open, setOpen] = useState(false); //updating this state transistions work!
const handleKeyDown = (event) => {
if (event.key === "Enter") {
setBurgerOpen(!burgerOpen);
}
};
return (
<>
<div className={"btn-container"} onKeyDown={handleKeyDown}>
<div
className={burgerOpen ? "navbar-btn open" : "navbar-btn"}
open={burgerOpen}
onClick={() => setBurgerOpen(!burgerOpen)}
>
<div className="navbar-burger" />
</div>
</div>
<Menu open={burgerOpen} key="menu" />
</>
);
};
const Menu = ({ open }) => {
return (
<ul className={open ? "open" : ""}>
<li>
<a to="/projects">Projects</a>
</li>
<li>
<a to="/design">Design</a>
</li>
<li>
<a to="/contact">Contact</a>
</li>
</ul>
);
};
return (
<nav
className={`navbar ${scrollState === "top" ? "dark-nav" : "light-nav"}`}
>
<Burger />
</nav>
);
};
Navbar.propTypes = {};
export default Navbar;
This however works but I need to move the state to the parent because of rerenders that I might add (e.g. I want to keep the menu open...)
import React, { useState, useEffect } from "react";
import "./navbar.css";
const Navbar = (props) => {
const [scrollState, setScrollState] = useState("top");
//const [burgerOpen, setBurgerOpen] = useState(false); //updating this state transistions does not work!
const Burger = () => {
const [open, setOpen] = useState(false); //updating this state transistions work!
const handleKeyDown = (event) => {
if (event.key === "Enter") {
open(!open);
}
};
return (
<>
<div className={"btn-container"} onKeyDown={handleKeyDown}>
<div
className={open ? "navbar-btn open" : "navbar-btn"}
open={open}
onClick={() => setOpen(!open)}
>
<div className="navbar-burger" />
</div>
</div>
<Menu open={open} key="menu" />
</>
);
};
const Menu = ({ open }) => {
return (
<ul className={open ? "open" : ""}>
<li>
<a to="/projects">Projects</a>
</li>
<li>
<a to="/design">Design</a>
</li>
<li>
<a to="/contact">Contact</a>
</li>
</ul>
);
};
return (
<nav
className={`navbar ${scrollState === "top" ? "dark-nav" : "light-nav"}`}
>
<Burger />
</nav>
);
};
Navbar.propTypes = {};
export default Navbar;
And the CSS:
.navbar {
display: flex;
justify-content: space-between;
align-items: center;
position: fixed;
z-index: 999;
width: 100%;
top: 0;
padding: 0.7rem 2rem;
height: 170px;
transition: all 0.8s ease;
background: linear-gradient(
to bottom,
rgba(0, 0, 0, 0.815) 50%,
rgba(0, 0, 0, 0.35) 50%
)
right;
background-size: 100% 200%;
background-position: top;
}
.light-nav {
/*background-color: rgba(0, 0, 0, 0.35);*/
background-position: bottom;
}
.navbar ul {
display: flex;
flex-flow: row nowrap;
}
.navbar li {
padding: 10px 10px;
font-size: 20px;
}
.navbar a {
background: linear-gradient(to right, royalblue, royalblue 50%, #f4f4f4 50%);
background-clip: text;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-size: 200% 100%;
background-position: 100%;
transition: background-position 0.5s ease;
}
.navbar a:hover {
background-position: 0 100%;
}
.navbar-logo {
height: auto;
width: 200px;
padding: 2px;
}
.navbar-logo img {
max-width: 100%;
max-height: 100%;
}
.navbar-btn {
visibility: hidden;
display: none;
position: relative;
justify-content: center;
align-items: center;
cursor: pointer;
transition: all 0.5s ease-in-out;
width: 50px;
height: 50px;
padding-top: 10px;
}
.btn-container:focus > .navbar-btn {
border: #f4f4f4 1px solid;
}
.btn-container:focus,
.navbar-btn:focus {
border: none;
}
.navbar-burger {
width: 35px;
height: 3px;
background: #f4f4f4;
border-radius: 5px;
transition: all 0.5s ease-in-out;
}
.navbar-burger::before,
.navbar-burger::after {
content: '';
position: absolute;
width: 35px;
height: 3px;
background: #f4f4f4;
border-radius: 5px;
transition: all 0.5s ease-in-out;
}
.navbar-burger::before {
transform: translateY(-10px);
}
.navbar-burger::after {
transform: translateY(10px);
}
.navbar-btn.open .navbar-burger {
transform: translateX(-50px);
background: transparent;
}
.navbar-btn.open .navbar-burger::before {
transform: rotate(45deg) translate(35px, -35px);
}
.navbar-btn.open .navbar-burger::after {
transform: rotate(-45deg) translate(35px, 35px);
}
.navbar-btn:hover .navbar-burger,
.navbar-btn:hover .navbar-burger::before,
.navbar-btn:hover .navbar-burger::after {
background: royalblue;
}
.navbar-btn.open:hover .navbar-burger {
background: transparent;
}
#media (max-width: 768px) {
.navbar {
height: 110px;
}
.navbar-logo {
width: 140px;
}
.navbar ul {
flex-flow: column nowrap;
position: fixed;
top: 110px;
right: 0;
height: 100vh;
width: 200px;
transform: translateX(100%);
transition: 0.5s ease-in-out;
background-color: rgba(0, 0, 0, 0.815);
}
.navbar ul li {
transform: translateX(100%);
transition: 0.5s ease-in-out;
}
.navbar ul.open li {
transform: translateX(0);
}
.navbar ul li:nth-child(1) {
transition-delay: 0.1s;
}
.navbar ul li:nth-child(2) {
transition-delay: 0.2s;
}
.navbar ul li:nth-child(3) {
transition-delay: 0.3s;
}
.navbar ul.open {
transform: translateX(0);
}
.navbar-btn {
visibility: visible;
display: flex;
padding-bottom: 10px;
}
}
Here is a sandbox of the working example but I need to move out the state of the Burger (resize for burger menu):
Working example (resize!)

What is the main cause of box-shadow not to work

Hello I have to been trying to search for a solution to my problem that is my box-shadow not working, I have seen other question on Stack Overflow that are similar but the all did not solve my problem can I please get some help
Code below is my React Component
import React from "react";
import "../StyleSheet/MainDashBaordWindow.css";
const HomeDashContent = () => {
return (
<div className="DashBoardContent">
<h1 className="DashBoardContent__header">Welcome Back!</h1>
<div className="DashBoarContent__mainWindow">
<div className="mainWindow__cards left-card">
<h2>On Going Shipments</h2>
</div>
<div className="mainWindow__cards right-card">
<h2>Finished Shipments</h2>
</div>
</div>
</div>
);
};
export default HomeDashContent;
Code below is my stylesheet
.DashBoardContent {
flex: 0.8;
display: flex;
flex-direction: column;
align-items: center;
}
.DashBoardContent__header {
font-weight: bolder;
margin-bottom: 2em;
}
.DashBoarContent__mainWindow {
display: flex;
}
.mainWindow__cards {
background-color: #f5f5f5f5;
padding: 4em 2em;
height: 30vh;
transition: transform 0.4s;
box-shadow: 2rem 2.5rem 2rem solid lightslategray;
}
.mainWindow__cards:hover {
transform: scale(1.1);
}
.left-card {
margin-right: 5em;
}
.right-card {
margin-left: 5em;
}
'Solid' value is not available for the box-shadow property. Just try to put a length value like 1px for the spread value(which is the fourth property value for box-shadow) instead of solid and it's gonna work.

Prevent page jump on Button click? ReactJS

I have a ShowcaseMovie component which fetches data on componentDidMount() and sets it to state. The component renders Card components to display the data as well as four button elements upcoming, top_rated, popular and now_playing which allow the user to toggle between the relevant data. Each button has an onClick event which calls changeFilter and sets state currentFilter to the selected key.
The problem: When the filter buttons are clicked, sometimes the page will jump to the top (if it's not already there). I've tried to find solutions to this but I can't seem to understand what is happening. Any suggestions will be a great help, thank you in advance.
Update: This issue seems to happen when there is no height set to an element with dynamic children. If I set the height on ShowcaseMovie to something large like height: 200vh it goes away.
I believe I've solved my problem but would love to hear other thoughts as to why this happens and some other ways to fix it. It's difficult to set a height to a parent when you don't know how much content is going to be rendered (or the height of that content). min-height would help but still kind of a quick fix.
ShowcaseMovie.js
import React, { Component } from "react";
import Card from "./Card";
import "../css/ShowcaseMovie.css";
import { v4 as uuidv4 } from "uuid";
import { formatString, buildMovieState } from "../utilities";
class ShowcaseMovie extends Component {
static defaultProps = {
filterNames: ["upcoming", "popular", "now_playing", "top_rated"]
};
constructor(props) {
super(props);
this.state = {
upcoming: [],
now_playing: [],
popular: [],
top_rated: [],
currentFilter: this.props.filterNames[0]
};
}
changeFilter = e => {
e.preventDefault();
const type = e.target.name;
this.setState({ currentFilter: type });
};
componentDidMount() {
this.props.filterNames.map(name => this.fetchMovies(name));
// setInterval(() => {
// this.timeoutFilter();
// }, 10000);
}
async fetchMovies(type) {
try {
const res = await fetch(
`url`
);
const data = await res.json();
if (data) {
this.setState(state => ({
...state,
[type]: buildMovieState(data)
}));
}
} catch (error) {
console.log(error);
}
}
render() {
const { currentFilter } = this.state;
const movies = this.state[currentFilter].map((movie, i) => (
<Card key={uuidv4()} movie={movie} index={i} />
));
const buttons = this.props.filterNames.map(name => (
<button
type="button"
key={name}
name={name}
className={`ShowcaseMovie-btn ${
currentFilter === name ? "active" : ""
}`}
disabled={currentFilter === name}
onClick={this.changeFilter}>
{formatString(name)}
</button>
));
return (
<section className="ShowcaseMovie">
<div className="ShowcaseMovie-container">
<h2 className="ShowcaseMovie-header">Movies</h2>
<div className="ShowcaseMovie-btn-container">{buttons}</div>
</div>
<div className="ShowcaseMovie-grid">{movies}</div>
</section>
);
}
}
ShowcaseMovie.css
.ShowcaseMovie {
padding: 4rem 10%;
}
.ShowcaseMovie-container {
position: relative;
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 2rem;
}
.ShowcaseMovie-button-container {
display: flex;
justify-content: center;
align-items: center;
}
.ShowcaseMovie-container::after {
content: "";
background-color: #64b5f6;
height: 80%;
width: 6px;
left: 0;
position: absolute;
border-radius: 1px;
}
.ShowcaseMovie-header {
font-size: 3rem;
font-weight: 200;
margin: 0 5rem;
}
.ShowcaseMovie-btn {
outline: none;
border: none;
background-color: transparent;
font-size: 1.6rem;
font-weight: 500;
letter-spacing: 1px;
padding: 1rem;
margin-left: 4rem;
color: white;
opacity: 0.5;
cursor: pointer;
transition-property: opacity;
transition-duration: 300ms;
transition-timing-function: ease;
}
.ShowcaseMovie-btn:hover {
opacity: 1;
transition-property: opacity;
transition-duration: 300ms;
transition-timing-function: ease;
}
.ShowcaseMovie-btn.active {
opacity: 1;
cursor: auto;
color: #64b5f6;
}
.ShowcaseMovie-grid {
display: grid;
gap: 3rem;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
}
Card.js
import React, { Component } from "react";
import "../css/Card.css";
class Card extends Component {
render() {
const { title, poster_path } = this.props.movie;
const style = { animationDelay: `${80 * this.props.index}ms` };
return (
<div className="Card">
<div className="Card-inner" style={style}>
<img
src={`https://image.tmdb.org/t/p/w500/${poster_path}`}
alt=""
className="Card-img"
/>
<p className="Card-name">{title}</p>
</div>
</div>
);
}
}
export default Card;
Card.css
.Card {
display: block;
transition: transform 300ms ease;
}
.Card:hover {
transform: translateY(-5px);
transition: transform 300ms ease;
}
.Card-inner {
position: relative;
display: block;
cursor: pointer;
height: 100%;
opacity: 0;
animation-name: moveUp;
animation-duration: 500ms;
animation-delay: 50ms;
animation-timing-function: ease;
animation-fill-mode: forwards;
}
.Card-inner::after {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-image: linear-gradient(transparent, rgba(33, 47, 61, 0.8));
border-bottom-left-radius: 2px;
border-bottom-right-radius: 2px;
z-index: 100;
opacity: 1;
transition: opacity 300ms ease;
}
.Card-inner:hover::after {
opacity: 0;
transition: opacity 300ms ease;
}
.Card-inner::before {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-image: linear-gradient(transparent, rgba(100, 180, 246, 0.6));
border-bottom-left-radius: 2px;
border-bottom-right-radius: 2px;
z-index: 100;
opacity: 0;
transition: opacity 300ms ease;
}
.Card-inner:hover::before {
opacity: 1;
transition: opacity 300ms ease;
}
.Card-img {
display: block;
position: relative;
object-fit: cover;
max-width: 100%;
min-height: 100%;
z-index: 0;
border-radius: 2px;
}
.Card-name {
position: absolute;
bottom: 0;
left: 0;
margin: 0 2rem 2rem 2rem;
z-index: 150;
font-weight: 400;
text-transform: uppercase;
font-size: 1.4rem;
letter-spacing: 2px;
}
#keyframes moveUp {
0% {
transform: translateY(5rem);
}
100% {
transform: translateY(0);
opacity: 1;
}
}
utilities.js
export const formatString = name => {
return name
.replace("_", " ")
.split(" ")
.map(w => w[0].toUpperCase() + w.slice(1))
.join(" ");
};
export const buildMovieState = data => {
if (data.results) {
const movies = data.results.filter(
d => d.backdrop_path && d.id && d.title && d.poster_path
);
return movies.length > 10 ? movies.slice(0, 10) : movies;
} else {
return [];
}
};
I was able to stop this from happening by returning false from the onClick call. Like this:
onClick={
doSomething()
return false
}
The page jumping could be from components unnecessarily re-rendering. Try wrapping all your components with React.memo( component name)

Resources