用CSS建立一个自定义的粘性导航条的教程

404 阅读4分钟

导航条可能是让用户毫不费力地在你的网站上导航而不迷路的最好方法。

人们通常把导航条放在页面的最顶端,但如果你的网页设计得当,你也可以把导航条放在网页的两边。导航条既可以是导航项目(链接)的水平列表,也可以是小屏幕上网页左上角或右上角的汉堡包式。

为了让导航栏有更好的可访问性,你可以通过使用几行CSS和JavaScript将它们粘在顶部。随着导航条的复杂性增加,更多的JavaScript代码会变得堆积如山。

在这篇文章中,我们将看到你如何创建一个自定义的粘性导航条,它对所有的屏幕尺寸都有响应,并具有很好的功能,只使用CSS来创建它。

我们还将学习如何使用SCSS的语法糖来更快、更干净地编写CSS代码。

那么,让我们开始吧。

目录

使用HTML和SCSS

我们将从一些简单的东西开始,随着本文的进展,逐渐深入到更复杂的东西。我们创建导航条的第一件事是写一些HTML。所以,先把这个HTML代码复制到你喜欢的代码编辑器或Codepen中。

<html>
  <body>
    <header class="header">
      <nav class="header__nav" id="navbar">
        <ul class="header__list">
          <li class="header__item"><a href="index.html" class="header__link">Home</a></li>
          <li class="header__item"><a href="about.html" class="header__link">About</a></li>
          <li class="header__item"><a href="services.html" class="header__link">Services</a></li>
          <li class="header__item"><a href="services.html" class="header__link">Contact</a></li>
        </ul>
      </nav>
    </header>
  </body>
</html>

上面给出的HTML代码非常简单,其中没有什么复杂的东西。我希望你注意到我为每个元素写 "类名 "时使用的惯例。这种为HTML元素写 "类名 "的小惯例被称为BEM。BEM是Block-Element-Modifier的缩写。

在我们的HTML代码中,我们给每一个包装元素起一个块的名字。在这种情况下,包装器就是我们的<header class="header"> 。你也可以把它描述为父元素。

包装器或父元素内的每个子元素都有其父元素的类名,后面是两个下划线,有一个唯一的标识符。你可能已经注意到,在我们的例子中,它是:

<nav class="header__nav" id="navbar">

现在,我们可以给包装器中的每个子元素起一个这样的类名。另一件需要注意的事情是,我以 "头 "这个词作为它们的类名的开头,即使它们是头的子元素。这样做的目的是为了保持一致性,在编写SCSS代码时,它最终会对我们有很大的帮助,我们稍后会看到这一点。

要继续,你可以在你的SCSS文件中复制下面给出的SCSS代码。

$color-blue: #00315c;
$color-purple: #6f479f;
$color-black: #202020;
$color-gray: #edebeb;
$color-white: #fcfcfc;

html {
  font-size: 62.5%;
  scroll-behavior: smooth;
}

html,
body {
  width: 100%;
  margin: 0px;
  padding: 0px;
  overflow-x: hidden;
}

body {
  font-family: "Montserrat", sans-serif;
}

.header {
  height: 20vh;
  background-color: $color-gray;
  padding: 1.5rem;
  position: relative;

  &__nav {
    display: flex;
    position: fixed;
    top: 0;
    left: 50%;
    transform: translateX(-50%);
    padding: 4rem 5rem;
    justify-content: space-around;
    align-items: center;
    z-index: 100;
    width: 100%;
    transition: 0.6s;
  }

  &__list {
    list-style: none;
    display: flex;
  }

  &__item {
    &:not(:last-child) {
      margin-right: 5rem;
    }
  }

  &__link {
    font-size: 1.6rem;
    color: $color-blue;
    font-weight: 400;
    text-decoration: none;

    &:hover {
      font-weight: 600;
      transition: all 0.3s;
    }
  }
}

(注:如果你在Codepen中与我一起跟进,你可以在CSS窗口的设置菜单中选择SCSS选项。如果你在你的编辑器(如VS Code)中,你可以下载SCSS扩展;它将把你的SCSS代码编译成CSS代码,你可以把它包含在你的HTML文件中)

CSS Preprocessor extension

