netflix交互式电影
前几天,我通过手机访问了Netflix Jobs网站 ,并查看了其非画布菜单。 我真的很喜欢每当您点击它时都会触发的惊人动画。 因此,我认为以该菜单为灵感并向您展示如何构建类似的响应菜单可能是一个很好的练习。 让我们潜入吧!
我们正在建设什么
在开始之前,我希望大家对我们将要构建的内容有清楚的了解:
这款嵌入式笔显示了我们菜单的移动版本。 确保在更大的屏幕上进行查看,以查看其桌面版本。 随意调整浏览器窗口的大小,以查看布局如何适应各种屏幕尺寸。
我们有很多事情要讲,所以让我们开始吧!
资产
出于本教程的目的,我将以下资产纳入笔中:
将在此处使用的Forecaster徽标 取自Envato Elements 。
1.从页面标记开始
乍看之下,页面标记可能看起来很冗长,但请不要感到不知所措。 实际上,它并不像看起来那样复杂。 无论如何,我会尽力向您解释!
在下面看看:
<header class="page-header">
<nav>
<button aria-label="Open Mobile Menu" class="open-mobile-menu fa-lg">
<i class="fas fa-bars" aria-hidden="true"></i>
</button>
<a href="">
<img class="logo horizontal-logo" src="horizontal-logo.svg" alt="">
<img class="logo vertical-logo" src="vertical-logo.svg" alt="">
</a>
<div class="top-menu-wrapper">
<div class="panel panel1"></div>
<div class="panel panel2"></div>
<ul class="top-menu">
<li class="mob-block">
<img class="logo" src="horizontal-logo-mobile.svg" alt="">
<button aria-label="Close Mobile Menu" class="close-mobile-menu fa-lg">
<i class="fas fa-times" aria-hidden="true"></i>
</button>
</li>
<li>...</li>
<li>...</li>
<li class="has-dropdown">
...
<ul class="sub-menu">...</ul>
</li>
<li class="has-dropdown">
...
<ul class="sub-menu">...</ul>
</li>
<li>
<ul class="socials">...</ul>
</li>
</ul>
<button class="search">...</button>
<form class="search-form">
<div>
<input type="search" placeholder="Search Resources">
<button aria-label="Search Resources" type="submit">
<i class="fas fa-search fa-2x" aria-hidden="true"></i>
</button>
</div>
</form>
</div>
</nav>
</header>
让我揭开这里的神秘面纱。
我们将从包含nav栏(navbar)的header开始。 在其中,我们将放置所有标头元素。 进一步来说:
- 汉堡包按钮将打开“画布”菜单。 这仅在中型屏幕(<995像素)上可见。
- 徽标。 我们将有两种不同类型的徽标。 垂直徽标和水平徽标。 它们的可见性将取决于视口的大小。
-
.top-menu-wrapper元素。 这将包括两个空的.panel元素,.panel.top-menu列表,搜索按钮和搜索表单。.panel仅在中型屏幕(<995px)上可见。 在.mob-block.top-menu列表内,我们将放置.mob-block元素,该元素将包装一些仅用于移动设备的元素,菜单链接和社交链接。 与.panel相似,.mob-block和社交链接将仅出现在中小型屏幕(<995px)上。
2.定义一些基本样式
准备好标记后,我们将继续使用CSS。 我们的第一步是设置一些CSS变量和常见的重置样式:
:root {
--purple-1: #3d174f;
--purple-2: #4b2860;
--white: #fff;
--black: #221f1f;
--red: #ed1849;
--lightgray: #cfcfcf;
--overlay: rgba(0, 0, 0, 0.5);
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
outline: none;
}
html {
font-size: 62.5%;
}
button {
background: transparent;
border: none;
cursor: pointer;
}
ul {
list-style: none;
}
a {
text-decoration: none;
}
img {
display: block;
max-width: 100%;
height: auto;
}
a,
button {
color: inherit;
}
.no-transition {
transition: none !important;
}
body {
font: 1.6rem/1.5 Roboto, sans-serif;
color: var(--white);
min-height: 100vh;
}
这里没什么壮观的。 我只想讨论两件事。
首先,请注意,我们给html赋予font-size: 62.5% 。 这会将基本字体大小设置为10px((62.5 / 100)* 16),并覆盖默认的浏览器字体大小16px(不过,用户可以配置)。 这样做,1rem等于10px而不是16px。 这使我们可以轻松地为元素指定基于rem的大小。
其次,注意no-transition班。 稍后,我们将使用此类在调整页面大小时禁用所有CSS过渡。
注意 :为简单起见,我不会逐步学习本教程中的所有 CSS规则。 这里有将近400行CSS。 确保通过单击演示项目的CSS选项卡检查所有内容。
3.设置手机菜单样式
要为导航栏设置样式,我们将遵循移动优先的方法。 也就是说,首先我们将在中小型屏幕(<995px)上浏览其布局,然后在大屏幕上浏览。
考虑到这一点,当视口大小小于995px时,导航栏将如下所示:
如您所见,此时,只有汉堡按钮,垂直徽标和搜索按钮(无文字)会出现。
导航栏将充当Flex容器。 我们将其指定justify-content: space-between align-items: center和align-items: center以使其可见子代在主轴和横轴上的位置相对应。
以下是相应的样式:
/*CUSTOM VARIABLES HERE*/
.page-header {
padding: 1.5rem 3rem;
background: var(--purple-1);
}
.page-header nav {
display: flex;
align-items: center;
justify-content: space-between;
}
.page-header .horizontal-logo,
.page-header .search span {
display: none;
}
打开画布
每次我们单击汉堡菜单时, .top-menu-wrapper元素都会收到show-offcanvas类。 在这种情况下,将出现“画布”菜单:
这将带有过渡效果。 .panel和.panel .top-menu元素将根据其源顺序依次显示并具有滑入效果。 首先将显示.panel1 ,然后在200ms之后显示.panel2 ,最后在400ms之后显示.panel2 .top-menu 。 同时,我们将为.top-menu-wrapper的::before伪元素设置背景色的动画。 此伪元素将用作位于画布外部菜单下方的叠加层。
在这一点上,重要的是写下一些有关画布外布局的关键信息:
-
.panel和.panel.top-menu都将是固定位置的元素,并覆盖整个视口高度。 它们还将位于所有其他元素之上。 - 它们的宽度将取决于视口的大小。 例如,在最大549像素的屏幕上,它们的宽度将覆盖整个视口宽度。 另一方面,在较大的屏幕上,它们的宽度都固定(约为窗口宽度的60%)。
- 它们出现的顺序将取决于其
transition-delay属性的值。 - 我们将使用flexbox布局.top
.top-menu和.mob-block元素的内容。
这是“画布”菜单所需样式的一部分:
/*CUSTOM VARIABLES HERE*/
.page-header .top-menu-wrapper::before {
content: '';
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: -1;
transition: background 0.5s;
}
.page-header .panel,
.page-header .top-menu {
position: fixed;
top: 0;
left: 0;
bottom: 0;
z-index: 2;
transform: translate3d(-100%, 0, 0);
transition: transform 0.4s cubic-bezier(0.23, 1, 0.32, 1);
}
.page-header .panel1 {
width: 100%;
background: var(--purple-1);
}
.page-header .panel2 {
width: calc(100% - 3rem);
background: var(--red);
}
.page-header .top-menu {
display: flex;
flex-direction: column;
width: calc(100% - 6rem);
overflow-y: auto;
padding: 2rem;
background: var(--white);
}
.page-header .top-menu .mob-block {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 3rem;
}
.page-header .top-menu-wrapper.show-offcanvas::before {
background: var(--overlay);
z-index: 1;
}
.page-header .top-menu-wrapper.show-offcanvas .panel,
.page-header .top-menu-wrapper.show-offcanvas .top-menu {
transform: translate3d(0, 0, 0);
transition-duration: 0.7s;
}
.page-header .top-menu-wrapper.show-offcanvas .panel1 {
transition-delay: 0s;
}
.page-header .top-menu-wrapper.show-offcanvas .panel2 {
transition-delay: 0.2s;
}
.page-header .top-menu-wrapper.show-offcanvas .top-menu {
transition-delay: 0.4s;
box-shadow: rgba(0, 0, 0, 0.25) 0 0 4rem 0.5rem;
}
@media screen and (min-width: 550px) {
.page-header .panel1 {
width: 60%;
}
.page-header .panel2 {
width: calc(60% - 3rem);
}
.page-header .top-menu {
width: calc(60% - 6rem);
}
}
以及打开它所需JavaScript代码:
const openMobMenu = document.querySelector(".open-mobile-menu");
const topMenuWrapper = document.querySelector(".top-menu-wrapper");
const showOffCanvas = "show-offcanvas";
openMobMenu.addEventListener("click", () => {
topMenuWrapper.classList.add(showOffCanvas);
});
关闭画布
每次单击✕按钮, .top-menu-wrapper都会丢失其show-offcanvas类。
就在此时, .panel和.panel .top-menu元素将消失,并具有相反顺序的滑出效果。 首先, .panel2 .top-menu将消失,然后在100ms的.panel2 ,最后在300ms的.panel1 。
以下是与过渡相关的样式,这些样式确定目标元素的速度:
.page-header .panel,
.page-header .top-menu {
transition: transform 0.4s cubic-bezier(0.23, 1, 0.32, 1);
}
.page-header .panel1 {
transition-delay: 0.3s;
}
.page-header .panel2 {
transition-delay: 0.1s;
}
以及隐藏异常JavaScript代码:
const closeMobMenu = document.querySelector(".close-mobile-menu");
const topMenuWrapper = document.querySelector(".top-menu-wrapper");
const showOffCanvas = "show-offcanvas";
closeMobMenu.addEventListener("click", () => {
topMenuWrapper.classList.remove(showOffCanvas);
});
切换形式
无论视口宽度如何,搜索表单最初都会被隐藏。 它也将位于导航栏下方。
相关样式:
/*CUSTOM VARIABLES HERE*/
.page-header {
position: relative;
}
.page-header .search-form {
position: absolute;
top: 100%;
left: 0;
right: 0;
visibility: hidden;
opacity: 0;
padding: 1rem 0;
background: var(--purple-2);
transition: all 0.2s;
}
.page-header .search-form.is-visible {
visibility: visible;
opacity: 1;
}
只要单击搜索按钮,表单的可见性状态就会改变。 这意味着,如果它是隐藏的,它将出现(它将接收is-visible类)。 但是,如果已经有了此类,它将消失。
处理表单可见性JavaScript代码:
const toggleSearchForm = document.querySelector(".search");
const searchForm = document.querySelector(".page-header form");
const isVisible = "is-visible";
toggleSearchForm.addEventListener("click", () => {
searchForm.classList.toggle(isVisible);
});
4.设置桌面菜单的样式
当视口宽度至少为995px时,导航栏布局将完全不同:
在这种情况下,典型的导航菜单将代替临时的画布菜单。
因此,让我们着重强调与移动版相比,桌面版版将发生的重要差异:
- 出现水平徽标。
- 另一方面,以下元素将消失:
.top-menu-wrapper的::before伪元素,汉堡包切换按钮,垂直徽标,.panel,.mob-block和social链接。 - 此外,
.top-menu不再充当固定位置的元素,而是根据其常规文档流进行position: static(position: static)。 另外,其下拉菜单默认情况下将被隐藏,并且仅当我们将鼠标悬停在其相应的父列表项上时才会显示。
这是桌面布局最关键的样式的一部分:
/*CUSTOM VARIABLES HERE*/
@media screen and (min-width: 995px) {
.page-header .panel,
.page-header .open-mobile-menu,
.page-header .vertical-logo,
.page-header .top-menu .mob-block,
.page-header .top-menu > li:last-child,
.page-header .top-menu-wrapper::before {
display: none;
}
.page-header .horizontal-logo {
display: block;
}
.page-header .top-menu-wrapper {
display: flex;
align-items: center;
color: var(--white);
}
.page-header .top-menu {
flex-direction: row;
position: static;
width: auto;
background: transparent;
transform: none;
padding: 0;
overflow-y: visible;
box-shadow: none !important;
}
.page-header .has-dropdown i {
display: inline-block;
}
.page-header .sub-menu {
display: none;
position: absolute;
top: 100%;
left: 50%;
transform: translateX(-50%);
padding: 1.5rem 2rem;
background: var(--purple-2);
}
.page-header .has-dropdown {
position: relative;
}
.page-header .has-dropdown:hover .sub-menu {
display: block;
}
}
当视口宽度至少为1200px时,我们将做一些小的更改。 最重要的是,我们将显示搜索按钮的文本( Search Resources ):

