Building an Intro section with dropdown navigation using Sass & JS
My Experiences working on this Frontend mentor challenge
Table of contents
- Introduction - Project Overview
- Templates- Design Templates
- Development Tools
- Setting Up the Environment
- SASS Setup
- Creating the Sass pages:
- Linking the sass pages:
- HTML Structure - Adding HTML
- Building Desktop Navigation Bar
- Building Desktop Home Section
- Responsive Navigation - Creating Responsive Nav Bar
- Responsive Home Section
- Conclusion - Wrapping Up
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.
Step 2: Install the latest version of any browser (recommended: Chrome or Firefox)
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.
- 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.
Download the starter file on the front-end mentor challenge. Unzip the file and open the folder on Vscode
Open VScode Terminal
Select GitBash
-
Clone the repository you created
git clone
https://github.com/johnwinifred/
...
SASS Setup
If you have followed the article on FreeCodeCamp, you should have a styles
folder
OR
Simply in Vscode, create a new folder
styles
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
- Create a
main.scss
in thestyles
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 amain.
css.map
in thestyles
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.
_base.scss
: Styling of base elements like h1, p, ul, li, etc._layout.scss
: Styling of container layout like grid._variables.scss
: styling all the variables._component.scss
: styling all the components._home.scss
: styling the home section._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
First, create a file
index.html
Link the
main.css
file not themain.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:
function showMenu(toggleId, navId)
: This function is defined and takes two arguments,toggleId
andnavId
, 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.const toggle = document.getElementById(toggleId);
: This line retrieves an HTML element with the ID specified bytoggleId
and assigns it to thetoggle
variable. This element is the menu toggle button (hamburger icon).const nav = document.getElementById(navId);
: This line retrieves an HTML element with the ID specified bynavId
and assigns it to thenav
variable. This element is the navigation menu that you want to show/hide.if (toggle && nav) { ... }
: This conditional statement checks if bothtoggle
andnav
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.toggle.addEventListener('click', () => { ... });
: This code attaches a click event listener to thetoggle
element. When the menu toggle button is clicked, the function inside the event listener is executed.nav.classList.toggle('showMenu');
: This line toggles the presence of the CSS class "showMenu" on thenav
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.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.showMenu('nav-toggle', 'nav-menu');
: Finally, this line calls theshowMenu
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.
Use Relative Units for Sizing:
- Instead of fixed pixel values (e.g.,
px
), use relative units like percentages (%) orem
andrem
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.
- Instead of fixed pixel values (e.g.,
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.
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 */ }
Fluid Images and Videos:
- Make images and videos responsive by setting their
max-width
to 100% and usingheight: auto
. This ensures that they scale down proportionally on smaller screens.
- Make images and videos responsive by setting their
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 👋