如果你对SCSS很熟悉,也明白上面给出的代码是怎么回事,那么可以随意跳过下面几行:

  • 代码的前几行是颜色的变量,我们将在本教程中使用最多的就是这些变量。你可以将这些变量设置为你喜欢的任何颜色,然后在每次你想使用一种颜色时,不要写哈希值或 "RGBA "值,你可以写变量名称
  • 我希望你注意的语法是从第24行开始的。我已经写了.header ,以启动标题元素的样式设计。但是,在同样的括号里,我也写了"&__nav",它启动了我们的导航元素的样式。
  • 在SCSS中,你可以把嵌套元素的样式写在同一个括号里。此外,& 符号持有你的父标识符的值。在这个例子中,它是.header 如果我们使用ID而不是类名,& 将意味着#header
  • 你还可以看到在第61行,我是如何使用&:hover ,因为我想在我的链接元素上应用伪悬停类。
  • 所以,这使得我们可以很容易地编写嵌套样式,并删除多余的代码。你可以按照这个链接来阅读更多关于SCSS和它的语法。

正如你所注意到的,我们没有花太多精力为大屏幕创建一个导航条,因为按照良好的用户体验,它应该始终是屏幕顶部的一个水平列表。

我们可以在大屏幕上添加汉堡包菜单,但为了防止用户的额外点击,汉堡包菜单总是放在小屏幕上,我们现在就来做这个。

使用CSS的汉堡包导航条

现在,我们可以把重点转移到在小屏幕上创建一个自定义的汉堡包导航条,只需使用CSS。

让你了解一下我们正在建立的东西;在小屏幕上显示水平导航项是不可行的。相反,我们将创建一个汉堡包菜单,它将通过覆盖整个屏幕的背景来显示这些项目。

让我们从编写一些代码开始。将下面给出的HTML代码复制到你现有的HTML代码的第10行之后:

 <div class="navigation">
    <input
      type="checkbox"
      class="navigation__checkbox"
      id="navi-toggle"
    />
    <label for="navi-toggle" class="navigation__button">
      <span class="navigation__icon"></span>
    </label>
    <div class="navigation__background"></div>
    <nav class="navigation__nav">
      <ul class="navigation__list">
        <li class="navigation__item">
          <a href="index.html" class="navigation__link">Home</a>
        </li>
        <li class="navigation__item">
          <a href="about.html" class="navigation__link">About</a>
        </li>
        <li class="navigation__item">
          <a href="services.html" class="navigation__link">Services</a>
        </li>
        <li class="navigation__item">
          <a href="contact.html" class="navigation__link">Contact Us</a>
        </li>
      </ul>
    </nav>
  </div>

复制代码后,你的HTML文件看起来应该是这样的:

HTML file

这是我们制作一个在小屏幕上看起来不错的汉堡包菜单所需要的唯一HTML代码。那么,让我向你解释一下这个新添加的代码中的一些关键点。

  • 我们添加了一个新的<div> 元素,并给这个<div> 一个 "导航 "的类名。在这个元素里面,我们添加了一个复选框。这个复选框将帮助我们决定何时显示导航项,何时隐藏它们。
  • 在复选框之后,我们有一个标签,连同里面的一个元素,将作为我们在典型的汉堡包菜单中看到的 "三行 "图标。
  • 第三个元素是另一个<div> ,类名是 "navigation__background"。这个元素将为我们的导航项目提供一个背景覆盖,以便在屏幕上清晰地显示出来。
  • 最后是我们的导航项目的列表。我们必须再次添加它们,因为之前的导航项是为大屏幕准备的,而这些导航项是为小屏幕准备的。

(注意:我使用了相同的BEM命名惯例来为每个元素写类名。)

用CSS设计导航条的样式

现在,剩下的就是为我们的导航条设计样式。所以,我们要写很多CSS代码。我将尝试逐一解释我们所写的每个CSS块,这样就不会引起任何混淆了。

首先,我们要写一些媒体查询,因为我们需要以一定的宽度来显示汉堡包菜单。

  • 现在,对于媒体查询,我们将使用SCSS中的 "mixins"。混合器就像SCSS中的函数
  • 对于参数,你将传递你想看到变化的中断点
  • 为了方便起见,你可以给每个断点起一个自己的名字;例如,"400px "可以命名为 "phone",因为这是手机的平均屏幕宽度。
  • 一旦被调用,你就可以在大括号里写上你的CSS样式,这些样式将被应用于该断点。让我们看看如何通过写这些媒体查询来实现这个目的

