Building an Intro section with dropdown navigation using Sass & JS

Building an Intro section with dropdown navigation using Sass & JS

My Experiences working on this Frontend mentor challenge

Introduction - Project Overview

I participated in the frontendmentor.io challenge. The platform has amazing beginner, mid-level, and advanced projects that can help you build your portfolio. I will be sharing my experiences, challenges, and the approach I used in solving this challenge.

Tip: Psst…Practice along as you go through the article. Fight those bugs 🪲and have fun as you build.
Note: While practicing alongside this article, you can try a different approach, as long as it works fine!!

Templates- Design Templates

Desktop - This is what the desktop version looks like:

Mobile - This is what the mobile version looks like:

Development Tools

GitHub repository:

Screenshot app: FireShot

Hosting: Vercel

IDE: Visual Studio Code

Built with: HTML5, Sass( CSS preprocessor) and Vanilla JS


Setting Up the Environment

Before you start building, you have to set up your developer environment. Make sure to download these necessary applications if you have not installed them already.

Step 1: Install Nodejs.

  1. Step 2: Install the latest version of any browser (recommended: Chrome or Firefox)

  2. Step 3: Install the following extensions in VScode

a. Live server

b. Live Sass Compiler

I will be building with Sass, if you are new to Sass, this article on FreeCodeCamp will guide you through the installation and compilation of Sass.

  1. Step 4: Creating a GitHub repository. This step is necessary so that you can get the resources and design templates.

Easy step

  • Go to GitHub and log in to your GitHub account if you haven't already.

  • Create repository" button to create your new GitHub repository.

  • Click on 'Code' and copy your https URL.

Ensure you have Gitbash already installed on your system. If it is, proceed with the next step and if is not, install Gitbash.


SASS Setup

If you have followed the article on FreeCodeCamp, you should have a styles folder

OR

  1. Simply in Vscode, create a new folder styles

  2. Make sure you change the file path so that the sass is compiled in the styles folder. To do this, follow the steps below:

image-credit: FreeCodeCamp

Image-credit: FreeCodeCamp

  1. Create a main.scss in the styles folder: The browser cannot read Sass, hence, it has to be compiled into CSS. Click on watch sass, two files get created: main.css and a main.css.map in the styles folder.

Creating the Sass pages:

Unlike CSS, you can have different sass pages. This makes debugging super easy. These are the pages you will have:

main.css - After compiling your sass, main.css is automatically created. This is where the sass will be compiled as regular CSS.

Note: Create the pages first, then link them to main.scss.

Don't be in a hurry to copy the styles. You will understand how it works after inserting html.

  1. _base.scss : Styling of base elements like h1, p, ul, li, etc.

  2. _layout.scss : Styling of container layout like grid.

  3. _variables.scss: styling all the variables.

  4. _component.scss: styling all the components.

  5. _home.scss : styling the home section.

  6. _responsive.scss: styling for other screen sizes.

Copy the styles for _base.scss, _variables.scss, _layout.scss and _component.scss

These styles are pretty much reusable and will not be changed throughout the code.

Codepen Here 👇👇:

Linking the sass pages:

In the main.scss file, link the subpages using this code:

@import "variables";
@import "component";
@import "base";
@import "layout";
@import "home";
@import "responsive";

Note: Make sure to spell accurately, creating a _variables.scss file and importing "variable" will lead to an error.


HTML Structure - Adding HTML

  1. First, create a file index.html

  2. Link the main.css file not the main.scss file to the HTML.

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <!-- displays site properly based on user's device -->

  <link rel="icon" type="image/png" sizes="32x32" href="./images/favicon-32x32.png">
  <link rel="stylesheet" href="/styles/main.css" />
  <script src="script.js" defer></script>
  <title>Frontend Mentor | Intro section with dropdown navigation</title>
</head>

For the HTML, we have 2 main parts: <header> and <section> . The <header> section is the main container for the nav elements and the <section> is the main container for the home section.

