How to build a Portfolio website with HTML, CSS & JavaScript

Amrin - Apr 7 '23 - - Dev Community

Hello everyone, today we are going to build a portfolio website with HTML, CSS & JavaScript.

We will not use any other library or framework, just vanilla CSS & JavaScript.

So, let’s get started.

If you prefer video content then check this one out.:

Prerequisite:

To follow along you don’t need to be a pro at anything, all you need is the fundamentals:

  1. The fundamentals of Html & CSS
  2. The fundamentals of JavaScript.

Setup:

Before we start we’ll have to set up the project. For the setup, you won’t have to do much.

Just create these files:

  1. Index.html
  2. Styles.css
  3. Script.js

and then include this code snippet in the Index.html file:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <link
      href="https://fonts.googleapis.com/css2?family=Poppins:wght@200;300;400;500;700&display=swap"
      rel="stylesheet"
    />
    <link
      rel="stylesheet"
      href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.3.0/css/all.min.css"
    />
    <link rel="stylesheet" href="style.css" />
  </head>
  <body>

        <script src="./script.js"></script>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

Then add this to the styles.css file:

* {
  box-sizing: border-box;
  margin: 0;
}

:root {
  --primary: #03011c;
  --secondery: #1c1847;
  --accent: #0cb8c2;
  --text: #fff;
}

html {
  scroll-behavior: smooth;
}

body {
  background: var(--primary);
  font-family: Poppins, sans-serif;
}

a {
  text-decoration: none;
  color: var(--text);
}

img {
  width: 100%;
}
Enter fullscreen mode Exit fullscreen mode

Also include the utility classes too:

/* utility classes */
.container {
  padding: 4rem 2rem;
  color: var(--text);
}

.highlighted {
  color: var(--accent);
}

.hidden {
  display: none;
}

.btn {
  background-color: var(--accent);
  color: var(--text);
  padding: 0.5rem 3rem;
  border-radius: 5rem;
  display: inline-block;
  margin-top: 2rem;
  border: 2px solid var(--accent);
}

.btn:hover {
  background-color: transparent;
  color: var(--accent);
}
Enter fullscreen mode Exit fullscreen mode

So, the setup is done!
Let’s start building.

The Sections:

Before we start let’s look at how I structured the project.

Our portfolio website has 5 sections.

  1. Home
  2. About
  3. Services
  4. Projects and
  5. Contact

1. Home:

This section includes the header and the hero section.

Let’s build the header first.

Header HTML:

The header consists of the logo, nav links, and mobile menu toggler.

    <header>
      <nav class="nav">
        <a href="/" class="logo"> <span class="highlighted"> O</span>liver</a>

        <div class="nav-links">
          <a href="#home" class="nav-item nav-item-active">Home</a>
          <a href="#about" class="nav-item">About</a>
          <a href="#services" class="nav-item">Services</a>
          <a href="#projects" class="nav-item">projects</a>
          <a href="#contact" class="nav-item">contact</a>
        </div>

        <div class="toggler">
          <span class="line"></span><span class="line"></span
          ><span class="line"></span>
        </div>
      </nav>
    </header>
Enter fullscreen mode Exit fullscreen mode

One quick note before we move on to CSS. We are going to follow the mobile-first approach here, we will at the desktop design at the end.

Header CSS:

/* Header style */
.nav {
  background-color: var(--secondery);
  display: flex;
  justify-content: space-between;
  padding: 0.5rem 1rem;
  position: fixed;
  width: 100%;
}

.logo {
  font-weight: 700;
  font-size: 1.5rem;
}

.nav-links {
  position: absolute;
  display: flex;
  flex-direction: column;
  top: 50px;
  background-color: var(--secondery);
  width: 100%;
  left: -200%;
  padding: 1rem;
  transition: left 0.5s ease;
}

.nav-active {
  left: 0;
}

.nav-item {
  font-size: 0.8rem;
  opacity: 0.7;
  display: block;
  text-align: center;
  margin-bottom: 1rem;
  text-transform: capitalize;
  position: relative;
}

