Netflix 浏览页面的设计在过去几年中一直保持着相似性。一个主要的组件是预览滑块,它允许用户滚动浏览内容并悬停在项目上以查看预览。
UI 的一个独特特点是其悬停行为。当节目预览在悬停时展开时,它旁边的卡片会向外推,这样它们就不会重叠。
就像这样

我们可以用 CSS 来实现!不需要 JavaScript。没有依赖项。纯 CSS。但在深入任何代码之前,以下是我们想要做的事情
- 悬停的卡片应该展开,同时保持其纵横比。
- 当卡片悬停时,其他卡片不应该改变大小,并且向外移动,以避免彼此重叠。
- 所有卡片应该彼此垂直居中。
听起来不错?现在让我们进入代码。
HTML 和弹性元素
让我们设置一行图像,代表 Netflix 的视频预览。这包括
- 一个
.container
父元素,其中包含多个.item
元素 - 每个
.item
元素包含一个包裹在锚标签中的图像 - 将
.container
变成一个 flex 容器,将项目水平对齐 - 为
.item
类设置 flex 行为,以便它们在行中占用相等的空间
悬停时展开项目
我们的下一步是让项目在悬停时展开。我们可以通过为元素的 width
设置动画来实现,但这会影响文档的流,并导致悬停项目的兄弟节点收缩 - 此外,为 width
属性设置动画在某些情况下会导致 性能下降。
为了避免挤压悬停项目的兄弟节点,我们将为 transform
属性(具体来说是它的 scale()
函数)设置动画,而不是 width
。这不会像 width
那样影响文档流。
将兄弟节点向外移动
让悬停项目的兄弟节点远离悬停项目是整个过程中最棘手的部分。我们可以使用的一个 CSS 功能是 通用兄弟节点组合器。这让我们可以选择所有位于悬停项目之后的兄弟节点。
我们将转向 transform
属性的 translateX()
函数来移动事物。同样,为 transform
设置动画比其他影响文档流的属性(如边距和填充)要好得多。
由于我们已将项目在悬停时设置为放大 150%,因此平移应该设置为 25%。这是悬停项目占用额外空间的一半。
.item:hover ~ .item {
transform: translateX(25%);
}
这处理了向右移动,但我们如何平移左侧的项目?由于通用兄弟节点组合器仅适用于位于给定选择器之后的兄弟节点(不能“向后”),因此我们需要另一种方法。
一种方法是在父容器本身添加一个额外的悬停规则。以下是计划
- 当悬停父容器时,将容器内的所有项目向左移动。
- 使用通用兄弟节点组合器使位于悬停项目之后的项目向右移动。
- 变得超级具体,这样悬停的项目就不会像其他项目一样被平移。
我们假设您的文档使用的是从左到右的书写模式。如果您想在从右到左的上下文中使用此效果,您需要将悬停的外部容器内的所有项目都向右移动,并使用通用兄弟节点组合器将所有选定的项目向左移动。
演示时间!
还有一点需要注意:此最终版本使用 :focus
和 :focus-within
伪类来支持键盘导航。Netflix 示例没有使用它,但我认为这对无障碍性来说是一个不错的补充。
就是这样!是的,我们可以使用 JavaScript 事件监听器而不是 CSS 悬停规则,这可能更有利于维护和可读性。但有时看到 CSS 能做到什么程度很有趣!
我认为在每个项目中添加一些内容(例如 Netflix 示例)会很好,因为这是一种更有用的情况,而且实现起来更难。
要实现它,您可以将所有项目缩小比例,然后将悬停项目缩放到 1,这样每个卡片内的内容都将保持其原始大小。
如果项目有始终可见的内容,这就会变得更加复杂。
让我想到了这个
说实话,这可能是 Netflix 只有在卡片完全展开后才显示信息的原因。这是一个非常好的观点。我想尝试在里面放一些内容,看看是否可以成功。
(抱歉,我的英语)我认为这非常棒,但如果你仔细看,你会发现第一个和最后一个图像存在问题,因为当它们悬停时,图像不会完全显示出来。我认为你可以用一些针对第一个和最后一个子元素的 CSS 来改进它。我提供了我的 CSS 代码。
但再次感谢,这真的很有帮助。
https://github.com/DvSemicolon/Nextflix-List
嘿,Chris,
这确实非常酷。
我在我的一个小项目中做了一个类似的动画(https://github.com/souravbaranwal/superflix)。
我真的很想得到一些反馈。
实时链接:https://superflix.sourav.co/。
此致,
Sourav
这很棒 - 谢谢分享!
这是一个很好的例子,说明为什么你需要深入了解 CSS。与 Javascript 相比,它的实现速度要快好几个数量级。推理和写作都很棒;我专门来这里是为了看看人们如何思考设计问题,这是一个很好的例子。
非常有帮助。谢谢!我的在缩放时会切断顶部。您能告诉我为什么吗?https://codepen.io/PixelRelish/pen/eYpzxpw
嘿,Sheila - 我相信你的问题与溢出有关。如果我将
.previewScroller
容器的溢出设置(x 和 y 轴)替换为基本的overflow: visible
,那么图像就会扩展到容器之外。不过,您可能需要进一步调整才能与可滚动容器一起使用。顺便说一句,非常酷的实现!
天啊:真是一个简单的解决方法!谢谢,Chris - 谢谢你的帮助以及所有很棒的文章。我喜欢 CSS Tricks。
不错。不过我注意到两件事,我想知道是否/如何解决它们
在缩放元素(但不平移兄弟节点)时,如果快速将鼠标悬停在相邻的兄弟节点上,它会有点“卡顿”,争抢着渲染到最上面。这可以使用 z-index 解决吗?
在缩放和平移时,如果快速将光标跨越元素,它们之间会短暂出现一些空白。也许平移和缩放之间的过渡持续时间需要以特定方式调整?
您可能已经注意到,Netflix 最近(我用这个词很宽泛)开始在您将鼠标悬停在视频上时播放视频样本。我不是要求您完全复制它的实现方式,我只是想知道这是否可以用纯 CSS/HTML5 实现,还是需要使用一些 JS?
非常感谢您的分享!我建议将 .itm 过渡属性设置为 500ms 来解决图像失去悬停状态时的重叠问题。
感谢您分享这个酷炫的演示,Chris。我能够使用它并添加滑块动画来显示点击更多项目。感谢您的启发 :)
嗨!这真的很棒。感谢您分享。我尝试过,并将我的图像从文件夹中添加进来,但不知何故它不起作用。你能告诉我悬停功能可能无法工作的可能原因吗?谢谢。
在 Chrome 中,如果您在图像之间快速移动然后取消悬停,您会看到这个错误:https://imgur.com/a/QO6NdGq
要修复它,请添加属性:
transform: scale(1);
到.item { }
。应该像这样
.item {
position: relative;
display: block;
flex: 1 1 0px;
transition: transform 500ms;
transform: scale(1);
}
你好!我刚开始学习 CSS... 我想要一个 Netflix 轮播图。我使用 Divi 主题和 divi 博客轮播模块。我在自定义设置中添加了这些 CSS,但它不起作用。我应该在轮播图中添加一个(或几个)类吗?非常感谢您!
activitesenergotherapie.com
嗨!这个技巧很棒!但是 Netflix 在悬停时会显示其他信息。当悬停时,添加其他 div 的最佳方法是什么?
谢谢