媒体查询

在你的SCSS文件的顶部复制以下代码,我们就可以使用这些媒体查询了。

@mixin respond($breakpoint) {
  @if $breakpoint == phone {
    @media only screen and (max-width: 37.5em) {
      @content;
    } //600px
  }
  @if $breakpoint == s-hundred {
    @media only screen and (max-width: 43.75em) {
      @content;
    } //700px
  }
  @if $breakpoint == tab-port {
    @media only screen and (max-width: 56.25em) {
      @content;
    } //900px
  }
  @if $breakpoint == tab-land {
    @media only screen and (max-width: 75em) {
      @content;
    } //1200px
  }
  @if $breakpoint == big-desktop {
    @media only screen and (min-width: 112.5em) {
      @content;
    } //1800
  }
}

你明白这些媒体查询的语法了吗?我们创建了一个名为 "response "的mixin(函数),它应该接受任何 "断点 "作为参数,并在该媒体查询中应用这些样式。

汉堡包的样式

现在,我们可以根据这些媒体查询开始设计我们的导航栏的样式。所以,让我们从复制这段代码开始。

.navigation {
  display: none;
  @include respond(s-hundred){
    display: block;
  }
  z-index: 2000;
  &__checkbox {
    display: none;
  }
}

在上面的代码中,我们将汉堡包导航的显示设置为**无,**因为我们只想在小屏幕上看到。所以,我们使用了我们的response mixin来实现这个功能。

z-index被设置为2000,因为我们希望我们的导航栏能够覆盖所有其他内容。我们将在本文的后面看到它。

由于我们在700px处显示我们的汉堡包导航,我们可以在相同的宽度下删除显示我们的水平列表。

要做到这一点,在你的 "header__list "样式内添加这个小的高亮媒体查询。

&__list {
    list-style: none;
    display: flex;
    @include respond(s-hundred){
      display: none;
    }
}

添加完这些多个代码块后,你的SCSS文件应该是这样的:

SCSS File code

屏幕尺寸超过700px。

Setting screen width to 705

屏幕尺寸小于700px的进行比较。

Setting screen size width to 696

从现在开始,我们必须在**".navigation "**样式块内添加所有代码块,因为所有东西都是嵌套的。

下一块代码块很简单。这段代码将把我们的导航按钮样式化为透明和圆形。我们让它透明,是因为它里面的导航图标元素将作为这个按钮的汉堡包图标。

&__button {
    background-color: transparent;
    height: 7rem;
    width: 7rem;
    top: 6rem;
    right: 6rem;
    border-radius: 50%;
    z-index: 2000;
    box-shadow: 0 1rem 3rem rgba($color-black, 0.1);
    text-align: center;
    cursor: pointer;
  }

现在,我们将设计我们的汉堡包图标。我们将使用Pseudo "before "和 "after "类,位置:绝对。最后,我们将使用 "hover "伪类在我们的图标上添加一个小小的悬停效果。

&__icon {
    position: relative;
    margin-left: 2rem;
    &,
    &::before,
    &::after {
      width: 4rem;
      height: 3px;
      background-color: $color-black;
      display: inline-block;
    }
    &::before,
    &::after {
      content: '';
      position: absolute;
      left: 0;
      transition: all 0.2s;
    }
    &::before {
      top: -0.65rem;
    }
    &::after {
      top: 0.65rem;
    }
  }
  &__button:hover &__icon::before {
    top: -1rem;
  }
  &__button:hover &__icon::after {
    top: 1rem;
  }

在这一点上,我们的汉堡包菜单图标应该出现在屏幕上,如下图所示:

Hamburger icon on nav bar

现在,在按下按钮(或检查)时,我们希望我们的汉堡包图标转变为一个*"*X"关闭图标,以表明我们的导航栏现在是可见的,再按下它将关闭我们的导航栏。

要做到这一点,请复制下面的代码,我们就可以开始使用我们的图标了。

