Currently I have a table with a question for each cell. It models a Jeopardy game. When the user clicks on one of the cells, a question modal pops up and then when he hits submit, a feedback modal pops up. I want to change the background of the question and feedback modals to be one consistent animated background. But currently the background only changes for that one column of the cell I click on. I need to somehow temporarily override the table and display the animated background rather than the table when the modals pop up.
Here is what I have:
Question Modal (that also renders Feedback modal)
import React, { Component } from 'react';
import Modal from "react-bootstrap/Modal";
import Button from "react-bootstrap/Button";
import UserInput from './userInput.js';
import Feedback from "./feedback/feedback";
import Backdrop from "./backdrop";
import styles from '../scss/backdrop.scss';
class SampleQ extends Component {
static getInitialProps({query: {amount, question, answer}}) {
return {specAmt: amount, specQ: question, specA: answer}
}
constructor(props) {
super(props);
this.state = {
showQuestion: false, // tracks visibility of first modal (the question modal)
showFeedback: false, // tracks visibility of second modal (the feedback modal)
showBackdrop: false // tracks visibility of backdrop when question pops up
};
this.handleShow = () => {
// show question and the backdrop when the user clicks a cell on the table
this.setState({ showQuestion: true, showBackdrop: true });
};
this.handleHide = () => {
this.setState({ showQuestion: false });
};
this.submitForm = event => {
event.preventDefault();
this.setState({
showQuestion: false, // close question modal
showFeedback: true, // should open Feedback modal
});
};
this.closeFeedback = () => {
// close Feedback modal and close backdrop so that it goes back to the table
this.setState( { showFeedback: false, showBackdrop: false });
};
}
render() {
let backdrop;
// only shows if either the question or feedback modal is up. if neither are open, then don't show stars
if (this.state.showBackdrop && (this.state.showQuestion || this.state.showFeedback) ) {
backdrop = <Backdrop/>
} else {}
return (
<>
<Button variant="outline-danger" size = "lg" onClick={this.handleShow}>
$ {this.props.amount}00
</Button>
{backdrop}
<Modal
show={this.state.showQuestion}
onHide={this.handleHide}
dialogClassName="modal-90w"
aria-labelledby="example-custom-modal-styling-title"
>
<Modal.Header closeButton>
<Modal.Title id="example-custom-modal-styling-title">
Question
</Modal.Title>
</Modal.Header>
<Modal.Body>
<p>
{this.props.question}
</p>
<div>
<UserInput
answer={this.props.specA}
handleClick={this.submitForm}
/>
</div>
</Modal.Body>
</Modal>
<Feedback
showModal={this.state.showFeedback}
handleHide={this.closeFeedback}
/>
</>
);
}
}
export default SampleQ;
Animated Backdrop/Background for the modals
import React, { Component } from 'react';
import styles from '../scss/backdrop.scss';
export default class Backdrop extends Component {
render() {
return (
<div className={styles.body}>
<div className={styles.night}>
<div className={styles.shooting_star}></div>
<div className={styles.shooting_star}></div>
<div className={styles.shooting_star}></div>
<div className={styles.shooting_star}></div>
</div>
</div>
);
}
}
CSS/SCSS for the backdrop/background
.body {
background: radial-gradient(ellipse at bottom, #1b2735 0%, #090a0f 100%);
height: 100vh;
overflow: hidden;
display: flex;
font-family: 'Anton', sans-serif;
justify-content: center;
align-items: center;
}
$shooting-time: 3000ms;
.night {
position: relative;
width: 100%;
height: 100%;
transform: rotateZ(45deg);
// animation: sky 200000ms linear infinite;
}
.shooting_star {
position: absolute;
left: 50%;
top: 50%;
// width: 100px;
height: 2px;
background: linear-gradient(-45deg, rgba(95, 145, 255, 1), rgba(0, 0, 255, 0));
border-radius: 999px;
filter: drop-shadow(0 0 6px rgba(105, 155, 255, 1));
animation:
tail $shooting-time ease-in-out infinite,
shooting $shooting-time ease-in-out infinite;
&::before {
content: '';
position: absolute;
top: calc(50% - 1px);
right: 0;
// width: 30px;
height: 2px;
background: linear-gradient(-45deg, rgba(0, 0, 255, 0), rgba(95, 145, 255, 1), rgba(0, 0, 255, 0));
transform: translateX(50%) rotateZ(45deg);
border-radius: 100%;
animation: shining $shooting-time ease-in-out infinite;
}
&::after {
#extend .shooting_star::before;
transform: translateX(50%) rotateZ(-45deg);
}
#for $i from 1 through 20 {
&:nth-child(#{$i}) {
$delay: random(9999) + 0ms;
top: calc(50% - #{random(400) - 200px});
left: calc(50% - #{random(300) + 0px});
animation-delay: $delay;
// opacity: random(50) / 100 + 0.5;
&::before,
&::after {
animation-delay: $delay;
}
}
}
}
#keyframes tail {
0% {
width: 0;
}
30% {
width: 100px;
}
100% {
width: 0;
}
}
#keyframes shining {
0% {
width: 0;
}
50% {
width: 30px;
}
100% {
width: 0;
}
}
#keyframes shooting {
0% {
transform: translateX(0);
}
100% {
transform: translateX(300px);
}
}
#keyframes sky {
0% {
transform: rotate(45deg);
}
100% {
transform: rotate(45 + 360deg);
}
}
Screenshots:
table
question
Related
Problem
In my app I have card with projects and sometimes images of those projects doesn't load on mobile i have to reload browser and to it is loaded correctly I have no idea how.I must also point out that on the computer viewer everything works correctly.
Stack
I`m using Astro.js with Preact.
Here is demonstration video of my problem
https://streamable.com/okquzk
My code
The way i use it. In Astro framework you can create collections with you mdx or md data here i pass route to imgs like this:
Note: in Astro you dont have to write public/something it ok to write
/projects/bhn.webp
---
title: "Black Hat News"
heroImage: /projects/bhn.webp
___
After some step I am using it inside Card.tsx
import "./styles/card.css";
type Props = {
title: string;
heroImage: string;
slug: string;
};
export const Card = ({ title, heroImage, slug }: Props) => (
<a href={slug}>
<div class="card">
<img src={heroImage} alt={title} />
<div class="info">
<h1>{title}</h1>
</div>
</div>
</a>
);
and there is css
/* Set padding top to make a trick with aspect ratio 16:9 */
.card {
padding: 1rem;
width: 100%;
padding-top: 56.25%;
position: relative;
display: flex;
align-items: flex-end;
transition: 0.4s ease-out;
box-shadow: 0px 7px 10px rgba(0, 0, 0, 0.5);
cursor: pointer;
}
.card:before {
content: "";
position: absolute;
top: 0;
left: 0;
display: block;
width: 100%;
height: 100%;
/* background: rgba(0, 0, 0, 0.6); */
z-index: 2;
}
.card img {
width: 100%;
height: 100%;
-o-object-fit: cover;
object-fit: cover;
object-position: center top;
position: absolute;
top: 0;
left: 0;
}
.card .info {
position: relative;
z-index: 3;
color: var(--color-text);
background: var(--color-dark);
padding: 0.4rem;
border-radius: 5px;
}
.card .info h1 {
font-size: var(--font-lg);
}
/* for desktop add nice effects */
#media (min-width: 1024px) {
.card:hover {
transform: translateY(10px);
}
.card:hover:before {
opacity: 1;
background: rgba(0, 0, 0, 0.6);
}
.card:hover .info {
opacity: 1;
transform: translateY(0px);
}
.card:before {
transition: 0.3s;
opacity: 0;
}
.card .info {
opacity: 0;
transform: translateY(30px);
transition: 0.3s;
}
.card .info h1 {
margin: 0px;
}
}
Edit
Added usage
import "./styles/projectsGrid.css";
import { useStore } from "#nanostores/preact";
import { getProjectsByTag } from "#utils/*";
import type { CollectionEntry } from "astro:content";
import { tagValue } from "src/tagStore";
import { Card } from "./Card";
type Props = {
projects: CollectionEntry<"projects">[];
};
export const ProjectsGrid = ({ projects }: Props) => {
const $tagValue = useStore(tagValue);
const filteredProjects = getProjectsByTag(projects, $tagValue);
return (
<div class="projects_wrapper">
{filteredProjects.map(({ data: { title, heroImage }, slug }) => (
<Card title={title} heroImage={heroImage} slug={slug} />
))}
</div>
);
};
I know this code won't work in the current state because it will just select the first modal class. I have tried many variations of using querySelectorAll and forEach loops in the functions and event listeners but I can't seem to get it right.
How can I convert the current code to work with the different project card modals?
// Project card modals
const modal = document.querySelector('.modal')
const trigger = document.querySelector('.trigger')
const closeButton = document.querySelector('.close-button')
const body = document.querySelector('body')
function toggleModal() {
modal.classList.toggle('show-modal')
showModal()
}
function windowOnClick(event) {
if (this.event.target === modal) {
toggleModal()
showModal()
}
}
trigger.addEventListener('click', toggleModal)
closeButton.addEventListener('click', toggleModal)
window.addEventListener('click', windowOnClick)
// Disable body scroll with modal open
const showModal = function (e) {
if (modal.classList.contains('show-modal')) {
// Disable scroll
body.style.overflow = 'hidden'
} else {
// Enable scroll
body.style.overflow = 'auto'
}
}
<div class="projects-container">
<div class="projects-grid">
<div class="project-cell">
<div class="project-tile trigger">
<img Card Image />
</div>
<div class="modal">
<div class="modal-content">
<div class="close-button">×</div>
Modal Content
</div>
</div>
</div>
</div>
</div>
.modal {
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(68, 71, 90, 0.8);
backdrop-filter: blur(20px) saturate(180%);
opacity: 0;
visibility: hidden;
transform: scale(1.1);
transition: visibility 0s linear 0.25s, opacity 0.25s 0s, transform 0.25s;
z-index: 5;
}
.modal-content {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
padding: 1rem 2rem;
width: 70%;
background-color: rgb(40, 42, 54, 0.8);
border-radius: 5px;
backdrop-filter: blur(20px) saturate(180%);
border: 2px solid transparent;
box-shadow: 0 0 5px 1px var(--dracula-background);
}
.close-button {
width: 1.5rem;
line-height: 1.5rem;
text-align: center;
border-radius: 3px;
color: black;
font-weight: 500;
background-color: rgba(255, 85, 85, 0.7);
cursor: url('../assets/images/icons/cursor-hand-white.png'), auto;
position: absolute;
right: 0;
top: 0;
transition: ease all 0.1s;
}
.show-modal {
opacity: 1;
visibility: visible;
transform: scale(1);
transition: visibility 0s linear 0s, opacity 0.25s 0s, transform 0.25s;
}
You can use unique id attributes on your modal elements to differentiate them, and then use data attributes to target modals.
// Project card modals
const body = document.querySelector('body')
function toggleModal(modal) {
modal.classList.toggle('show-modal')
showModal(modal)
}
document.addEventListener('click', function(event) {
if (event.target.classList.contains('modal')) {
toggleModal(event.target)
showModal(event.target)
} else if (event.target.classList.contains('trigger')) {
toggleModal(document.getElementById(event.target.getAttribute('data-target')))
} else if (event.target.classList.contains('close-button')) {
toggleModal(document.getElementById(event.target.getAttribute('data-target')))
}
})
// Disable body scroll with modal open
const showModal = function(modal) {
if (modal.classList.contains('show-modal')) {
// Disable scroll
body.style.overflow = 'hidden'
} else {
// Enable scroll
body.style.overflow = 'auto'
}
}
.modal {
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(68, 71, 90, 0.8);
backdrop-filter: blur(20px) saturate(180%);
opacity: 0;
visibility: hidden;
transform: scale(1.1);
transition: visibility 0s linear 0.25s, opacity 0.25s 0s, transform 0.25s;
z-index: 5;
}
.modal-content {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
padding: 1rem 2rem;
width: 70%;
background-color: rgb(40, 42, 54, 0.8);
border-radius: 5px;
backdrop-filter: blur(20px) saturate(180%);
border: 2px solid transparent;
box-shadow: 0 0 5px 1px var(--dracula-background);
}
.close-button {
width: 1.5rem;
line-height: 1.5rem;
text-align: center;
border-radius: 3px;
color: black;
font-weight: 500;
background-color: rgba(255, 85, 85, 0.7);
position: absolute;
right: 0;
top: 0;
transition: ease all 0.1s;
}
.show-modal {
opacity: 1;
visibility: visible;
transform: scale(1);
transition: visibility 0s linear 0s, opacity 0.25s 0s, transform 0.25s;
}
<div class="projects-container">
<div class="projects-grid">
<div class="project-cell">
<div class="project-tile trigger" data-target="modal1">
<img Card Image /> trigger1
</div>
<div class="modal" id="modal1">
<div class="modal-content">
<div class="close-button" data-target="modal1">×</div>
Modal Content 1
</div>
</div>
</div>
<div class="project-cell">
<div class="project-tile trigger" data-target="modal2">
<img Card Image /> trigger2
</div>
<div class="modal" id="modal2">
<div class="modal-content">
<div class="close-button" data-target="modal2">×</div>
Modal Content 2
</div>
</div>
</div>
<div class="project-cell">
<div class="project-tile trigger" data-target="modal3">
<img Card Image /> trigger3
</div>
<div class="modal" id="modal3">
<div class="modal-content">
<div class="close-button" data-target="modal3">×</div>
Modal Content 3
</div>
</div>
</div>
</div>
</div>
I can definitely refactor this, but I was able to get it working by using the IDs. I also had to switch the querySelectorAll to getElementsByClassName because querySelectorAll will return a static collection, while getElementsByClassName returns a live collection.
// Project card modals
const body = document.querySelector('body')
const modal = document.getElementsByClassName('modal')
const trigger = document.getElementsByClassName('trigger')
const closeButton = document.getElementsByClassName('close-button')
// When the user clicks the project image, open the modal
trigger[0].onclick = function () {
modal[0].classList.toggle('show-modal')
if (modal[0].classList.contains('show-modal')) {
// Disable scroll
body.style.overflow = 'hidden'
} else {
// Enable scroll
body.style.overflow = 'auto'
}
}
trigger[1].onclick = function () {
modal[1].classList.toggle('show-modal')
if (modal[1].classList.contains('show-modal')) {
// Disable scroll
body.style.overflow = 'hidden'
} else {
// Enable scroll
body.style.overflow = 'auto'
}
}
trigger[2].onclick = function () {
modal[2].classList.toggle('show-modal')
if (modal[2].classList.contains('show-modal')) {
// Disable scroll
body.style.overflow = 'hidden'
} else {
// Enable scroll
body.style.overflow = 'auto'
}
}
trigger[3].onclick = function () {
modal[3].classList.toggle('show-modal')
if (modal[3].classList.contains('show-modal')) {
// Disable scroll
body.style.overflow = 'hidden'
} else {
// Enable scroll
body.style.overflow = 'auto'
}
}
// When the user clicks on (x), close the modal
closeButton[0].onclick = function () {
modal[0].classList.toggle('show-modal')
body.style.overflow = 'auto'
}
closeButton[1].onclick = function () {
modal[1].classList.toggle('show-modal')
body.style.overflow = 'auto'
}
closeButton[2].onclick = function () {
modal[2].classList.toggle('show-modal')
body.style.overflow = 'auto'
}
closeButton[3].onclick = function () {
modal[3].classList.toggle('show-modal')
body.style.overflow = 'auto'
}
// When the user clicks anywhere outside of the modal, close it
window.onclick = function (event) {
if (event.target == modal[0]) {
modal[0].classList.toggle('show-modal')
body.style.overflow = 'auto'
}
if (event.target == modal[1]) {
modal[1].classList.toggle('show-modal')
body.style.overflow = 'auto'
}
if (event.target == modal[2]) {
modal[2].classList.toggle('show-modal')
body.style.overflow = 'auto'
}
if (event.target == modal[3]) {
modal[3].classList.toggle('show-modal')
body.style.overflow = 'auto'
}
}
I'm using react.
I want to display the modal from the bottom when I press the btn button.
I want to show the modal from the bottom, like the modal on this site.
https://codepen.io/takapen/pen/jdwwWQ
I created a modal with the same structure as the modal on this site.
However, when I press the button, the modal is not displayed.
import React, { useState } from "react";
const App: React.FunctionComponent = () => {
const Spin = (
<style>
{`
#keyframes SlideUp {
0% {
opacity: 0;
transform: translateY(-1%);
}
100% {
opacity: 1;
transform: translateY(-80%);
}
}
`}
</style>
);
const [isCheck, setIsCheck] = useState(false);
console.log(isCheck);
return (
<>
<div
class="js-modal__btn"
onClick={() => {
setIsCheck(true);
}}
>
btn
</div>
<div
class="js-modal__bg"
style={{
width: "100%",
height: "100%",
backgroundColor: "rgba(0,0,0,0.6)",
position: "fixed",
top: 0,
left: 0,
zIndex: 10,
display: "none"
}}
></div>
<div
class="js-modal__main"
style={{
width: "calc(100% - 32px)",
height: "80%",
padding: "16px",
bottom: "-81%",
left: "0",
background: "#fff",
borderRadius: "4px 4px 0 0",
position: "fixed",
zIndex: 11,
opacity: "0",
animation: isCheck ? `${Spin} .5s ease-in-out forwards` : undefined
}}
>
<p>コンテンツ</p>
<p class="js-modal__btn--close">close</p>
<p class="js-modal__btn--close--fix"></p>
</div>
</>
);
};
export default App;
First, you need to render your style to the document.
Second, you need to use the correct name for the animation.
So you need to fix those lines:
return (
<>
// Render your style
{Spin}
// Use the keyframe's name
animation: isCheck ? `SlideUp .5s ease-in-out forwards` : undefined
</>
)
But I recommend you should:
Create the CSS file then import it
Toggle animation based on className will be better.
My solution
styles.css
.modal__bg {
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.6);
position: fixed;
top: 0; left: 0;
z-index: 10;
display: none;
}
.modal__main {
width: calc(100% - 32px);
height: 80%;
padding: 16px;
bottom: -81%;
left: 0;
background: white;
border-radius: 4px 4px 0 0;
position: fixed;
z-index: 11;
opacity: 0;
}
.modal__main-show {
animation: SlideUp .5s ease-in-out forwards
}
.modal__main-hide {
// or animation configs for slide out
animation: none
}
#keyframes SlideUp {
0% {
opacity: 0;
transform: translateY(-1%);
}
100% {
opacity: 1;
transform: translateY(-80%);
}
}
App.tsx
import React, { useState } from "react";
import "./styles.css";
const App: React.FunctionComponent = () => {
const [isCheck, setIsCheck] = useState(false);
return (
<>
<div
className="js-modal__btn"
onClick={() => {
setIsCheck((prev) => !prev);
}}
>
btn
</div>
<div className="modal__bg" />
<div
className={`modal__main ${
isCheck ? "modal__main-show" : "modal__main-hide"
}`}
>
<p>コンテンツ</p>
<p className="js-modal__btn--close">close</p>
<p className="js-modal__btn--close--fix"></p>
</div>
</>
);
};
export default App;
You can use isCheck to show modal like this:
{isCheck && <div class="js-modal__main">...</div>}
I created slide animation for my drop out menu, now I need to change the keyframes to make this menu not just disappear but smoothly hide in the same way it appears on the screen.
The issue is that I'm missing something or using the incorrect syntax for some of my approaches.
link to the repo:
https://github.com/kkdima/barva
For styling, I'm using styled-components, because it has these ThemeProvider features and variables options.
I was trying to fix this with the ThemeProvider but no success so far. It gives messages that something wrong with the props.
Also, I have 2 components in the same .js file, one of them is sharing state with another.
this.state = { menuTriggered: false };
this state is the reference to which keyframe should be animated, either bgAnimationOpen or bgAnimationClose.
In both of them, I have elements (Background and Ul) which need to be changed for the smooth backward animation.
The next code example has needed keyframes in the definition of Background div. The rest are stored in the separate KeyFrames.js file which I import.
Pardon me for such a long code, I just have styles inside my js files.
import Link from "next/link";
import React, { Component } from "react";
import styled, { ThemeProvider } from "styled-components";
import Logo from "./Logo";
import { menuAnimationOpen } from "../styles/KeyFrames";
import { menuToClose } from "../styles/KeyFrames";
import { closeToMenu } from "../styles/KeyFrames";
import { MenuToCloseBackwards } from "../styles/KeyFrames";
import { bgAnimationOpen } from "../styles/KeyFrames";
import { bgAnimationClose } from "../styles/KeyFrames";
class Menu extends Component {
constructor(props) {
super(props);
}
render() {
const { menuTriggered } = this.props;
return (
<div>
<ThemeProvider theme={theme}>
<Background />
</ThemeProvider>
<UL className="menuOpens">
<StyledLink href="/">
<Li>
<A>Home</A>
</Li>
</StyledLink>
<StyledLink href="/projects">
<Li>
<A>Projects</A>
</Li>
</StyledLink>
<StyledLink href="/about">
<Li>
<A>About</A>
</Li>
</StyledLink>
<StyledLink href="/contact">
<Li>
<A>Contact</A>
</Li>
</StyledLink>
</UL>
</div>
);
}
}
class SlideNav extends Component {
constructor(props) {
super(props);
this.state = { menuTriggered: false };
}
toggleMenu = () => {
this.setState({ menuTriggered: !this.state.menuTriggered });
};
render() {
const { menuTriggered } = this.state;
return (
<MenuWrapper className="menu">
<LogoAndMenuButton>
<Logo />
<MenuTextWrapper>
<Input type="checkbox" onClick={this.toggleMenu} />
<Span className="text-Menu">
<p>Menu</p>
</Span>
<Span className="text-Close">
<p>Close</p>
</Span>
</MenuTextWrapper>
</LogoAndMenuButton>
{menuTriggered ? (
<Menu
menuTriggered={this.state.menuTriggered}
>
{/* {this.props.children} */}
</Menu>
) : (
<div />
)}
</MenuWrapper>
);
}
}
export default SlideNav;
const StyledLink = styled(Link)``;
const MenuWrapper = styled.div`
width: 100vw;
box-sizing: border-box;
padding-left: 40;
background: grey;
`;
const LogoAndMenuButton = styled.div`
display: flex;
justify-content: space-between;
flex-direction: row;
margin: 0;
width: 100%;
`;
// MENU/CLOSE BUTTON STYLES:
// MENU/CLOSE BUTTON STYLES:
// MENU/CLOSE BUTTON STYLES:
const MenuTextWrapper = styled.div`
background: none;
border: none;
overflow: hidden;
width: 65px;
height: 26px;
padding: 0;
z-index: 1;
margin: 40px 40px;
/* Menu to Close text animation 1st span */
input[type="checkbox"]:checked ~ .text-Menu {
animation: ${menuToClose} 300ms ease-in-out;
animation-fill-mode: forwards;
}
/* Menu to Close text animation 2nd span */
input[type="checkbox"]:checked ~ .text-Close {
color: #fff;
animation: ${closeToMenu} 300ms ease-in-out;
animation-fill-mode: forwards;
}
/* Close to Menu text animation 2nd span */
input[type="checkbox"]:not(:checked) ~ .text-Menu {
animation: ${MenuToCloseBackwards} 300ms ease-in-out;
animation-fill-mode: forwards;
}
`;
const Input = styled.input`
position: absolute;
width: 65px;
height: 26px;
z-index: 2;
cursor: pointer;
margin: 0;
opacity: 0;
`;
const Span = styled.span`
justify-content: center;
display: flex;
color: black;
padding-bottom: 10px;
z-index: -1;
p {
font-size: 1.2rem;
margin: 0;
}
`;
//END OF MENU/CLOSE BUTTON STYLES;
//END OF MENU/CLOSE BUTTON STYLES;
//END OF MENU/CLOSE BUTTON STYLES;
const menuOpen = bgAnimationOpen, menuClose = bgAnimationClose;
const Background = styled.div`
position: absolute;
top: 0;
background-color: #222222;
box-sizing: border-box;
height: 100vh;
width: 100vw;
#keyframes bgAnimationOpen {
from {
transform: translateY(-900px);
}
to {
visibility: block;
}
}
#keyframes bgAnimationClose {
from {
transform: translateY(900px);
}
to {
visibility: block;
}
}
animation: ${bgAnimationOpen} 0.8s
cubic-bezier(0.215, 0.61, 0.355, 1);
animation-fill-mode: forwards;
`;
Background.defaultProps = {
theme: {
open: "bgAnimationOpen"
}
};
const theme = {
close: "bgAnimationClose",
open: "bgAnimationOpen"
};
// UL NAVIGATION STYLES:
// UL NAVIGATION STYLES:
// UL NAVIGATION STYLES:
const UL = styled.ul`
position: absolute;
top: 140px;
font-size: 32px;
font-weight: bold;
max-width: 200px;
margin: 0px 0px 0px 40px;
padding: 0px;
li:nth-of-type(1) {
animation: ${menuAnimationOpen} 0.8s 0.5s cubic-bezier(0.35, 0.25, 0, 1.28);
animation-fill-mode: forwards;
}
li:nth-of-type(2) {
animation: ${menuAnimationOpen} 0.8s 0.6s cubic-bezier(0.35, 0.25, 0, 1.22);
animation-fill-mode: forwards;
}
li:nth-of-type(3) {
animation: ${menuAnimationOpen} 0.8s 0.7s cubic-bezier(0.35, 0.25, 0, 1.15);
animation-fill-mode: forwards;
}
li:nth-of-type(4) {
animation: ${menuAnimationOpen} 0.8s 0.8s cubic-bezier(0.35, 0.25, 0, 1.1);
animation-fill-mode: forwards;
}
`;
const Li = styled.li`
opacity: 0;
list-style: none;
color: pink;
text-align: left;
line-height: 45px;
transition: transform 400ms ease-in;
&:hover {
transform: scale(1.1);
}
`;
const A = styled.a`
cursor: pointer;
text-decoration: none;
`;
The needed outcome is working animation back and force just as on the attached gif. Much love if you can help with any clue to resolving this!
PS. It's slightly out of topic but maybe somebody knows how to fix the gif in the logo background? In the end of the cycle or in the very beggining it dissapears and creates delay in couple sec where there's no gif background. How to keep it in the loop all the time with no dissapearence? even though it's on the loop by default
animation: gifs 60s infinite running;
I built simple Modal component which will slide from bottom when opened. Animations are working fine when Modal trigger button clicked and backdrop clicked. But i am seeing slide-down animation at initial render of page. How can i prevent initial animation ?? I am specifically looking how to solve with react hooks.
Modal.js
import React, { useRef, useEffect } from 'react';
import { createPortal } from 'react-dom';
import './Modal.css';
const Modal = ({ isOpen, onClose, children }) => {
const modalEl = useRef(null);
const handleCoverClick = (e) => {
if (e.target.hasAttribute('modal')) {
onClose();
}
}
useEffect(() => {
const handleAnimationEnd = (event) => {
if (!isOpen) {
event.target.classList.remove('show');
event.target.classList.add('hide');
} else {
event.target.classList.remove('hide');
event.target.classList.add('show');
}
};
modalEl.current.addEventListener('animationend', handleAnimationEnd);
return () => modalEl.current.removeEventListener('animationend', handleAnimationEnd);
}, [isOpen]);
return createPortal(
<>
<div className={`ModalCover ${isOpen ? 'show' : 'hide'}`} onClick={handleCoverClick} modal="true"></div>
<div className={`ModalContainer ${isOpen ? 'slide-up' : 'slide-down'}`} ref={modalEl}>
{children}
</div>
</>,
document.body);
};
export default Modal;
Modal.css
.show {
display: block;
}
.hide {
display: none;
}
.slide-up {
transform: translateY(0%);
animation: slide-up 0.5s forwards;
}
.slide-down {
transform: translateY(100%);
animation: slide-down 0.5s forwards;
}
#keyframes slide-up {
0% { transform: translateY(100%); }
100% { transform: translateY(0%); }
}
#keyframes slide-down {
0% { transform: translateY(0%); }
100% { transform: translateY(100%); }
}
.ModalCover {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 10;
background-color: rgba(0, 0, 0, 0.15);
}
.ModalContainer {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 400px;
margin-top: calc(100vh - 400px);
z-index: 20;
}
demo (codesandbox) : https://codesandbox.io/s/l7x5p4k82m
Thanks!
A simpler way is to do this with classNames since direct DOM access is discouraged with DOM. modalEl.current ref is assigned after initial render, it can be used as a flag that a component was mounted:
<div className={`
ModalContainer
${isOpen ? 'slide-up' : 'slide-down'}
${!modalEl.current && 'hide'}
`} ref={modalEl}>
Applying hide class on component mount in useEffect may result in briefly shown modal animation.