Published on

Portfolio Project: Build a Technical Documentation Page That Works

Authors

'Portfolio Project: Build a Technical Documentation Page That Works'

A comprehensive, step-by-step guide to building a professional and responsive technical documentation page for your portfolio using HTML, CSS, and a touch of JavaScript.

Table of Contents

So, you're building your developer portfolio and you need projects that scream 'hire me.' You've probably thought about a to-do list, a weather app, or maybe a simple blog. Those are great, but let me introduce you to the unsung hero of portfolio projects: the technical documentation page.

Why is it so great? Because it’s a project that every single developer, from junior to principal, can appreciate. We all live and breathe documentation. Building a good documentation page shows you understand structure, user experience, and clarity—core skills that are valuable in any development role. It’s also a classic project on platforms like freeCodeCamp for a reason!

In this guide, we're not just going to build a basic page. We'll go step-by-step to create a responsive, interactive, and professional-looking documentation site that you'll be proud to feature in your portfolio. We'll stick to the fundamentals—HTML, CSS, and a dash of vanilla JavaScript—to prove you don't need a fancy framework to build something impressive.

Ready? Let's get building.

Why a Technical Documentation Page is a Genius Portfolio Move

Before we write a single line of code, let's appreciate why this project is such a powerhouse.

  • It Showcases Foundational Skills: At its core, this project is a masterclass in HTML structure and CSS layout. You can't fake it. It forces you to think about semantics, accessibility, and responsive design from the ground up.
  • It's Deceptively Complex: A simple doc page is easy. A good doc page? That requires thought. How does the navigation work? Is the code readable? Does it adapt to mobile? These are the details that separate a beginner from an apprentice.
  • It's Infinitely Practical: Every API, library, framework, and language has documentation. By building one, you're creating something that directly mirrors a real-world developer task. This signals to employers that you're thinking about the entire development lifecycle, not just a flashy UI.
  • It's a Content Chameleon: Don't know what to write about? Document something you just learned! Explain CSS Flexbox, JavaScript Promises, the basics of Git, or even document one of your other portfolio projects. It becomes a learning tool and a portfolio piece in one.

Section 1: Laying the Foundation with Semantic HTML

Great websites start with a great HTML structure. A technical documentation page typically has a simple, two-column layout: a navigation bar on the side and the main content area. We can represent this beautifully with semantic HTML, which helps with both SEO and accessibility.

Here’s the skeleton we'll be working with:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>JS Docs: The Basics</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div class="container">
        <nav id="navbar">
            <header>JS Docs: The Basics</header>
            <ul>
                <li><a class="nav-link" href="#Introduction">Introduction</a></li>
                <li><a class="nav-link" href="#What_you_should_already_know">What you should already know</a></li>
                <li><a class="nav-link" href="#JavaScript_and_Java">JavaScript and Java</a></li>
                <li><a class="nav-link" href="#Variables">Variables</a></li>
                <li><a class="nav-link" href="#Declaring_variables">Declaring variables</a></li>
                <li><a class="nav-link" href="#Constants">Constants</a></li>
            </ul>
        </nav>

        <main id="main-doc">
            <section class="main-section" id="Introduction">
                <header>Introduction</header>
                <article>
                    <p>JavaScript is a cross-platform, object-oriented scripting language...</p>
                    <p>It is a small and lightweight language. A host environment...</p>
                    <ul>
                        <li>Client-side JavaScript extends the core language...</li>
                        <li>Server-side JavaScript extends the core language...</li>
                    </ul>
                </article>
            </section>

            <section class="main-section" id="What_you_should_already_know">
                <header>What you should already know</header>
                <article>
                    <p>This guide assumes you have the following basic background:</p>
                    <ul>
                        <li>A general understanding of the Internet and the World Wide Web (WWW).</li>
                        <li>Good working knowledge of HyperText Markup Language (HTML).</li>
                    </ul>
                </article>
            </section>

            <section class="main-section" id="JavaScript_and_Java">
                <header>JavaScript and Java</header>
                <article>
                    <p>JavaScript and Java are similar in some ways but fundamentally different in others...</p>
                    <code>// This is a single-line JavaScript comment</code>
                </article>
            </section>

            <section class="main-section" id="Variables">
                <header>Variables</header>
                <article>
                    <p>You use variables as symbolic names for values in your application...</p>
                    <p>The name of a variable, called its identifier, must conform to certain rules.</p>
                </article>
            </section>

            <section class="main-section" id="Declaring_variables">
                <header>Declaring variables</header>
                <article>
                    <p>You can declare a variable in three ways:</p>
                    <p>With the keyword var. For example, <code>var x = 42.</code></p>
                    <p>With the keyword let. For example, <code>let y = 13.</code></p>
                    <pre><code>// Example of a multi-line code block
function greet(name) {
  return 'Hello, ' + name;
}</code></pre>
                </article>
            </section>

            <section class="main-section" id="Constants">
                <header>Constants</header>
                <article>
                    <p>You can create a read-only, named constant with the const keyword.</p>
                    <code>const PI = 3.14;</code>
                </article>
            </section>
        </main>
    </div>
    <script src="script.js"></script>