I used the BEM (Block Element Method) naming methodology to make parent-child selection easier. Example: nav__logo

  • nav" is the block: This typically represents the higher-level component or container, in this case, a navigation menu.

  • "__" (double underscore) is used to separate the block from the element.

  • "logo" is the element: This represents a specific part or component within the block, like a list of items within the navigation.

For the header structure:

 <header>
    <nav class="nav container-layout">
      <!-- for the logo -->
      <a href="#" class="nav__logo">snap</a>

      <!-- the nav menu -->
      <div class="nav__menu" id="nav__menu">
        <ul class="nav__list">
<!--List item features on nav bar-->
            <li class="nav__item toggle-button">
              <a href="#features" class="nav__link">Features
                <span class="toggle-icon"></span>
              </a>
            </li>
     <!--List item company on nav bar-->
            <li class="nav__item toggle-button">
              <a href="#company" class="nav__link">Company
                <span class="toggle-icon"></span>
              </a>
            </li>
        <!--List item careers on nav bar-->
          <li class="nav__item toggle-button">
            <a href="#career" class="nav__link">Careers</a>
          </li>
  <!--List item about on nav bar-->
          <li class="nav__item toggle-button">
            <a href="#about" class="nav__link">About</a>
          </li>
          <!-- login and register section -->
          <div class="nav__item nav__signup">
            <ul class="nav__list">
              <li class="nav__item"><a href="#">Login</a></li>
              <li class="nav__item"><a href="#" class="reg">Register</a></li>
            </ul>

          </div>
        </ul>
      </div>

Once you have structured your HTML, you can try to style the elements.

The Features and Company in the nav bar have drop-down components, so let's create that :

 <div class="nav__item toggle-container">
            <li class="nav__item toggle-button">
              <a href="#features" class="nav__link">Features
                <span class="toggle-icon"></span> <!-- add Caret icon-->
              </a>

            </li>
            <div class="nav__item toggle-content"> <!-- toggle content-->
              <div class="nav__item content">
                <img src="images/icon-todo.svg" alt="">
                <h3><a href="">Todo List</a> </h3>
              </div>
              <div class="nav__item  content">
                <img src="images/icon-calendar.svg" alt="">
                <h3><a href=""> Calender</a></h3>
              </div>
              <div class="nav__item  content">
                <img src="images/icon-reminders.svg" alt="">
                <h3><a href="">Reminders</a></h3>
              </div>
              <div class="nav__item  content">
                <img src="images/icon-planning.svg" alt="">
                <h3><a href="">Planning</a></h3>
              </div>

            </div>
          </div>
<!--repeat the same for Company-->

The entire code is really long, so you can check out the full solution on this Codepen:


Building Desktop Navigation Bar

The nav bar is inside a container header. I labeled both of these class names as components, hence, they are styled in _component.scss

Now let me explain:

The code for the header is straightforward. Set the height, width, and position, and adjust the background color.

Let's look at the nav section.

Step 1: I separated the nav bar into 3 major parts: the Logo, the nav items (features, Company, About, and Careers), and the nav items(login and signup).

Step2: I styled the base of the nav bar in the _base.scss (ul, li, a)

Step 3: After setting up the base for the navbar, What next?

The nav bar for the desktop screen is different from that of smaller screens (mobile and small tablet). I styled the desktop navigation bar in _responsive.scss using media query.

The desktop screen does not need the menu bar as all the nav items are fully displayed.

.nav{
&__toggle,   //to hide the menu bar and close menu icon for desktop
        &__close {
            display: none;
        }
}

Step 4: Under the _component.scss I styled some components in the nav bar that can be reusable across all screens.

These include hover states, the caret icons on Features and Company, and the toggle content that displays when the caret is clicked.


Building Desktop Home Section

The entire code is really long, so you can check out the full solution on this Codepen:

The styling for this section is in the _home.scss file.

I used grid template areas to style the home section. This method is really helpful when arranging items in a grid layout. For the home section, there are three main grid areas: The text area, the image area, and the brand logo area.