显示搜索文本的样式:
@media screen and (min-width: 1200px) {
.page-header .search span {
display: block;
}
}
5.清除窗口调整大小时的过渡
我们几乎完成了菜单的创建。 但是,我们还有最后一件事需要解决。 更具体地说,每次我们调整浏览器窗口的大小时,都应清除所有CSS过渡。 否则,在我们调整窗口大小的情况下,“画布”菜单会出现一会儿,然后再返回其默认的“屏幕外”位置。
尽管它不是很重要,但是如果我们能够找到解决此问题的方法,那将是非常不错的。
因此,我们可以做的是监听resize事件,并且每次触发时,我们都会向所有.page-header后代添加no-transition类(希望您还记得!)。
但是,当调整大小完成时,我们将等待500毫秒(随意更改该值),然后再从所有.page-header后代中删除该类。
这是实现此功能的小JavaScript代码:
const pageHeader = document.querySelector(".page-header");
const noTransition = "no-transition";
let resize;
window.addEventListener("resize", () => {
pageHeader.querySelectorAll("*").forEach(function(el) {
el.classList.add(noTransition);
});
clearTimeout(resize);
resize = setTimeout(resizingComplete, 500);
});
function resizingComplete() {
pageHeader.querySelectorAll("*").forEach(function(el) {
el.classList.remove(noTransition);
});
}
我不确定这是否是解决此问题的最明智的方法,但我认为至少它可以正常工作,并且可以取消窗口调整大小时不希望的过渡。
显然,我们可以增强此代码,使其仅对很少的过渡元素运行,而不对所有标头的后代运行。
结论
就是这样! 我们以Netflix Jobs网站的标题菜单为灵感,并学会了创建自己的高级响应菜单。 确实,这是一段漫长的旅程,但我希望它能帮助您提高前端技能并学习一些新知识。
让我们再次看看我们构建了什么:
在结束之前,我还要说一件事:了解此演示的工作原理的最佳方法是检查CSS样式。
如果您打算建立与此类似的东西,我很想知道您的想法! 与往常一样,非常感谢您的阅读!
netflix交互式电影
835

被折叠的 条评论
为什么被折叠?