</body>
</html>

Breaking Down the Structure:

  • <nav id="navbar">: This is our navigation container. The header inside gives it a title, and the <ul> contains our navigation links.
  • <a class="nav-link" href="#...">: These are crucial. The href attribute points to the id of a <section> in the main content. This is how we create the jump-to-section functionality.
  • <main id="main-doc">: This element holds all our documentation content. It's the main course of our page.
  • <section class="main-section" id="...">: Each section is a distinct topic in our documentation. The id here is the target for our navigation links. This is a requirement for the freeCodeCamp project and a fantastic practice for navigability.
  • <header>: Inside each section, a <header> element provides a clear title for that topic.
  • <code> and <pre>: We use <code> for inline code snippets and <pre><code>...</code></pre> for multi-line code blocks. The <pre> tag preserves whitespace and formatting, which is essential for code readability.

Section 2: Styling with CSS: From Bland to Grand

Now that we have a solid HTML skeleton, let's breathe some life into it with CSS. We'll focus on three key areas: the main layout, styling the components, and making it all responsive.

Let's start by setting up some CSS variables for a consistent theme. This makes it super easy to change colors or fonts later on.

/* style.css */
:root {
    --main-bg-color: #ffffff;
    --nav-bg-color: #f8f9fa;
    --text-color: #333;
    --border-color: #e7e7e7;
    --link-color: #007bff;
    --code-bg-color: #f1f1f1;
    --header-font: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    --body-font: 'Georgia', serif;
}

body {
    font-family: var(--body-font);
    line-height: 1.6;
    color: var(--text-color);
    margin: 0;
    background-color: var(--main-bg-color);
}

Creating the Two-Column Layout

This is where the magic happens. We'll use CSS Grid to create our main two-column layout. It's perfect for this job because it's designed for two-dimensional layouts.

.container {
    display: grid;
    grid-template-columns: 300px 1fr;
    min-height: 100vh;
}

#navbar {
    grid-column: 1 / 2;
    border-right: 2px solid var(--border-color);
    padding: 20px;
    position: fixed; /* Make it sticky */
    top: 0;
    left: 0;
    width: 300px;
    height: 100%;
    overflow-y: auto; /* Allow scrolling if content overflows */
    background-color: var(--nav-bg-color);
}

#main-doc {
    grid-column: 2 / 3;
    padding: 30px;
}

What's happening here?

  1. We set .container to display: grid.
  2. grid-template-columns: 300px 1fr; creates two columns. The first is a fixed 300px wide (for our navbar), and the second (1fr) takes up the remaining available space.
  3. We make the #navbar position: fixed so it stays on the screen as the user scrolls through the content. We also give it a width of 300px to match our grid column and height: 100% to fill the viewport.
  4. #main-doc is placed in the second grid column. The padding gives our content some breathing room.

Styling the Components

Now let's style the individual pieces to make them look clean and professional.

Navigation Bar:

#navbar header {
    font-family: var(--header-font);
    font-size: 1.8em;
    font-weight: bold;
    text-align: center;
    margin-bottom: 20px;
}

#navbar ul {
    list-style: none;
    padding: 0;
    margin: 0;
}

#navbar li {
    border-top: 1px solid var(--border-color);
}

#navbar a {
    display: block;
    padding: 12px 15px;
    text-decoration: none;
    color: var(--link-color);
    transition: background-color 0.2s, color 0.2s;
}

#navbar a:hover {
    background-color: var(--link-color);
    color: white;
}

Main Content and Code Blocks: This is a technical documentation page, so our code blocks need to look good!

.main-section header {
    font-family: var(--header-font);
    font-size: 2em;
    font-weight: 500;
    border-bottom: 1px solid #ccc;
    margin-bottom: 20px;
    padding-bottom: 10px;
}

code {
    background-color: var(--code-bg-color);
    padding: 2px 5px;
    border-radius: 4px;
    font-family: 'Courier New', Courier, monospace;
}

pre {
    background-color: var(--code-bg-color);
    border: 1px solid var(--border-color);
    border-radius: 5px;
    padding: 15px;
    white-space: pre-wrap; /* Wrap long lines of code */
    word-wrap: break-word;
    overflow-x: auto; /* Add scrollbar for very long lines */
}

pre code {
    background-color: transparent; /* Reset background for code inside pre */
    padding: 0;
}

Making It Responsive with Media Queries

A professional site works on all screen sizes. On smaller screens, a two-column layout is cramped. We'll use a media query to stack the navigation on top of the main content.

@media (max-width: 800px) {
    .container {
        /* Switch to a single-column layout */
        grid-template-columns: 1fr;
    }

    #navbar {
        /* Unfix the navbar and make it full-width */
        position: static;
        width: 100%;
        height: auto;
        border-right: none;
        border-bottom: 2px solid var(--border-color);
        max-height: 250px; /* Prevent it from taking too much space */
        overflow-y: auto;
        padding: 0;
    }

    #navbar header {
        padding: 20px;
    }

    #main-doc {
        /* Take up the full width */
        grid-column: 1 / 2;
        margin-left: 0;
    }
}

