CSS – Build Navigation

This post will explain how to build a simple navigation logic for a webpage.
Please note that I have learned this from the udemy course by Jonas Schmedtmann.
Let’s take a look at the example first.


Please note a couple of things. The navigation button always stays on the upper right corner (even if you scroll). And there is an animation from the button as soon as you click it. In this post, button animation is not explained. Please refer to the post here for button animation.


<div class="navigation">
    <input type="checkbox" class="navigation__checkbox" id="navi-toggle">
    <label for="navi-toggle" class="navigation__button">
        <span class="navigation__icon"> </span>
    <div class="navigation__background"> </div>
    <nav class="navigation__nav">
        <ul class="navigation__list">
            <li class="navigation__item"><a href="#" class="navigation__link"><span>01</span>Option 1</a></li>
            <li class="navigation__item"><a href="#" class="navigation__link"><span>02</span>Option 2</a></li>
            <li class="navigation__item"><a href="#" class="navigation__link"><span>03</span>Option 3</a></li>
            <li class="navigation__item"><a href="#" class="navigation__link"><span>04</span>Option 4</a></li>
            <li class="navigation__item"><a href="#" class="navigation__link"><span>05</span>Option 5</a></li>


Please don’t forget to replace SCSS variables into actual numbers.

There are three main functionalities here (except button animation)
1. The existing screen will be covered by navigation background (animation starts from the button)
2. Another animation when you hover over each option
3. Background animation bounces when render

Let’s take a look at each class now.

.navigation {
  &__checkbox {
    display: none;

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

  &__background {
    height: 6rem;
    width: 6rem;
    border-radius: 50%;
    position: fixed; // similar to absolute. but it doesn't change the position as we scroll the page
    top: 6.5rem;
    right: 6.5rem;
    // difference bewteen linear gradient and radial gradient
    // linear gradient goes from one side to the other
    // radial gradient goes from the center to others
    background-image: radial-gradient($color-primary-light, $color-primary-dark);
    z-index: 500;

    // easings.net
    transition: transform .8s cubic-bezier(.86, 0, .07, 1);
  &__nav {
    height: 100vh;
    position: fixed;
    top: 0;
    left: 0;
    z-index: 600;

    opacity: 0;
    width: 0;
    transition: all .8s cubic-bezier(.68, -.55, .265, 1.55);

  &__list {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    list-style: none;
    text-align: center;
    width: 100%;

  &__item {
    margin: 1rem;

  &__link {
    &visited {
      display: inline-block;
      font-size: 3rem;
      font-weight: 300;
      padding: 1rem 2rem;
      color: $color-white;
      text-decoration: none;
      text-transform: uppercase;
      background-image: linear-gradient(
        transparent 0%,
        transparent 50%,
        $color-white 50%);

      // size of the background, shift to the left to render animation
      background-size: 220%;
      transition: all .4s;

      span {
        margin-right: 1.5rem;
        display: inline-block;
    &:active {
      background-position: 100%;
      color: $color-primary;
      transform: translateX(1rem);

  &__checkbox:checked ~ &__background {
    transform: scale(80);

  &__checkbox:checked ~ &__nav {
    opacity: 1;
    width: 100%;

Navigation Background Animation

The most important things to note are
1. background-image: radial-gradient at line 30.
Unlike linear-gradient making the color from one side to the other side, radial-gradient makes gradient color from the center to all directions. (it’s like a water ripple)

2. transition: transform .8s cubic-bezier(.86, 0, .07, 1) at line 34
This is a bezier curve to provide a custom timing function. There are multiple websites that help you find various timing functions. The number is also calculated from one of the websites.

3. position: fixed at line 24
This is to fix the navigation button in the upper right corner. How is this different from absolute? Unline absolute, fixed doesn’t change the position even if you scroll the page and takes out the element from the float.

4. transform: scale(80) at line 99
This is the line to scale up to cover the entire screen when the checkbox is clicked. Please note that sibling selector is used because you want to select navigation__background and navigation__nav only when the checkbox is clicked. Please also note that the nav opacity is initially 0 and width is 0 to make it completely gone but once the checkbox is clicked it will have opacity 1 and proper width.

Navigation Option Animation

The most important thing to note is
1. &__link class
background-image: linear-gradient at line 73 is solid color gradients usage that you can specify different color in each stage (%). As you can see in the code, it rotates 120 degrees and transparent 0% and 50% and white color starting at 50%. But this alone doesn’t make the animation. It will just show you a different mix of the color. You need to have background-size at line 80 so that you will be able to shift the color by making the size bigger. Then when you hover (at line 89), you just need to re-position the element. Don’t forget to put transition: all .4s for animation.