&__container{
            @include grid();
            margin: 5em 8em;
            align-items: center;
//This will arrange the items in 2 rows and 2 columns
                grid-template-areas:"txt imge"
                                     "brand imge";
                                    //  "footer footer";
                grid-template-columns: 1fr 1fr ;
                grid-template-rows: 1fr 100px;


            }

Responsive Navigation - Creating Responsive Nav Bar

After styling the desktop screen, the mobile screens and tablet were styled using media query on the _responsive.scss page.

@media screen and (max-width: 767px) {} //for mobile screens and small tablets
@media screen and (min-width: 768px) and (max-width: 1024px) {} //for tablets 
@media screen and (min-width: 1025px) {} // for desktop

The entire code is really long, so you can check out the full solution on this Codepen

📌For the tablet with big screens, the same styling for the desktop works. A few adjustments in the sizes were made.

Mobile and small tablets

The nav bar for smaller screens has only two parts: The Logo and the menu bar.

Logic:

  • Only the menu bar should be displayed

  • When the menu bar is clicked, the nav items will be displayed in a sidebar

  • The sidebar should display the close menu icon which when clicked will close the sidebar.

    To display only the menu bar

    HTML

  •   <!-- toggle section for small screens -->
            <div class="nav__toggle" id="nav-toggle">
              <a class="menu-icon"><img src="images/icon-menu.svg" alt=""></a>
            </div>
    
            <!--collaspe sidebar for small screens-->
            <div class="nav__menu  nav__close">
              <a href="#"><img src="images/icon-close-menu.svg" alt=""></a>
            </div>
    

SCSS

//STYLING THE SIDE BAR 
        &__menu {
            position: fixed;
            top: 0;
            right: 0;
            height: 100%;
            width: 0;
            overflow: hidden;
            transition: 0.5s;
            background-color: $white;
            padding-top: $mb-6;
            transition: 0.4s;
            box-shadow: 0 0 4px rgba(0, 0, 0, 0.1);
        }
//STYLING THE NAV ITEMS 
        &__item{
            margin-bottom: 20px; //ADDS SPACE BETWEEN EACH ITEM
//STYLING THE TOGGLE CONTENT FOR FEATURES AND COMPANY
            &.toggle-content {
                position: absolute;
                top: 4em;
                right:0;
                line-height: 0;
                height: auto;
                max-width: 100%;
                border: 2px solid rgb(246, 246, 246);
                padding: 0.5rem 0.5rem;
                border-radius: 0.5rem;
                background: rgba(255, 255, 255, 0.99);
                box-shadow: 31px 27px 89px -26px rgba(0, 0, 0, 0.48);
                -webkit-box-shadow: 31px 27px 89px -26px rgba(0, 0, 0, 0.48);
                -moz-box-shadow: 31px 27px 89px -26px rgba(0, 0, 0, 0.48);
            }
            &.toggle-content.active{
              display: block
            }
        }
//SIGNUP SECTION
        &__signup {
            ul { 
                @include flex();
                flex-direction: column;
                li {
                    a {
                        &.reg {
                            border: 2px solid $medium-gray;
                            padding: 0.5rem $mb-4;
                            border-radius: $mb-1;
                        }
                    }
                }

            }
        }
//STYLING THE MENU ICON
        &__toggle {
            width: $logo-font;
        }
//STYLING THE CLOSE MENU ICON
       &__close{
         width: 50px;
        height: auto;
        box-shadow: none;
        padding-top: 20px;
        display: none;

       }
    }

JS:

// code to display menu icon for small screens
function showMenu(toggleId, navId) {
  const toggle = document.getElementById(toggleId); // Get the menu toggle element by its ID.
  const nav = document.getElementById(navId); // Get the navigation menu element by its ID.

  if (toggle && nav) {
    toggle.addEventListener('click', () => {
      nav.classList.toggle('showMenu'); // Toggle the 'showMenu' class on the navigation menu element.
      console.log('Menu toggled'); // Log a message to the console when the menu is toggled.
    });
  }
}

showMenu('nav-toggle', 'nav-menu'); // Call the function, passing the IDs of the toggle and navigation menu elements.