.nav-item::after {
  content: "";
  display: block;
  width: 100%;
  height: 2px;
  background-color: rgb(56, 56, 56);
  margin-top: 0.5rem;
}

.nav-item:hover {
  opacity: 1;
}

.nav-item-active::after {
  background-color: var(--accent);
  opacity: 1;
}

.toggler .line {
  width: 30px;
  height: 2px;
  display: block;
  background-color: var(--text);
  margin: 5px;
}
Enter fullscreen mode Exit fullscreen mode

Header JavaScript:

We have to add the javascript to make the toggler and the nav-item’s active state work.
Here’s the code, add it to the script.js file.

const toggler = document.querySelector(".toggler");
const navLinks = document.querySelector(".nav-links");
const navItems = document.querySelectorAll(".nav-item");

// show and hide navbar in mobile
toggler.addEventListener("click", () => {
  navLinks.classList.toggle("nav-active");
});

// add active class on click to nav-items
navItems.forEach((item) => {
  item.addEventListener("click", function () {
    navItems.forEach((i) => i.classList.remove("nav-item-active"));
    this.classList.add("nav-item-active");

    navLinks.classList.toggle("nav-active");
  });
});
Enter fullscreen mode Exit fullscreen mode

That’s the section. Let’s add the hero section.

Hero HTML

<section class="hero container" id="home">
       <div class="hero-info">
        <h1 class="title">Oliver <span class="highlighted">Queen</span></h1>
        <p class="hero-description">Web developer based in Starling City.</p>
        <a href="#services" class="btn hero-btn">Services</a>
      </div>

      <div class="hero-img">
        <img src="./images/hero-img.png" alt="Oliver Queen" />
      </div>
 </section>
Enter fullscreen mode Exit fullscreen mode

Hero CSS:

/* Hero styles */
.hero {
  display: flex;
  flex-direction: column-reverse;
  justify-content: center;
  align-items: center;
  color: var(--text);
}

.hero-img {
  padding-top: 2rem;
}

.hero-info {
  text-align: center;
  padding-top: 3rem;
}

.title {
  font-size: 2.5rem;
}

.hero-description {
  opacity: 0.7;
}
Enter fullscreen mode Exit fullscreen mode

2. About

Here is the HTML of About section:

<section class="about container" id="about">
      <div class="about-img">
        <img src="./images/about-img.png" alt="Oliver Queen" />
      </div>

      <div class="about-info">
        <h2 class="secondery-title">About Me</h2>

        <p class="description">
          Dolorem facere perspiciatis voluptatibus qui placeat ut eum est autem.
          Deleniti eius repellendus dolorum id illo. Quasi autem dolorem est eos
          autem magni. Tempore consequuntur ullam enim molestias fugit
          voluptatibus sed sit aut.
        </p>

        <p class="description">
          Ex veritatis vitae nam autem sint natus odio perspiciatis autem.
          Dolorem quos dicta culpa quod dolores vel sunt eligendi iste.
          Voluptate ut voluptatum beatae sint ut saepe impedit tempora id. Eaque
          tempore cum officia porro consequatur. Quis eos nostrum eos a commodi.
        </p>

        <p class="description">
          Officiis dolores asperiores inventore ut est delectus. Vel voluptatem
          quae omnis sunt nihil et iste consectetur. Sint rerum totam optio
          tempora et doloremque id.
        </p>

        <a href="#" class="btn btn-secondery">More</a>
      </div>
    </section>
Enter fullscreen mode Exit fullscreen mode

About CSS:

/* About style */
.about {
  color: var(--text);
}

.about-info {
  padding-top: 2rem;
}

.description {
  opacity: 0.7;
  font-size: 0.8rem;
  margin-bottom: 1rem;
  line-height: 1.5;
}

.secondery-title {
  display: inline-block;
  margin-bottom: 1.5rem;
}

.secondery-title::after {
  content: "";
  display: block;
  width: 100%;
  height: 2px;
  margin-top: 0.5rem;
  background-color: var(--accent);
}
Enter fullscreen mode Exit fullscreen mode

3. Services

Services Html

