React Carousel - images with different widths display wrong - css

I have an array of URLs that I am passing in as a prop to a slide component. Only one URL is passed at a time using a stateful index. Whenever the right button is clicked, the index is incremented by 1 and vice versa for the left. This is working to display the next URL in the array; however, the images seem to repeat even though I set no-repeat on the background. This is due to the images being different widths and some being smaller than the last. I've tried setting the parent container to a set width so that the slide class is 100% the width of the parent but this doesn't seem to be working for me. Below are the two components that I'm using and the styles file.
//Parent carousel component
const HeroImage = ({state}) => {
const [index, setIndex] = useState(0);
var imgUrls = [];
const goToPrevSlide = () => {
setIndex(index - 1);
}
const goToNextSlide = () => {
setIndex(index + 1);
}
return(
<React.Fragment>
<StyledHeroImage>
<div className="slider-wrapper">
{state.heroImage.map(image => {
imgUrls.push(`${IMAGE_BASE_URL}${BACKDROP_SIZE}${image.backdrop_path}`);
})}
<Slide title={state.heroImage.original_title} text={state.heroImage.overview} image={imgUrls[index]}/>
</div>
<LeftArrow goToPrevSlide={goToPrevSlide}/>
<RightArrow goToNextSlide={goToNextSlide}/>
</StyledHeroImage>
</React.Fragment>
)
}
//child Slide Component
const Slide = ({image, text, title}) => {
const styles = {
background: `linear-gradient(to bottom, rgba(0,0,0,0) 39%, rgba(0,0,0,0) 41%, rgba(0,0,0,0.65) 100%), url(${image})`,
backgroundSize: 'cover',
backgroundRepeat: 'no-repeat',
backgroundPosition: 'center',
}
return(
<div className="slide" style={styles}>
<div className="heroimage-content">
<div className="heroimage-text">
<h1>{title}</h1>
<p>{text}</p>
</div>
</div>
</div>
)
}
//Styles file
export const StyledHeroImage = styled.div`
height: 650px;
width: 100%;
margin: 0 auto;
.slider-wrapper{
height: 100%;
width: 100%;
}
.slide{
width: 100%;
height: 100%;
}
.arrow{
height: 50px;
width: 50px;
display: flex;
align-items: center;
justify-content: center;
background: #f9f9f9;
border-radius: 50%;
cursor: pointer;
transition: transform ease-in .1s;
}
.nextArrow {
position: absolute;
top: 50%;
right: 25px;
z-index: 999;
color: #fff;
}
.backArrow {
position: absolute;
top: 50%;
left: 25px;
z-index: 999;
color: #fff;
}
.fa-arrow-right:before, .fa-arrow-left:before {
color: #222
}
`;

Related

How to fade or create a slider image change effect with React

I'm building a website with React and Frame Motion and in the slider I can't make sure that when the image changes there is a transition or effect other than the simple detachment of the image change.
I tried to do the same thing using the img tag instead of the backgroundImage css property but still couldn't create the effect.
This is the component:
import { useState, useEffect, useCallback } from 'react';
import { motion } from 'framer-motion';
function ImgSlider({ slides, children }) {
const [current, setCurrent] = useState(0),
length = slides.length,
time = 4000;
const handleNext = useCallback(() => {
current + 1 >= length ?
setCurrent(0) :
setCurrent(current + 1);
}, [current, length]);
const handlePrev = () => {
current === 0 ?
setCurrent(length - 1) :
setCurrent(current - 1);
};
useEffect(() => {
const autoplay = setInterval(handleNext, time);
return () => clearInterval(autoplay);
}, [handleNext]);
return (
<motion.section
className="slider flex space-around g-6"
style={{ backgroundImage: `url(${slides[current]})` }}
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: .5, ease: 'easeInOut' }}
exit={{ opacity: 0 }}
>
{children}
<button className="prev" onClick={handlePrev}>
<span className="sr-only">Slide Precedente</span>
</button>
<button className="next" onClick={handleNext}>
<span className="sr-only">Slide Successiva</span>
</button>
</motion.section>
);
}
export default ImgSlider;
and his css:
/* Slider */
section.slider {
min-height: 95vh;
padding: 1rem;
background-repeat: no-repeat;
background-size: cover;
background-position: center;
color: var(--bg);
}
section.slider button.prev,
section.slider button.next {
position: absolute;
right: 1rem;
top: 50%;
width: 3rem;
aspect-ratio: 1;
background-image: url(./imgs/arrow.svg);
background-repeat: no-repeat;
background-position: center;
opacity: .8;
transition: .3s ease-in-out;
}
section.slider button.prev {
transform: rotate(180deg);
left: 1rem;
right: unset;
}
section.slider button.prev:hover,
section.slider button.next:hover {
opacity: 1;
}
I don't know how I could do... Can anyone give me some suggestions?
Thank you :)

