如何实现类似DeviantArt的多图行排列,自适应视口且图片不变形
实现方案
纯CSS Flexbox方案(优先推荐,兼容性良好)
这个方案依靠弹性盒的拉伸特性实现整行填充,不需要额外JS逻辑,只要提前获取每张图片的原始宽高即可。
修改后的CSS代码:
/* 外层容器样式 */ .gallery-container { display: flex; flex-wrap: wrap; /* 统一控制卡片之间的间隙,代替原item内的padding间距逻辑 */ gap: 0.5em; width: 100%; } .item { /* 弹性属性:允许拉伸占满剩余空间、不强制缩小、基础宽度由图片比例决定 */ flex: 1 0 auto; position: relative; background: lightcoral; border: black solid 1px; padding: 0.5em; /* 可选:设置最小宽度避免过窄的图片被压缩到无法显示 */ min-width: 120px; display: flex; flex-direction: column; } .item img { /* 固定基础行高,可根据需求调整 */ height: 200px; width: 100%; /* 保持图片原始比例,完全显示不裁剪、不变形 */ object-fit: contain; /* 如果接受图片裁剪填满容器,可替换为 object-fit: cover; */ } /* 可选:最后一行不需要拉伸占满的话加上这段伪类,要拉伸直接删掉即可 */ .gallery-container::after { content: ""; flex-grow: 1000; }
修改后的HTML代码:
<div class="gallery-container"> <div class="item" v-for="(i, index) in images" :key="index"> <!-- 提前把图片原始宽高存在images数组,设置aspect-ratio保证容器比例和图片一致 --> <img :src="i.url" :style="{aspectRatio: `${i.width}/${i.height}`}"> <div style="display: flex; flex-direction: column; margin-top: 0.5em;"> <div>{{i.title}}</div> <div>By User1234</div> </div> </div> </div>
JS动态计算方案(兼容性最好、控制精度最高)
如果无法提前获取图片宽高,或者需要更精准的填充效果,可通过JS动态计算每行的缩放比例:
实现逻辑
- 预设基础行高,按比例算出每张图在该高度下的宽度
- 遍历图片累加宽度,加上间隙后刚好小于容器宽度的归为同一行
- 按容器宽度和当前行总宽度的比值,放大当前行所有图片的高度,让总宽度刚好填满容器
- 窗口尺寸变化时重新计算即可
示例代码(Vue环境可直接复用)
// 初始化调用时机:mounted钩子、图片列表加载完成、窗口resize时 function adjustGalleryLayout() { const container = document.querySelector('.gallery-container'); const containerWidth = container.clientWidth; const gap = 8; // 和CSS里gap对应,0.5em约等于8px const baseRowHeight = 200; // 基础行高,可自定义 let currentRowImgs = []; let currentRowTotalWidth = 0; document.querySelectorAll('.item img').forEach((img, idx) => { // 没有提前存宽高的话,可以通过img.naturalWidth/img.naturalHeight获取原始比例 const ratio = images[idx].width / images[idx].height; const imgBaseWidth = baseRowHeight * ratio; const addWidth = currentRowImgs.length ? (imgBaseWidth + gap) : imgBaseWidth; if (currentRowTotalWidth + addWidth <= containerWidth) { currentRowImgs.push({ img, ratio }); currentRowTotalWidth += addWidth; } else { // 计算当前行需要的高度,刚好填满容器 const usableWidth = containerWidth - (currentRowImgs.length - 1) * gap; const rowHeight = usableWidth / currentRowImgs.reduce((sum, item) => sum + item.ratio, 0); currentRowImgs.forEach(item => item.img.style.height = `${rowHeight}px`); // 重置行缓存 currentRowImgs = [{ img, ratio }]; currentRowTotalWidth = imgBaseWidth; } }); // 处理最后一行,不需要拉伸就用基础高度,要拉伸的话复用上面的逻辑即可 currentRowImgs.forEach(item => item.img.style.height = `${baseRowHeight}px`); } // 绑定窗口resize事件 window.addEventListener('resize', adjustGalleryLayout);
内容的提问来源于stack exchange,提问作者RedRK9
相关产品推荐
相关产品推荐

