• 日常搜索
  • 百度一下
  • Google
  • 在线工具
  • 搜转载

构建受 Netflix 启发的高级响应式菜单

前几天,我通过手机访问了 Netflix Jobs 网站,并查看了它的画布菜单。我真的很喜欢每次击中它时都会触发的惊人动画。所以我认为以这个菜单为灵感,向你展示如何构建一个类似的响应式菜单可能是一个很好的练习。

我们正在构建什么

在开始之前,我希望你们都清楚地了解我们将要构建的内容:

See the Pen  Build an Advanced Responsive Menu Inspired by Netflix by Envato Tuts+ (@tutsplus)  on CodePen.

这个嵌入式笔显示我们菜单的移动版本。请务必在更宽的屏幕上查看它以查看它的桌面版本。随意调整浏览器窗口的大小,以查看布局如何适应各种屏幕尺寸。

我们有很多东西要讲,所以让我们开始吧!

资产

出于本教程的目的,我已将以下资产合并到笔中:

  • Roboto Google字体

  • 字体 真棒库 


构建受 Netflix 启发的高级响应式菜单  第1张


此处将使用的 Forecastr 徽标取自 Envato Elements。 


构建受 Netflix 启发的高级响应式菜单  第2张

预报员徽标


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>

让我揭开这里发生的一切的神秘面纱。

我们将从 header 包含nav (navbar) 的 a 开始。在其中,我们将放置所有标题元素。进一步来说: 

  • 将打开画布外菜单的汉堡包按钮。这仅在中小型屏幕 (<995px) 上可见。

  • 徽标。我们将有两种不同类型的徽标。一个垂直标志和一个水平标志。它们的可见性将取决于视口大小。

  • .top-menu-wrapper 元素。 这将包括两个空.panel元素, .top-menu 列表、搜索按钮和搜索表单。s 仅在.panel中小型屏幕 (<995px) 上可见。在.top-menu列表中,我们将放置 .mob-block 将包装一些仅限移动设备的元素、菜单链接和社交链接的元素。.panel与s  类似,the.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;

}

这里没有什么壮观的。我只想讨论两件事。 

首先,请注意我们给 font-size: 62.5%了html. 这会将基本字体大小设置为 10px ((62.5/100)*16) 并覆盖默认的浏览器字体大小,即 16px(尽管它是用户可配置的)。通过这样做,1rem 等于 10px 而不是 16px。这使我们可以轻松地为我们的元素指定基于 rem 的大小。 

其次,重视no-transition课堂。稍后我们将使用该类在调整页面大小时禁用所有 CSS 过渡。

注意:为简单起见,我不会  在教程中介绍所有CSS 规则。这里有将近 400 行 CSS。 确保通过单击演示项目的CSS选项卡来检查它们 。

3. 为移动菜单设置样式

为了设置导航栏的样式,我们将遵循移动优先的方法。也就是说,首先我们将在中小型屏幕 (<995px) 上浏览它的布局,然后在大屏幕上进行。

考虑到这一点,当视口大小低于 995 像素时,导航栏将如下所示:


构建受 Netflix 启发的高级响应式菜单  第3张


如您所见,此时只会出现汉堡包按钮、垂直徽标和搜索按钮(不包括其文本)。 

导航栏将充当弹性容器。我们将给它 justify-content: space-between并 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 类。在这种情况下,将出现画布外菜单:


构建受 Netflix 启发的高级响应式菜单  第4张


这将带有过渡效果。.panel 和元素将.top-menu根据它们的源顺序以滑入效果顺序可见。首先.panel1会出现,然后在 200 毫秒后出现,.panel2最后在 400 毫秒后出现.top-menu。同时,我们将为::before. .top-menu-wrapper此伪元素将用作位于画布外菜单下方的叠加层。

在这一点上,重要的是写下有关画布外布局的一些关键内容:

  • .panels 和 the都.top-menu将是固定定位的元素并覆盖整个视口高度。它们还将位于所有其他元素之上。

  • 它们的宽度将取决于视口大小。例如,在最大 549px 的屏幕上,它们的宽度将覆盖整个视口宽度。另一方面,在较大的屏幕上,它们都有固定的宽度(大约是窗口宽度的 60%)。

  • 它们出现的顺序将取决于其transition-delay财产的价值。

  • 我们将使用 flexbox 来布局.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 和 .top-menu 元素会以相反的顺序以滑出的效果消失。首先 .top-menu 将消失,然后在 100 毫秒后消失, .panel2最后在 300 毫秒 后消失.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类)。但是如果它已经有这个类,它就会消失。


构建受 Netflix 启发的高级响应式菜单  第5张


处理表单可见性的 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 时,导航栏布局将完全不同:


构建受 Netflix 启发的高级响应式菜单  第6张


在这种情况下,典型的导航菜单将取代临时的画布外菜单。

因此,让我们强调一下桌面布局与移动版布局的重要区别:

  • 将出现水平徽标。

  • 另一方面,以下元素将消失: 的::before伪元素.top-menu-wrapper、汉堡切换按钮、垂直徽标、.panels、the.mob-block和社交链接。

  • 此外,  .top-menu将不再作为固定定位元素,而是根据其正常的文档流 ( 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;

  }

}

当视口宽度至少为 1200 像素时,我们将做一些小的更改。最重要的是,我们将显示搜索按钮的文本(搜索资源):

构建受 Netflix 启发的高级响应式菜单  第7张

显示搜索文本的样式:

@media screen and (min-width: 1200px) {

  .page-header .search span {

    display: block;

  }

}

5. 清除窗口调整大小的过渡

我们几乎完成了菜单的创建。但是我们必须解决最后一件事。更具体地说,每次我们调整浏览器窗口的大小时,我们都应该清除所有的 CSS 过渡。否则,在我们的例子中,当我们调整窗口大小时,画布外菜单将出现片刻,然后返回到其默认的屏幕外位置。

虽然这不是很重要的事情,但如果我们能找到解决这个问题的方法,那就太好了。

所以我们可以做的是监听resize事件,每次触发时,我们都会将no-transition 类(希望你记得它!)添加到所有.page-header 后代。

但是,当调整大小完成后,我们将等待 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 网站的标题菜单为灵感,并学会了创建我们自己的高级响应式菜单。确实这是一个漫长的旅程,但我希望它可以帮助你提高你的前端技能并学习一些新东西。

让我们再看看我们构建了什么:

See the Pen  Build an Advanced Responsive Menu Inspired by Netflix by Envato Tuts+ (@tutsplus)  on CodePen.

在结束之前,我想再说一件事:了解这个演示如何工作的最好方法是检查 CSS 样式。

如果您打算构建类似的东西,我很想知道您的想法!一如既往,非常感谢您的阅读!

文章目录
  • 我们正在构建什么
  • 资产
  • 1. 从页面标记开始
  • 2. 定义一些基本样式
  • 3. 为移动菜单设置样式
    • 打开画布外
    • 关闭画布外
    • 切换表格
  • 4. 设置桌面菜单样式
  • 5. 清除窗口调整大小的过渡
  • 结论