<div class="services container" id="services">
      <div class="services-header">
        <h2 class="secondery-title">Services</h2>
      </div>

      <div class="grid services-grid">
        <div class="grid-item services-item">
          <i class="fa-solid fa-computer"></i>
          <h3>Webdesite Design</h3>
          <p class="description">
            Qui sunt id nemo voluptatem. Cum veritatis reiciendis rem dolores at
            unde harum sit omnis.
          </p>
        </div>
        <div class="grid-item services-item">
          <i class="fa-solid fa-meteor"></i>

          <h3>SEO & Marketing</h3>
          <p class="description">
            Dolores minus suscipit rerum neque. Et vitae rerum et ratione.
            Nesciunt ut dolores neque.
          </p>
        </div>
        <div class="grid-item services-item">
          <i class="fa-solid fa-pen-nib"></i>
          <h3>UI/UX Design</h3>
          <p class="description">
            Architecto et aliquid totam quam sit quibusdam ipsam. Dolorem
            dolores fuga rerum quidem. A odio et qui quia harum.
          </p>
        </div>
      </div>
    </div>
Enter fullscreen mode Exit fullscreen mode

Services section CSS:

/* Services styles */
.services-item {
  background: var(--secondery);
  border-radius: 10px;
  text-align: center;
  padding: 2rem 1rem;
  margin-bottom: 1.5rem;
}

.services-item i {
  font-size: 4rem;
  color: var(--accent);
  margin-bottom: 2rem;
}
Enter fullscreen mode Exit fullscreen mode

4. Projects

Projects Section Html:

<section class="projects container" id="projects">
      <div class="projects-header">
        <h2 class="secondery-title">Projects</h2>

        <div class="projects-tab">
          <button class="projects-tab-btn projects-tab-btn-active" id="all">
            All
          </button>
          <button class="projects-tab-btn" id="design">Design</button>
          <button class="projects-tab-btn" id="seo">SEO</button>
          <button class="projects-tab-btn" id="ui-ux">UI/UX</button>
        </div>
      </div>

      <div class="grid projects-grid">
        <div class="grid-item projects-item all design">
          <img src="./images/project-1.png " alt="" />
        </div>
        <div class="grid-item projects-item all design">
          <img src="./images/project-2.png" alt="" />
        </div>
        <div class="grid-item projects-item all seo">
          <img src="./images/project-3.png" alt="" />
        </div>
        <div class="grid-item projects-item all seo">
          <img src="./images/project-4.png" alt="" />
        </div>
        <div class="grid-item projects-item all ui-ux">
          <img src="./images/project-5.png" alt="" />
        </div>
        <div class="grid-item projects-item all ui-ux">
          <img src="./images/project-6.png" alt="" />
        </div>
      </div>
    </section>
Enter fullscreen mode Exit fullscreen mode

Projects Section CSS:

/* Projects styles */
.projects-header {
  padding-bottom: 2rem;
}

.projects-tab-btn {
  background-color: transparent;
  border: 2px solid var(--accent);
  color: var(--text);
  padding: 0.3rem 1.5rem;
  border-radius: 5rem; 
  margin-right: 0.5rem;
  margin-bottom: 0.5rem;
}

.projects-tab-btn-active {
  background-color: var(--accent);
}

.projects-item {
  margin-bottom: 1rem;
}

.projects-item img {
  border-radius: 10px;
}
Enter fullscreen mode Exit fullscreen mode

Project section JavaScript

const projectsTabBtns = document.querySelectorAll(".projects-tab-btn");
const projectsItems = document.querySelectorAll(".projects-item");

// filter projects
projectsTabBtns.forEach((btn) => {
  btn.addEventListener("click", function () {
    projectsTabBtns.forEach((btn) =>
      btn.classList.remove("projects-tab-btn-active")
    );

    this.classList.add("projects-tab-btn-active");

    projectsItems.forEach((item) => {
      if (item.classList.contains(btn.id)) {
        item.classList.remove("hidden");
      } else {
        item.classList.add("hidden");
      }
    });
  });
});
Enter fullscreen mode Exit fullscreen mode