&__checkbox:checked + &__button &__icon {
  background-color: transparent;
}
&__checkbox:checked + &__button &__icon::before {
  top: 0;
  transform: rotate(135deg);
  background-color: $color-white;
}
&__checkbox:checked + &__button &__icon::after {
  top: 0;
  transform: rotate(-135deg);
  background-color: $color-white;
}

  • 在上面的代码块中,我们正在利用我们的复选框元素上的 "checked "伪类的帮助。除此之外,我们还使用了 "+"CSS选择器。
  • +"CSS选择器帮助我们选择紧随指定元素之后的元素。
  • 最后,我们正在旋转我们的图标的 "前 "和 "后 "伪元素,使其看起来像一个 "X"。

我们将继续前进,添加我们的背景叠加。我们的背景背后的逻辑很简单;我们将在我们的按钮上添加背景色,最初,它将是不可见的,因为它的z-index将在复选框按钮后面。

一旦我们点击复选框,我们就会将背景扩大到覆盖整个屏幕,而我们的导航项目就会变得可见。

复制下面的代码来实现这一点。

&__background {
  background: radial-gradient(
    rgba($color-blue, 1),
    rgba($color-purple, 1)
  );
  height: 6rem;
  width: 6rem;
  position: fixed;
  top: -1rem;
  right: 0rem;
  z-index: -1000;
  display: none;
  border-radius: 50rem;
  }

  &__checkbox:checked ~ &__background {
  @include respond(s-hundred) {
    display: block;
    transform: scale(80);
  }
}

应用背景覆盖后,导航条应该是这样的:

Navbar with dark blue background

剩下的最后一件事是为我们的导航项设计样式。对于上下文,导航项应该只在我们点击汉堡包图标时出现。

它将覆盖整个屏幕,以便在小屏幕上提供积极的用户体验。

最后,一旦我们再次点击该图标,它应该消失。一些基本的造型逻辑已经进入了这个代码块,这与我们在教程的其他部分所做的非常相似。

&__nav {
    position: fixed;
    margin-top: 1rem;
    padding: 1.2rem;
    font-size: 1.5rem;
    font-weight: 400;
    z-index: 1500;
    @include respond(phone){
      padding: 0;
    }
  }

  &__list {
    list-style: none;
    opacity: 0;
    visibility: hidden;
    margin-top: 50%;
  }

  &__item {
    &:not(:last-child) {
      margin-bottom: 1.5rem;
    }
  }

  &__link {
    text-decoration: none;
    color: $color-white;
    &:hover {
      color: $color-blue;
    }
  }

  &__checkbox:checked ~ &__nav &__list {
    opacity: 1;
    visibility: visible;
    transition: all 0.5s;
  }

  &__checkbox:checked ~ &__nav {
    @include respond(s-hundred) {
      font-size: 4rem;
      position: absolute;
      top: 32rem;
      left: 50%;
      transform: translate(-50%, -50%);
    }
  }

  &__checkbox:checked ~ &__nav &__link {
    @include respond(s-hundred) {
      color: $color-white;
    }
  }

最后,我们的自定义粘性导航栏在小屏幕上应该是这样的:

Navigation bar on smaller screen navigation bar items on smaller screen

你可以根据自己的需要来设计导航栏或其项目。我把关闭的 "X"符号放在中间,但它通常会放到右上方。所以,你可以自由地做其余的造型,只要你认为合适。

最后,如果你想在你的导航条上添加一些滚动的小动画,你可以在你的标题样式块内添加这一小块CSS代码。

&__sticky {
    padding: 5rem 10rem;
    background-color: $color-gray;
    box-shadow: 0px 3px 5px rgba($color-blue, 0.5);
}

另外,别忘了添加这个JavaScript代码。

const navBar = document.getElementById('navbar');
window.addEventListener('scroll', () => {
  navBar.classList.toggle('header__sticky', window.scrollY > 0);
});

现在,CSS为我们提供的工具和技术足以在不使用JavaScript的情况下建立像我们的导航栏这样的超级酷的东西。

你可以在这里找到这个自定义粘性导航条的CodePen链接

总结

你可以只用CSS来做很多事情。如果你看到关于自定义导航条或其他花哨的东西的教程,你必须下载一些库或编写一些JavaScript代码,那么请先考虑其他的选择,因为JavaScript不是唯一的方法

试着理解CSS的各种概念,也许你就可以只用CSS来做这些事情了。