如何将绝对定位的CloseButton锚定在滚动容器末端保持固定显示?
轮播组件关闭按钮固定定位失效问题
我开发了一个轮播组件,底部的BottomCarouselContainer容器内有个CloseButton关闭按钮,需要让按钮锚定在固定位置,即使容器向右滚动也始终可见。我尝试用相对定位的FixedContainer包裹按钮,让按钮绝对定位锚定它,但这个方案没生效,想知道原因和解决方法。
代码示例
import React from 'react' import styled from 'styled-components' const GalleryContainer = (props) => { const arrayOfImages=[...props.arrayImages]; const [selectedImage, setSelectedImage]=React.useState(arrayOfImages[0]) const image=arrayOfImages.map(imageName =>( <Photo key={arrayOfImages.indexOf(imageName)} img={require(`../../media/images/${props.folder}/${imageName}.JPG`)} onClick={()=>setSelectedImage(imageName)} /> )) function goToNextImage(){ if(arrayOfImages.indexOf(selectedImage)+1 <arrayOfImages.length) setSelectedImage(arrayOfImages[arrayOfImages.indexOf(selectedImage)+1]); } function goToPreviousImage(){ if(arrayOfImages.indexOf(selectedImage)>0) setSelectedImage(arrayOfImages[arrayOfImages.indexOf(selectedImage)-1]); } return ( <> <PhotoGalleryContainer display={props.display}> <PhotoContainer img={require(`../../media/images/${props.folder}/${selectedImage}.JPG`)}> <ArrowButton onClick={()=>goToPreviousImage()}><</ArrowButton> <RightArrow onClick={()=>goToNextImage()}>></RightArrow> <BottomCarouselContainer> <FixedContainer> <CloseButton>X</CloseButton> </FixedContainer> <Background arrayOfImages={arrayOfImages}/> {image} </BottomCarouselContainer> </PhotoContainer> </PhotoGalleryContainer> </> ) } export default GalleryContainer const PhotoGalleryContainer=styled.div` background:rgba(0,0,0); width:100%; height:100%; position:absolute; display:${(props)=> props.display}; z-index:2; animation:showGallery 1s; @keyframes showGallery{ 0% { height:20%; } 100% { height:100%; } } ` const PhotoContainer=styled.div` height:100%; width:100%; background-image: url( ${(props)=>props.img}); background-repeat: no-repeat; background-size: cover; background-position: center; display:flex; align-items:flex-end; margin:0 auto; position:relative; @media(min-width:1068px){ width:80%; } ` const BottomCarouselContainer=styled.div` display:flex; position:relative; border:1px solid white; height:30%; width:90%; margin:20px auto; display:${(props)=>props.display}; flex-wrap: nowrap; overflow-x: auto; -webkit-overflow-scrolling: touch; &::-webkit-scrollbar { height:8px; } &::-webkit-scrollbar-track { box-shadow: inset 0 0 5px grey; border-radius: 10px; } &::-webkit-scrollbar-thumb { border-radius: 10px; background: #555; } &::-webkit-scrollbar-thumb:hover { background: #333; } ` const FixedContainer=styled.div` position:relative; padding:5px 15px 5px 15px; ` const Background=styled.div` //for blured background position: absolute; height:100%; width:${(props)=>100*props.arrayOfImages.length}px; //an image is 80px and it's margins are 20px background-color:rgba(0,0,0,0.3); backdrop-filter: blur(10px); ` const ArrowButton=styled.div` position:absolute; color:white; font-size:20px; z-index:3; top:50%; transform: translateY(-50%); text-shadow: 1px 1px 18px black; height:25px; width:20px; font-weight:bold; border-radius:5px; text-align:center; line-height:25px; &:hover{ cursor:pointer; background:rgba(0,0,0,0.3); } ` const RightArrow=styled(ArrowButton)` right:0; ` const Photo=styled.div` height:80%; width:80px; background-image: url( ${(props)=>props.img}); background-repeat: no-repeat; background-size: cover; background-position: center; margin:auto 10px; opacity: 0.6; z-index:2; box-shadow: 1px 1px 18px black; flex: 0 0 auto; transform: translateX(-${(props)=>props.translate}px); &:hover{ opacity:1; cursor:pointer; } ` const CloseButton=styled.div` color:white; font-size:15px; top:2px; right:5px; width:20px; height:20px; text-align:center; line-height:20px; z-index:3; border-radius:50%; background:rgba(0,0,0,0.7); position:absolute; &:hover{ cursor:pointer; background:rgba(255,0,0,0.7); } `
失效原因
FixedContainer是BottomCarouselContainer的子元素,设置position: relative后仍属于滚动容器的内容流,会跟着容器的水平滚动一起移动,内部的绝对定位按钮自然也会被带跑。BottomCarouselContainer开启了overflow-x: auto,它的滚动区域是自身内部所有子元素,相对定位的容器无法脱离这个滚动流。
解决方法
方案1:将按钮移出滚动容器,基于父容器定位
把关闭按钮从滚动容器中取出,放到PhotoContainer(已设置position: relative)里,直接基于父容器固定位置:
- 修改JSX结构:
<PhotoContainer img={require(`../../media/images/${props.folder}/${selectedImage}.JPG`)}> <ArrowButton onClick={()=>goToPreviousImage()}><</ArrowButton> <RightArrow onClick={()=>goToNextImage()}>></RightArrow> {/* 移动关闭按钮到这里 */} <FixedContainer> <CloseButton>X</CloseButton> </FixedContainer> <BottomCarouselContainer> <Background arrayOfImages={arrayOfImages}/> {image} </BottomCarouselContainer> </PhotoContainer>
- 调整
FixedContainer样式:
const FixedContainer=styled.div` position:absolute; bottom:40px; /* 对应BottomCarouselContainer的margin:20px auto */ right:5%; /* 对应BottomCarouselContainer的width:90% */ padding:5px 15px 5px 15px; `
方案2:使用position: sticky(更简洁)
直接给关闭按钮设置sticky定位,让它在滚动容器内固定在指定位置:
- 修改
CloseButton样式:
const CloseButton=styled.div` color:white; font-size:15px; top:2px; width:20px; height:20px; text-align:center; line-height:20px; z-index:3; border-radius:50%; background:rgba(0,0,0,0.7); position:sticky; /* 替换absolute为sticky */ left: calc(100% - 30px); /* 固定在容器右侧,根据自身宽度和padding计算 */ align-self:flex-start; /* 垂直方向对齐顶部 */ &:hover{ cursor:pointer; background:rgba(255,0,0,0.7); } `
- 简化JSX结构(去掉
FixedContainer):
<BottomCarouselContainer> <CloseButton>X</CloseButton> <Background arrayOfImages={arrayOfImages}/> {image} </BottomCarouselContainer>
内容的提问来源于stack exchange,提问作者Andreea
相关产品推荐
相关产品推荐

