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:
- The fundamentals of Html & CSS
- 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:
- Index.html
- Styles.css
- 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>
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%;
}
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);
}
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.
- Home
- About
- Services
- Projects and
- 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>
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;
}
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");
});
});
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>
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;
}
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>
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);
}
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>
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;
}
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>
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;
}
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");
}
});
});
});
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>© 2023 Oliver Queen All Right Reserved</p>
</footer>
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;
}
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;
}
}
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