响应式布局卡片/视频封面等比缩放实现

935 阅读2分钟

“我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第1篇文章,点击查看活动详情

阅读时间: 5~10mins

最近在做整站布局改造,需要把站点由静态布局改成响应式布局。工程量很大,不过遇到了些较为有趣的实现,简单记录下。

如果你不熟悉网站布局的几种常见形式,可以看: 静态布局、自适应布局、流式布局、响应式布局、弹性布局等的概念和区别 - 腾讯云开发者社区-腾讯云 (tencent.com)

把固定的宽度改成释放宽度通常流式布局就可以,也就是说我们把硬编码的宽度放开,改成100%让渲染器自己计算。但是在一些卡片列表和视频封面的情况下需要额外考虑,做成等比缩放。

示意图:

Untitled.png

可以看出如果为了让保持卡片的内容(通常是封面图)不变形,需要每个条目的高度也新增。

Untitled2.png

水平方向我们可以使用 calc 让每个卡片均分容器宽度:

.card {
    width: calc(100% / 3);
}

在垂直方向我们会遇到困难,因为css的height百分比取值,是依据宽度百分比计算的,而不是我们期望的自身父容器高度。

但是幸运的是,垂直方向 padding 取值是根据自身父容器高度百分比计算的(乌拉!),使用css hack:

.card {
    position: relative;
    padding-bottom: 56.25%; /* 16:9 */
    padding-top: 25px;
    height: 0;
}

这样我们就完成了高宽等比缩放实现。

另外,如果卡片包含的内容比较复杂,比方说包含一个播放中第三方的视频页面,我们会使用iframe嵌套。如果必须给iframe指定高宽的情况,我们可以使用 useRect 优雅获得卡片高宽值:

useRect 是个十分实用的 React Hook: useRect — getBoundingClientRect() React Hook with resize handler · GitHub

import { useRect } from '@/util'
 
const Card = () => {
    const ref = useRef()
    const { height, width } = useRect(ref)

    return <div className="card" ref={ref}>
        <iframe src="blahblah" height={height} width={width} />
    </div>
}

如此一来,卡片中的第三方视频大小就会跟随我们放大缩小视窗而自动调整大小。

当然,如果不需要显式指定,也可以让渲染引擎帮忙:

.card iframe { 
    position: absolute; 
    top: 0; 
    left: 0; 
    border: 0; 
    width: 100%; 
    height: 100%; 
}

效果演示:

3yp0g-zr0tv.gif