5. Contact

Contact section HTML:

<section class="container contact" id="contact">
      <div class="contact-info">
        <h2 class="secondery-title">Contact</h2>
        <div class="info-container">
          <div class="contact-info-item">
            <div class="contact-info-icon">
              <i class="fa-solid fa-location-dot"></i>
            </div>
            <div class="contact-info-data">
              <h3>Address</h3>
              <p>Alec Brook 243</p>
            </div>
          </div>
          <div class="contact-info-item">
            <div class="contact-info-icon">
              <i class="fa-solid fa-envelope"></i>
            </div>
            <div class="contact-info-data">
              <h3>Email</h3>
              <p>Oliver@gmail.com</p>
            </div>
          </div>
          <div class="contact-info-item">
            <div class="contact-info-icon">
              <i class="fa-solid fa-phone-volume"></i>
            </div>
            <div class="contact-info-data">
              <h3>Phone</h3>
              <p>333-423-889</p>
            </div>
          </div>
        </div>
      </div>
      <div class="contact-form">
        <form>
          <input type="text" placeholder="Name" />
          <input type="text" placeholder="Email" />
          <textarea
            name="message"
            id=""
            cols="30"
            rows="10"
            placeholder="Message"
          ></textarea>
          <button class="btn submit-btn">Send Message</button>
        </form>
      </div>
    </section>

        <footer class="footer">
      <p>&copy; 2023 Oliver Queen All Right Reserved</p>
    </footer>
Enter fullscreen mode Exit fullscreen mode

Contact section CSS:

/* contact styles */
.contact-info-item {
  display: flex;
}

.contact-info-icon {
  width: 50px;
  height: 50px;
  background-color: var(--accent);
  border-radius: 50%;
  display: flex;
  justify-content: center;
  align-items: center;
  margin-right: 0.5rem;
  margin-bottom: 1rem;
}

.contact-form form {
  display: flex;
  flex-direction: column;
}

input,
textarea {
  background: var(--secondery);
  border: none;
  border-radius: 10px;
  margin-top: 1rem;
  padding: 0.8rem 1rem;
}

.footer {
  color: var(--text);
  text-align: center;
  padding: 2rem 0;
}
Enter fullscreen mode Exit fullscreen mode

This is the mobile design.
Now we will add the desktop design inside the media query.

/* Desktop Design */
@media screen and (min-width: 700px) {
  .container {
    padding: 4rem 6rem;
  }

  .description {
    font-size: 1rem;
  }

  /* grid */
  .grid {
    display: flex;
    gap: 2rem;
    flex-wrap: wrap;
  }

  .grid-item {
    width: 30%;
  }

  /* nav */
  .nav {
    padding-left: 6rem;
    padding-right: 6rem;
    justify-content: space-between;
    align-items: center;
  }

  .toggler {
    display: none;
  }

  .nav-links {
    position: static;
    flex-direction: row;
    padding: 0;
    width: auto;
  }

  .nav-item {
    margin: 0 0.5rem;
  }

  .nav-item::after {
    position: absolute;
    top: 30px;
    margin: 0;
    background: none;
  }

  .nav-item-active {
    opacity: 1;
  }

  .nav-item-active::after {
    background: var(--accent);
  }

  /* hero */
  .hero {
    flex-direction: row;
    justify-content: space-between;
  }

  .hero-info {
    text-align: left;
  }

  .title {
    font-size: 5rem;
  }

  /* About */
  .about {
    display: flex;
    justify-content: space-between;
  }

  .about-img {
    width: 40%;
  }

  .about-info {
    width: 55%;
  }

  /* contact */
  .contact {
    display: flex;
    justify-content: space-between;
  }

  .contact-form {
    width: 55%;
  }

  .submit-btn {
    font-size: 1.5rem;
  }
}
Enter fullscreen mode Exit fullscreen mode

That’s it, you got a complete portfolio website built with HTML, CSS, and JavaScript.

If you want to see more tutorials like this follow me:

Twitter: https://twitter.com/coderamrin

YouTube: https://www.youtube.com/@coderamrin

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .