Im trying to make a carousel with arrows. for the arrows to be in the right position and look pretty, im using a negative margin (margin: -Npx).
This causes the arrow to be hidden inside the carousel.
ive trying applying z-index: 9999.
overflow-x of carousel cannot be visible (per design)
const CarouselWrapper = styled.div`
display: flex;
flex-wrap: nowrap;
overflow-x: hidden;
position: relative;
scroll-snap-type: x mandatory;
&::-webkit-scrollbar {
display: none;
}
& > * {
scroll-snap-align: start;
}
`;
const ArrowsContainer = styled.div`
display: flex;
align-items: center;
position: absolute;
width: 100%;
justify-content: space-between;
top: 50%;
transform: translateY(-50%);
pointer-events: none;
`;
const ArrowWrapper = styled.div`
background: white;
border-radius: 50%;
display: flex;
opacity: 0.7;
padding: ${rem(8)};
pointer-events: auto;
box-shadow: 0px 10px 6.2px -4.95px rgba(0, 0, 0, 0.06),
0px 0px 10.2px 0.55px rgba(0, 0, 0, 0.02);
visibility: ${({ show }) => (show ? 'visible' : 'hidden')};
&:first-child {
margin-left: ${rem(-20)};
}
`;
const CarouselContainer = styled.div`
position: relative;
`;
<CarouselContainer>
<CarouselWrapper ref={ref}>{children}</CarouselWrapper>
{showArrows && (
<ArrowsContainer>
<ArrowWrapper
show={scrollPosition !== 0}
onClick={() => scrollToNext(ref.current, -1)}
>
<ChevronLeft style={{ width: 24, height: 24 }} />
</ArrowWrapper>
<ArrowWrapper
show={scrollPosition !== maxScrollValue}
onClick={() => scrollToNext(ref.current)}
>
<ChevronRight style={{ width: 24, height: 24 }} />
</ArrowWrapper>
</ArrowsContainer>
)}
</CarouselContainer>
Seems the
`&:first-child {
margin-left: ${rem(-20)};
}`
has an effect on both the left and the right arrows as you are targeting in both cases the <ChevronLeft /> and the <ChevronRight /> with the &:first-child selector. You can remove this from the ArrowWrapper styled component and add the margin in the style tag inside the <ChevronLeft /> and the <ChevronRight />
Related
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);
}
I tried to use antdesign drawer in react and it doesnt scroll properly on safari.
Currently my code looks like.
<Drawer
placement="right"
closable={!!fullCheckout}
onClose={() => setVisible(false)}
visible={visible}
getContainer={false}
style={{
position: "absolute",
height: `calc(100vh - ${view === "MobileView" ? "50px" : "55px"})`,
top: `${view === "MobileView" ? 0 : "55px"}`,
}}
width={fullCheckout ? "100%" : 455}
>
<CheckoutDrawContainer>
<TopContainer />
<BottomContainer />
</CheckoutDrawContainer>
</Drawer>
The issue is the scroll is not working properly on safari, iphone.
export const CheckoutDrawerContainer = styled.div`
display: flex;
flex-direction: column;
position: relative;
-webkit-overflow-scrolling: touch !important;
height: ${({ view }) => (view !== "MobileView" ? "calc(100vh - 50px)" : "")};
`;
export const CheckoutDrawerTopContainer = styled.div`
background-color: ${primary[0]};
height: 258px;
padding: 0 21px;
padding-top: 27px;
z-index: 9;
`;
export const CheckoutDrawerBottomContainer = styled.div`
background-color: white;
padding: 0 21px;
padding-top: 80px;
height: 500px;
`;
I think it is related to the vh on safari, iphone.
Thanks in advance
While implementing a simple toggle control I encountered a problem that only seems to appear in Safari. The same code works fine in Firefox and Chrome.
.mgs.huge {
font-size: 36pt;
}
input.mgs.toggle {
display: none;
}
label.mgs.toggle {
display: flex;
flex-direction: row;
align-items: center;
width: max-content;
position: relative;
--toggle-color: 49, 112, 212;
}
/* The toggle background. */
label.mgs.toggle::before {
display: inline-block;
content: "";
height: 12px;
width: 23px;
border: 1px solid rgba(var(--toggle-color), 1);
background-color: rgba(var(--toggle-color), 0.75);
border-radius: 25pt;
margin-right: 4px;
}
label.mgs.toggle.huge::before {
height: 35px;
width: 69px;
}
/* The circle (handle) in the toggle - unchecked, standard size. */
label.mgs.toggle::after {
flex: 0 0 auto;
align-self: center;
content: "";
position: absolute;
width: 12px;
height: 12px;
left: 1px;
background-color: white;
border-radius: 50%;
transition: left 0.2s;
}
label.mgs.toggle.huge::after {
width: 35px;
height: 35px;
}
input:checked.mgs.toggle.huge + label::after {
left: 35px;
}
<input type="checkbox" class="mgs toggle huge" readonly="" id="toggle6" value="">
<label for="toggle6" class="mgs toggle huge">Huge</label>
In Safari the white knob doesn't align vertically. By specifying a top value you can align it manually (in this case by adding 11px top to label.mgs.toggle.huge::after), but unfortunately this shows another problem: Firefox doesn't use the same vertical offset as Chrome and Safari do: the circle is offset subtly by half a pixel or so.
Hence I would prefer a solution where Safari does the automatic vertical centering, as it is supposed in this flex-box layout.
Here's also a fiddle to play with: https://jsfiddle.net/3Ltkwaux/.
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
}
`;
i'm trying to create a custom button for my portfolio.
This button will be animated, the top part sliding in from left and the bottom part sliding in from right when hovered.
At the center of it will be the Category linked to this button.
Here an illustration :
How can i set my text in the center for every that i will create ? I can't use "position: absolute" property cause the reference would be the webpage and not the position where the custom component is declared...
Here my actual code :
CSS
const CatStyle = styled.div`
box-shadow: 0px 0px 2px 2px rgba(0,0,0,0.75);
height: 50px;
max-width: 150px;
background-color: white;
display: flex;
justify-content: center;
flex-direction: column;
cursor: pointer;
transition : background-color 0.5s ease-out;
:hover div{
display: flex;
}
.catContent {
position: relative;
align-self: center;
font-size: 1.5rem;
}
.topSlideAnimation {
display: none
height: 50%;
background-color: green;
}
.botSlideAnimation {
transition : background-color 0.5s ease-out;
display: none;
height: 50%;
background-color: blue;
}
`
JSX
const ButtonCat = (props) => (
<CatStyle>
<div className="topSlideAnimation"></div>
<div className="catContent">Hello</div>
<div className="botSlideAnimation"></div>
</CatStyle>
)
Not done any jsx so not sure what your catstyle tag would render, but if you can just render a button (or div), I would do the following
Make an outer container that is flex (for aligning text in center)
Make an inner container that is for the text (so you can position it relatively and add a z-index to it)
Add pseudo elements to your outer container for the animated bits (rather than having 2 empty divs)
* {
box-sizing: border-box;
}
.button {
display: inline-flex; /* make flex for centring */
justify-content: center; /* vertically centre */
align-items: center; /* horizontally centre */
position: relative; /* for adding absolute positioned children */
min-height: 50px; /* test value to show text is centred */
overflow: hidden; /* hide pseudo elements when not shown */
}
.button:before,
.button:after {
content: ''; /* make coloured animatable bits */
display: block;
height: 50%;
width: 100%;
position: absolute;
transition: all 1s ease-in;
z-index: 1;
}
.button:before {
top: 0;
right: 100%;
background: grey;
}
.button:hover:before {
right: 0;
}
.button:after {
top: 50%;
left: 100%;
background: darkgrey;
}
.button:hover:after {
left: 0;
}
.text {
position: relative; /* needs to have a higher z-index than the pseduo elements so text appears on top */
z-index: 2;
}
<button class="button"><span class="text">test content</span></button>