CSS position absolute elements not aligning properly with their sibling elements

I'm building out a custom Tooltip component in React that allows for rendering both to the right of the element as well as below it. I've decided to handle the functionality by having the Tooltip accept children which it then renders, and when those children are hovered the tip itself, positioned absolutely, will become visible through CSS classes. The effect works exactly how I want when the elements are stacked in a column and the tooltip is set to render to the right, but when the elements are laid out in a row with the tip rendering on the bottom, the tip itself becomes misaligned from the child its rendering -- the length of the tooltip text seems to offset it to the right.
Here's a codesandbox displaying the problem. You'll see that in the first state, when the elements are in a column, the tip is aligned perfectly. Click the button to toggle them into a row format and hover again to see that they are now misaligned:
https://codesandbox.io/s/busted-tooltip-obf0h1?file=/src/Tooltip.scss
How can I get the tips to align centered with their child element when I've chosen to have them render below it?
// Tooltip.jsx
import React, { useState } from 'react';
import './Tooltip.scss';
const Tooltip = ({ children, label, orientation = 'right' }) => {
const [isHovered, setIsHovered] = useState(false);
return (
<div className={`Tooltip__Container ${orientation}`}>
<div
onMouseOver={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
>
{children}
</div>
<div className={`Tooltip__Inner ${orientation} ${isHovered ? 'Visible' : ''}`}>
{orientation === 'right' && <div className={`Tooltip__PointLeft ${isHovered ? 'Visible' : ''}`} />}
{orientation === 'bottom' && <div className={`Tooltip__PointUp ${isHovered ? 'Visible' : ''}`} />}
<div className={`Tooltip ${orientation} ${isHovered ? 'Visible' : ''}`}>
{label}
</div>
</div>
</div>
);
};
export default Tooltip;
/* Tooltip.scss */
#import 'src/styles/colors.scss', 'src/styles/typography.scss', 'src/styles/breakpoints.scss';
.Tooltip__Container {
display: flex;
position: relative;
&.right {
flex-direction: row;
}
&.bottom {
flex-direction: column;
}
}
.Tooltip__Inner {
display: flex;
z-index: -1;
position: absolute;
transition: all .25s ease;
opacity: 0;
left: 0;
top: 0;
&.right {
flex-direction: row;
}
&.bottom {
flex-direction: column;
}
}
.Tooltip__Inner.right.Visible {
opacity: 1;
left: 3.5rem;
}
.Tooltip__Inner.bottom.Visible {
opacity: 1;
top: 3.5rem;
}
.Tooltip__PointLeft.Visible {
opacity: 1;
width: 0;
height: 0;
border-top: 10px solid transparent;
border-bottom: 10px solid transparent;
border-right: 10px solid $white-transparent;
align-self: center;
justify-self: center;
}
.Tooltip__PointUp.Visible {
opacity: 1;
width: 0;
height: 0;
width: 0;
height: 0;
border-left: 10px solid transparent;
border-right: 10px solid transparent;
border-bottom: 10px solid $white-transparent;
align-self: center;
justify-self: center;
}
.Tooltip {
background-color: $white-transparent;
padding: .75rem;
border-radius: 3px;
#include MainFont;
color: white;
}
For quick solution, you can update the bottom class inside .Tooltip__Inner
with this:
&.bottom {
flex-direction: column;
left: 50%;
-ms-transform: translate(-50%, 0);
transform: translate(-50%, 0);
}

Sidebar slides in and out on page refresh

I created a sidebar (hidden by default) in a web store that contains a list of items you like. When clicked on a button the likes-list will show sliding in from the right smoothly. However on page refresh/reload the sidebar slides in and out rapidly. I'm using css animation to do the trick.
It works fine but somehow on page reload the animation is triggered without clicking the button. How to prevent this from happening?
App is built in React (create-react-app).
React component
import React from 'react';
import { useGlobalContext } from '../Context'
import './likes.css';
const Likes = ({ showLikes, setShowLikes }) => {
let { liked, setLiked, paintings, setPaintings } = useGlobalContext()
//Remove item from likes list
const removeItemFromLikeslist = (id) => {
liked = liked.filter(item => {
return item.id !== id;
});
//Change likes-heart to green
paintings = paintings.map(el => {
if (el.id === id) {
el.like = false
}
return el
})
//remove sidebar overlay
if (liked.length === 0) {
setShowLikes(false)
}
setPaintings(paintings)
setLiked(liked)
localStorage.setItem("PAINTINGS", JSON.stringify(paintings))
localStorage.setItem('LIKES', JSON.stringify(liked))
}
return (
<div className={showLikes ? "likesContainer show" : "likesContainer"} >
<div className="likesHeader">You like these paintings</div>
{liked.map(item => {
const { id, name, imgSrc } = item;
return (
<div className="like-item" onClick={() => removeItemFromLikeslist(id)} key={id}>
<div className="like-info">
<img src={imgSrc} style={{ width: "100px" }} alt={name} className="picInCart" />
</div>
<div className="like-name">
<h5>{name}</h5>
</div>
</div>
)
})}
</div>
)
}
export default Likes
CSS file
.likesContainer {
position: fixed;
top: 83px;
right: -328px;
width: 320px;
background-color: rgb(70, 70, 70);
height:auto;
display: flex;
align-items: center;
justify-content: flex-start;
flex-direction: column;
z-index: 2;
box-shadow: 0px 4px 10px black;
animation: animateHide .5s linear forwards;
}
#keyframes animateHide {
from {
right: 0;
}
to {
right: -328px;
}
}
.likesContainer.show {
right: 0;
animation: animateShow .5s linear forwards;
}
#keyframes animateShow {
from {
right: -328px;
}
to {
right: 0;
}
}
Problem solved, changed from animation to transition like so:
.likesContainer {
position: fixed;
top: 83px;
right: -328px;
width: 320px;
background-color: rgb(70, 70, 70);
height:auto;
display: flex;
align-items: center;
justify-content: flex-start;
flex-direction: column;
z-index: 2;
box-shadow: 0px 4px 10px black;
transition: .5s ease-in-out;
}
.likesContainer.show {
right: 0;
}

Flipcard on mobile - First tap doesn't work

Working in Next.js. Currently trying to debug the mobile version of a site I'm working on. Just have a tiny hitch, the first flip-card tapped in mobile refuses to flip. If I tap multiple times on this "stubborn" card, it selects the text on the opposite side of the card. If I tap a different card, it flips properly. It doesn't matter which card I tap first, the result is that the initially tapped card doesn't flip (until I tap other cards and try again). This is a very confusing issue and I would appreciate even a direction to start looking in. Site currently running on d20dev.com
class SoloContent1 extends React.Component {
constructor(props) {
super(props);
this.state={
className1: "flipCard",
className2: "flipCard",
className3: "flipCard",
fadeOneA: "unFade",
fadeOneB: "fade",
fadeTwoA: "unFade",
fadeTwoB: "fade",
fadeThreeA: "unFade",
fadeThreeB: "fade",
}
this.flip1 = this.flip1.bind(this);
this.unflip1 = this.unflip1.bind(this);
this.flip2 = this.flip2.bind(this);
this.unflip2 = this.unflip2.bind(this);
this.flip3 = this.flip3.bind(this);
this.unflip3 = this.unflip3.bind(this);
}
flip1() {
this.setState({ className1 : "flipCard is-flipped", fadeOneA : "fade", fadeOneB : "unFade" })
}
unflip1() {
this.setState({ className1 : "flipCard", fadeOneA : "unFade", fadeOneB : "fade" })
}
flip2() {
this.setState({ className2 : "flipCard is-flipped", fadeTwoA : "fade", fadeTwoB : "unFade" })
}
unflip2() {
this.setState({ className2 : "flipCard", fadeTwoA : "unFade", fadeTwoB : "fade" })
}
flip3() {
this.setState({ className3 : "flipCard is-flipped", fadeThreeA : "fade", fadeThreeB : "unFade" })
}
unflip3() {
this.setState({ className3 : "flipCard", fadeThreeA : "unFade", fadeThreeB : "fade" })
}
render() {
return (
<div id="contentContainer">
<div className="contentCanvas contentCanvas--card">
<div className="contentCanvas contentCanvas--card">
<div className="flipCardContainer" id="flipContainer1" onMouseEnter={this.flip1} onMouseLeave={this.unflip1}>
<div className={this.state.className1} id="card1">
<div className="card__face card__face--front" id={this.state.fadeOneA}
style={{
backgroundImage: "url(" + `${require("../public/assets/JPG.jpg")}` + ")",
width: "100%",
height:"100%",
backgroundRepeat: "no-repeat",
backgroundSize: "cover",
backgroundPosition: "center",
}}
>
</div>
<div className="card__face card__face--back" id={this.state.fadeOneB}>
<div style={{
backgroundImage: "url(" + `${require("../public/assets/JPG.jpg")}` + ")",
width: "100%",
height:"100%",
backgroundRepeat: "no-repeat",
backgroundPosition: "center",
backgroundSize: "cover",
filter: "blur(20px)",
}}>
</div>
<p className="cardText" id="cardText1">TEXT</p>
</div>
</div>
</div>
</div>
</div>
.cardText {
position: absolute;
height: 100%;
width: 80%;
transform: translateY(-105%);
}
#cardText1 {
text-align: right;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 75%;
color: white;
font-size: calc(12px + 1.3vw);
text-shadow: 2px 2px 2px black;
}
#cardText2 {
text-align: center;
width: 90%;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
color: white;
font-size: calc(12px + 1.3vw);
text-shadow: 2px 2px 2px black;
}
#cardText3 {
text-align: left;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 75%;
color: white;
font-size: calc(12px + 1.1vw);
text-shadow: 2px 2px 2px black;
}
#contentContainer {
position: absolute;
height: 100%;
width: 100%;
background-image: url('image');
background-color: rgb(192,192,192);
border-radius: 8px;
transform: translateX(-225%);
overflow: hidden;
border: 5px solid silver;
box-sizing: border-box;
}
.contentCanvas {
z-index: 1;
height: 100%;
width: 100%;
margin: auto;
margin-top: 0%;
}
.flipCard {
margin: auto;
list-style: none;
font-size: 1.6em;
width: 100%;
height: 100%;
padding: 0;
display: inline-block;
transition: transform 0.5s;
transform-style: preserve-3d;
position: relative;
cursor: pointer;
}
.card__face {
position: absolute;
height: 100%;
width: 100%;
text-align: center;
}
.card__face--front {
background: white;
overflow: hidden;
}
.card__face--back {
background: black;
transform: rotateY( 180deg );
overflow: hidden;
}
.flipCard.is-flipped {
transform: rotateY( 180deg );
}
#card1 {
}
.flipCardContainer {
perspective: 40rem;
z-index: 1;
height: 100%;
width: 33.333333333333333333333333%;
margin: auto;
display: inline-block;
}
To me the problem comes from the event listener. Instead of having
mouseenter/leave, when being on mobile you should have a function
onClick. Then you would need to either change your current code or add
an extra toggleFlip() function to make it work nicely. – Aurélien B.
All credit for the answer goes to Aurélien B. in the comment above.

