CSS Grid调整项尺寸时防止换行并保留两侧间隙的实现方案
问题:CSS Grid布局动态调整项尺寸导致换行与定位问题
我有一个6列10行的CSS Grid图片布局。当网格项滚动到中心位置时,会通过修改span值调整尺寸,这会导致最后一列的项换行,进而改变图片位置。这种换行效果很突兀,让导航或滚动到下一张图片的操作变得不可预测。
我希望在保持6×10布局的前提下,实现网格项居中对齐,同时在网格两侧留有间隙。
目前尝试的方案是在每行的首尾向图片数组中添加网格项,并在图片调整尺寸时缩小这些额外项,但尚未成功。
另外,图片分为横版(1×1)和竖版(1×2)两种规格。竖版图片会将下方图片推挤到下一行,这是预期效果,但我希望调整图片宽度时避免行发生换行。

以下是实现图片尺寸调整逻辑的代码:
import React from "react"; import { useEffect, useState, useRef} from "react"; import styled from "styled-components"; const PhotoGrid = (props) => { const sortPhotos = (a, b) => a.index - b.index; const [photos, setPhotos] = useState(null) const [imgCount, setImgCount] = useState(0) const gridRef = useRef(null); const gridWrapperRef = useRef(null) const [imagesLoaded, setImagesLoaded] = useState(false); const [photoId, setPhotoId] = useState(null) const imgCounter = () => { setImgCount(imgCount + 1) console.log("images loaded", imgCount, props.photos.length, photos.length) if (imgCount + 1 === 60){ setImagesLoaded(true) console.log("images loaded") } } const scrollPosition = () => { if (props.mobile){ const grid = gridRef.current; const photos = grid.children const gridWrapper = gridWrapperRef.current; const gridWrapperRect = gridWrapper.getBoundingClientRect() const gridWrapperWidth = gridWrapperRect.width const height = gridWrapperRect.height for (let i = 0; i < photos.length; i++) { let photo = photos[i]; const gridItem = photo.getBoundingClientRect(); const top = Math.abs(gridItem.top) const left = Math.abs(gridItem.left) const centered = (top >= height * .25 && top < height * .4) && (left >= gridWrapperWidth * .3 && left <= gridWrapperWidth * .5) const findCenter = () => { if (centered && !!photo){ return eval(photo.id) } } const centeredId = findCenter() const changeCells = (centeredId) => { if (!!centeredId){ const centeredType = !!photos[centeredId].getElementsByClassName("tile").length const centeredOrientation = !!photos[centeredId].getElementsByClassName("portrait").length const first = Math.floor(centeredId/6) * 6 const range = centeredOrientation ? 16 + first : 11 + first for (let i = first; i < range; i++){ let rangePhoto = photos[i]; const rangeOrientation = !!rangePhoto?.getElementsByClassName("portrait").length const rangeType = !!photos[i].getElementsByClassName("tile").length if (!!rangePhoto){ if (!centeredType){ if (eval(rangePhoto.id) === centeredId && photoId !== centeredId){ setPhotoId(eval(rangePhoto.id)) if (!rangeType){ if (!rangeOrientation){ console.log("rangeType", rangeType, rangePhoto.firstChild, rangePhoto, rangePhoto.style) rangePhoto.style.gridColumnEnd = `span 80` rangePhoto.style.gridRowEnd = `span 80` rangePhoto.firstChild.style.height = '220px' rangePhoto.firstChild.style.width = '240px' rangePhoto.firstChild.style.top = '50%' setPhotoId(null) } else { rangePhoto.style.gridColumnEnd = `span 80` rangePhoto.style.gridRowEnd = `span 120` rangePhoto.firstChild.style.height = '340px' rangePhoto.firstChild.style.width = '240px' rangePhoto.firstChild.style.top = '50%' setPhotoId(null) }} else{ console.log("rangePhoto", rangePhoto.firstChild, rangePhoto, rangePhoto.style) rangePhoto.style.gridColumnEnd = `span 1` rangePhoto.style.gridRowEnd = `span 1` } } if (eval(rangePhoto.id) !== centeredId){ if (!rangeOrientation){ rangePhoto.style.gridColumnEnd = `span 32` rangePhoto.style.gridRowEnd = `span 40` rangePhoto.firstChild.style.height = '100px' rangePhoto.firstChild.style.top = '50%' } else { rangePhoto.style.gridColumnEnd = `span 32` rangePhoto.style.gridRowEnd = `span 80` rangePhoto.firstChild.style.height = '220px' rangePhoto.firstChild.style.top = '50%' } } } else{ if (!rangeOrientation){ rangePhoto.style.gridColumnEnd = `span 40` rangePhoto.style.gridRowEnd = `span 40` rangePhoto.firstChild.style.width = '120px' rangePhoto.firstChild.style.height = '100px' } else { rangePhoto.style.gridColumnEnd = `span 40` rangePhoto.style.gridRowEnd = `span 80` rangePhoto.firstChild.style.width = '120px' rangePhoto.firstChild.style.height = '220px' rangePhoto.firstChild.style.top = '50%' } } } } return [first, range] } } const rowState = changeCells(centeredId) const reset = () => { for (let i = 0; i < photos.length; i++) { let photo = photos[i]; const orientation = !!photo.getElementsByClassName("portrait").length const type = !!photo.getElementsByClassName("tile").length if (!!rowState){ if((eval(photo.id) > rowState[1]) || (eval(photo.id) < rowState[0])){ if (!orientation){ photo.style.gridColumnEnd = `span 40` photo.style.gridRowEnd = `span 40` photo.firstChild.style.height = '100px' photo.firstChild.style.width = '120px' } else { photo.style.gridColumnEnd = `span 40` photo.style.gridRowEnd = `span 80` photo.firstChild.style.height = '220px' photo.firstChild.style.width = '120px' } }} }} reset(rowState) } } } useEffect(() => { const grid = gridRef.current; const gridWrapper = document.getElementById("grid-wrapper"); const gridRect = grid?.getBoundingClientRect() if (!!gridRect){ const center = gridRect.width/2 gridWrapper.scrollLeft = center } }, [!!gridRef.current === true]) useEffect(() => { !!props.photos && setPhotos([...props.photos]) }, [props.photos]) return ( <article > <> <div id="grid-wrapper" className="grid-wrapper" onScroll={() => scrollPosition()} ref={gridWrapperRef} > <Grid ref={gridRef} className="grid" style={{ opacity: imagesLoaded ? 1 : 0 }} > {!!photos && !photos !== !null && photos !== undefined && photos.sort(sortPhotos).map((photo) => ( <GridItem className="grid-item" id={photo.index} mobile={props.mobile} edit={props.edit} key={photo.index} orientation={photo.orientation} url={!!photo.url} photo={photo} collaborator={!!photo.u_id && props.folderCollaborators.filter(user => user.uuid === photo.u_id)} colorArr={props.colorArr} highlight={photo.color} > <PictureFrame className={!!photo.url ? photo.orientation ? "picture landscape" : "picture portrait" : 'tile landscape'} mobile={props.mobile} url={photo.url} highlight={photo.color} contentSizing={!!photo.name || !!photo.details} enableDelete={props.enableDelete} orientation={photo.orientation} > <img className="photo" onLoad={() => imgCounter() } src={ !!photo.thumbnail_url ? photo.url : require('../assets/100x135.png') } /> </PictureFrame> </GridItem> ))} </Grid> </div> </> </article> ); }; export default PhotoGrid; const Grid = styled.div` display: grid; grid-gap: 2px; grid-auto-rows: 1px; background: black; grid-template-columns: repeat(241, minmax(1px, 1px)) ; position: relative; width: fit-content; @media (max-width: 700px) { padding-block-start: 20vh; padding-block-end: 40vh; padding-inline: 40vw; }; .grid-item { position: relative; grid-row-end: span 40; grid-column-end: span 40; }; ` const GridItem = styled.div` z-index: ${({url}) => url ? "1" : "-5"}; ` const PictureFrame = styled.div` position: relative; left: 50%; top: ${({orientation}) => orientation ? '50%' : '100%' }; transform: translate(-50%, -50%); padding: 0px; overflow: hidden; height: ${({orientation}) => orientation ? '100px' : '220px'}; display: flex; justify-content: center; border-radius: 13px; width: 120px ; max-width: calc(100% - 15px); transition: height .1s ease-in, width .1s ease-in, border-radius .2s ease-out, background-color 0s linear 1s, max-width .3s ease-out .2s, padding-right .2s ease-out .1s, padding-left .2s ease-out .1s, padding-block .2s ease-out .1s, ${({url}) => url ? 'box-shadow .2s ease-in .6s' : 'box-shadow .3s ease-in'}; .photo { max-height: 110%; } `
内容的提问来源于stack exchange,提问作者user16159725
相关产品推荐
相关产品推荐