Here's an explanation of each part:

  1. function showMenu(toggleId, navId): This function is defined and takes two arguments, toggleId and navId, which are expected to be the IDs of HTML elements. The function's purpose is to toggle the visibility of a navigation menu when the menu toggle (hamburger icon) is clicked.

  2. const toggle = document.getElementById(toggleId);: This line retrieves an HTML element with the ID specified by toggleId and assigns it to the toggle variable. This element is the menu toggle button (hamburger icon).

  3. const nav = document.getElementById(navId);: This line retrieves an HTML element with the ID specified by navId and assigns it to the nav variable. This element is the navigation menu that you want to show/hide.

  4. if (toggle && nav) { ... }: This conditional statement checks if both toggle and nav elements exist. If they do, it proceeds to the next block of code. If not, it does nothing, which is a safety measure to prevent errors if the elements are not found.

  5. toggle.addEventListener('click', () => { ... });: This code attaches a click event listener to the toggle element. When the menu toggle button is clicked, the function inside the event listener is executed.

  6. nav.classList.toggle('showMenu');: This line toggles the presence of the CSS class "showMenu" on the nav element. This class is likely used to control the visibility of the navigation menu. So, when you click the menu toggle, it either adds or removes the "showMenu" class, effectively showing or hiding the menu.

  7. console.log('Menu toggled');: This line logs a message to the console when the menu is toggled, which can be helpful for debugging and tracking the menu's state changes.

  8. showMenu('nav-toggle', 'nav-menu');: Finally, this line calls the showMenu function, passing the IDs of the menu toggle element and the navigation menu element as arguments. This sets up the behavior for your specific HTML elements with those IDs.


Responsive Home Section

The entire code is really long, so you can check out the full solution on this Codepen:

Like the desktop screen, I also used grid-template-areas. The only difference will be in the grid rows and columns arrangement.

.home{
        display: flex;
        align-items: center;
        justify-content: center;
        margin-top: 3em;
        &__container{
           @include grid();
//This will arrange the items in 1 column and 3 rows.
           grid-template-areas: "imge"
                                "txt"
                                "brand";
           grid-template-columns: 1fr;
           grid-template-rows: 1fr 1fr 100px;
            /* 90% of the viewport width */
            max-width: 375px; /* Maximum width */

        }
}

Conclusion - Wrapping Up

I learned how to use amazing tools like CSS Box shadow generator and FireShot.

You can check out the full solution on this Codepen:

Challenges

I had some set back in the building of this project such as implementing the sidebar on the mobile screen. I encountered a lot of bugs and logic errors in my javascript code for displaying toggle content.

Getting a pixel-perfect design from only a design template was certainly not easy. I had to make a lot of adjustments in styles and look for better ways to implement the designs.

Best Practices I learned:

This helped me create responsive designs without having to use media queries all the time.

  1. Use Relative Units for Sizing:

    • Instead of fixed pixel values (e.g., px), use relative units like percentages (%) or em and rem for font sizes and padding/margin. This allows elements to scale relative to their parent containers and text to adjust with respect to the base font size.
  2. CSS Grid and Flexbox Layouts:

    • Leverage CSS Grid and Flexbox for layout design. These layout systems provide powerful tools for creating responsive designs that adapt to different screen sizes and orientations.
  3. Media Queries:

    • Use media queries to apply different CSS rules based on the screen width and other conditions. This allows you to create specific styles for various breakpoints. For example:

        @media (max-width: 768px) {
          /* CSS rules for screens with a maximum width of 768px */
        }
      
  4. Fluid Images and Videos:

    • Make images and videos responsive by setting their max-width to 100% and using height: auto. This ensures that they scale down proportionally on smaller screens.

Next Steps:

  • Push the changes to GitHub

  • Deploy on any free hosting platform: I deployed on Vercel

  • Take a screenshot of your website: I used FireShot extension on Chrome to screenshot my work.

  • Finally 🎊🎊...Blog about your work

Have Fun while building. It is definitely okay to go back and understand certain concepts before returning back to the project. The goal is to learn while practicing.

If you have any questions, please let me know in the comment section.

Let's connect on Twitter 👋