Circle image on hover occupy 100% height and width

Hi I'm trying to do an animation on hover, without the hover I would like my circle to make 100% of the height and width
and for some reason I am not able to leave my circle with 100% border radius
like this:
code:
export const TeamCard = styled.div`
background: red;
padding: 10px 0;
& .bgCircle {
border-radius: 50%;
padding: 64px;
background: hotpink;
}
`;
export default function App() {
return (
<TeamCard>
<div className="bgCircle" />
<div class="description">
<h3>huhuehu</h3>
<h3>testing</h3>
</div>
</TeamCard>
example:
https://codesandbox.io/s/dry-river-09ft0
Try using the following styled-div:
export const TeamCard = styled.div`
position: relative;
background: red;
height: 300px;
width: 300px;
& .bgCircle {
border-radius: 100%;
height: 50px;
width: 50px;
background: hotpink;
transition: all ease 333ms;
}
&:hover {
.bgCircle {
position: absolute;
top: 0;
height: 300px;
width: 300px;
border-radius: 0;
left: 0;
right: 0;
}
}
& .description {
position: absolute;
bottom: 0;
}
`;
This is making use of absolute positioning to correctly set where the circle should go. In order to make absolute positioning work, the containing element needs to have a position of something other than 'static'.
The transition property is what provides the animation.

Resources