With this media query, once the screen width is 800px or less, our layout transforms. The navbar becomes a scrollable section at the top, and the main content flows below it. Simple, effective, and responsive!

Section 3: A Sprinkle of JavaScript for a Pro Touch

Our page is functional and looks good, but we can add some JavaScript to make the user experience even better. We'll implement a feature common in modern documentation sites: highlighting the active navigation link as you scroll.

We'll use the Intersection Observer API. It's a modern, performant way to detect when an element enters the viewport, far better than listening to every single scroll event.

First, add this CSS class to style our active link:

/* Add this to your style.css */
.nav-link.active {
    background-color: var(--link-color);
    color: white;
    font-weight: bold;
}

Now, let's create our script.js file:

// script.js
document.addEventListener('DOMContentLoaded', () => {
    const sections = document.querySelectorAll('.main-section');
    const navLinks = document.querySelectorAll('.nav-link');

    // The Intersection Observer configuration
    const observerOptions = {
        root: null, // observes intersections relative to the viewport
        rootMargin: '0px',
        threshold: 0.5 // trigger when 50% of the section is visible
    };

    const observer = new IntersectionObserver((entries, observer) => {
        entries.forEach(entry => {
            // If the section is intersecting (visible)
            if (entry.isIntersecting) {
                // Get the id of the visible section
                const currentSectionId = entry.target.id;

                // Remove 'active' class from all nav links
                navLinks.forEach(link => {
                    link.classList.remove('active');
                });

                // Find the corresponding nav link and add 'active' class
                const activeLink = document.querySelector(`a[href="#${currentSectionId}"]`);
                if (activeLink) {
                    activeLink.classList.add('active');
                }
            }
        });
    }, observerOptions);

    // Observe each main section
    sections.forEach(section => {
        observer.observe(section);
    });

    // Bonus: Smooth scrolling for all anchor links
    // This can also be done in CSS with `scroll-behavior: smooth;` on the <html> element
    document.querySelectorAll('a[href^="#"]).forEach(anchor => {
        anchor.addEventListener('click', function (e) {
            e.preventDefault();

            document.querySelector(this.getAttribute('href')).scrollIntoView({
                behavior: 'smooth'
            });
        });
    });
});

What this JavaScript does:

  1. IntersectionObserver Setup: We create a new observer. The threshold: 0.5 means our callback function will fire when 50% of a target section is visible in the viewport.
  2. The Callback Function: When a section enters the viewport (entry.isIntersecting), we find its id.
  3. Update Active Link: We then loop through all our navigation links, remove any existing active class, and add it only to the link that corresponds to the currently visible section.
  4. Observe!: We tell the observer to start watching all of our <section> elements.
  5. Bonus - Smooth Scrolling: The second part adds a click listener to all anchor links. Instead of the default jarring jump, scrollIntoView({ behavior: 'smooth' }) provides a pleasant scrolling animation. Note: The most modern and easiest way to do this is by adding html { scroll-behavior: smooth; } to your CSS. The JavaScript method is shown here for completeness and for browsers that might not support the CSS property.

Section 4: Best Practices and Finishing Touches

You've built a fantastic project. Now let's polish it to a professional shine.

  • Accessibility (a11y): Good news! By using semantic HTML (<nav>, <main>, <section>, <header>), you've already done a lot for accessibility. Screen readers can understand the layout of your page. Ensure your color choices have sufficient contrast using an online contrast checker. Make sure all functionality is usable with a keyboard (our navigation and scrolling should be, by default).

  • Choose Your Content Wisely: The content of your documentation matters. Pick a topic you're either passionate about or want to learn better. Explaining a concept is one of the best ways to solidify your own understanding. Some ideas:

    • A deep dive into the CSS Grid properties you just used.
    • An explanation of JavaScript's async/await.
    • A basic guide to using a popular API like the GitHub API.
    • Documentation for another one of your portfolio projects.
  • Deployment: Don't let your project sit on your local machine! Deploying it is the final step. Services like GitHub Pages, Netlify, and Vercel offer free and incredibly simple ways to get your static site online. Most can be connected directly to your GitHub repository, automatically deploying any changes you push.

Conclusion: You've Built More Than a Page

Congratulations! You've successfully designed and built a technical documentation page from scratch. You didn't just copy and paste some code; you thoughtfully structured your HTML, crafted a responsive and clean layout with CSS, and added a touch of professional interactivity with JavaScript.

This project is a testament to your understanding of the core technologies of the web. It demonstrates attention to detail, a focus on user experience, and the ability to organize information clearly—qualities that every hiring manager is looking for.

Add this to your portfolio, link the live version and the GitHub repository, and be prepared to talk about the choices you made. Explain why you used CSS Grid, why you chose the Intersection Observer API, and how you ensured the page was responsive.

Now, the only question left is: what will you document first? Go build something amazing!