Skip to content
Learni
View all tutorials
Développement Web

How to Create a Personal Storytelling Timeline on Your Site in 2026

Lire en français

Introduction

Personal storytelling is the art of turning your professional journey into a captivating story that engages recruiters or clients. In 2026, with ultra-performant static websites, integrating this directly into your portfolio is essential to stand out. Imagine an interactive timeline that unfolds your dev journey: from your first 'Hello World' to your open-source projects.

This beginner tutorial guides you step-by-step to create a storytelling section on your HTML/CSS/JS site. No heavy frameworks, just vanilla for maximum perf (perfect Core Web Vitals). At the end, you'll have a copy-pasteable, responsive, and animated component. Why is it crucial? 85% of recruiters spend less than 10s on a CV; a visual story keeps them 3x longer. Ready to narrate your dev epic?

Prerequisites

  • Basic knowledge of HTML, CSS, and JavaScript (beginner level).
  • A code editor like VS Code.
  • A modern browser (Chrome/Firefox).
  • No server needed: just open index.html in your browser.

Initialize the Project

terminal
mkdir storytelling-personnel
cd storytelling-personnel
touch index.html style.css script.js
code .

This command creates a minimal project folder and opens it in VS Code. Each file has a specific role: HTML for structure, CSS for styling, JS for interactivity. Skip frameworks for this beginner tutorial to master the basics without dependencies.

Understand the Narrative Structure

Good storytelling follows a narrative arc: hook (problem), rise (learnings), climax (achievements), resolution (future vision). We'll structure it as a vertical timeline with 4 milestones. Each step includes personal text, an image, and CSS animations. Analogy: like a movie, each scene builds suspense.

Basic HTML Structure

index.html
<!DOCTYPE html>
<html lang="fr">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Mon Storytelling Personnel</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <section class="storytelling">
    <h1>Mon Voyage Dev</h1>
    <div class="timeline">
      <div class="milestone" data-year="2020">
        <div class="icon">🚀</div>
        <h2>Découverte du Code</h2>
        <p>Premier 'Hello World' en HTML. Passion immédiate !</p>
      </div>
      <div class="milestone" data-year="2022">
        <div class="icon">💻</div>
        <h2>Premier Job Junior</h2>
        <p>Construction d'une app React pour un client local.</p>
      </div>
      <div class="milestone" data-year="2024">
        <div class="icon">⭐</div>
        <h2>Projet Open-Source</h2>
        <p>500 stars sur GitHub pour mon CLI tool.</p>
      </div>
      <div class="milestone" data-year="2026">
        <div class="icon">🎯</div>
        <h2>Vision Future</h2>
        <p>Lead Dev Fullstack IA.</p>
      </div>
    </div>
  </section>
  <script src="script.js"></script>
</body>
</html>

This HTML creates a timeline with 4 customizable milestones. The data-year attributes will drive JS animations. Replace the texts with your real story. Pitfall: don't forget the viewport meta for mobile responsiveness.

Style the Timeline

Now apply styles for a vertical timeline effect with a connecting line. Use Flexbox for beginner simplicity and CSS animations for smooth fluidity (no heavy JS).

Responsive CSS Stylesheet

style.css
body {
  margin: 0;
  font-family: 'Segoe UI', sans-serif;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  color: white;
}

.storytelling {
  max-width: 800px;
  padding: 2rem;
}

h1 {
  text-align: center;
  font-size: 3rem;
  margin-bottom: 4rem;
  text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
}

.timeline {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 2rem;
}

.timeline::before {
  content: '';
  position: absolute;
  left: 50%;
  top: 0;
  bottom: 0;
  width: 4px;
  background: rgba(255,255,255,0.3);
  transform: translateX(-50%);
}

.milestone {
  display: flex;
  align-items: center;
  position: relative;
  animation: fadeInUp 1s ease-out;
}

.milestone:nth-child(1) { animation-delay: 0.2s; }
.milestone:nth-child(2) { animation-delay: 0.4s; }
.milestone:nth-child(3) { animation-delay: 0.6s; }
.milestone:nth-child(4) { animation-delay: 0.8s; }

@keyframes fadeInUp {
  from { opacity: 0; transform: translateY(30px); }
  to { opacity: 1; transform: translateY(0); }
}

.milestone:nth-child(odd) {
  flex-direction: row-reverse;
}

.icon {
  font-size: 3rem;
  width: 80px;
  height: 80px;
  background: white;
  color: #667eea;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 10px 30px rgba(0,0,0,0.3);
  z-index: 1;
}

.milestone > div:last-child {
  flex: 1;
  padding: 1rem 2rem;
  background: rgba(255,255,255,0.1);
  backdrop-filter: blur(10px);
  border-radius: 20px;
  margin: 0 2rem;
  box-shadow: 0 8px 32px rgba(0,0,0,0.2);
}

@media (max-width: 768px) {
  .timeline::before { left: 20px; }
  .milestone { flex-direction: column !important; }
  .milestone > div:last-child { margin: 1rem 0 0 60px; }
}

This CSS makes the timeline responsive with a gradient background, central line, and staggered animations. Backdrop-filter adds modern glassmorphism. Pitfall: always test on mobile; media queries adjust for small screens.

Add Interactivity

Make it come alive with JS: scroll reveal and hover effects. Use IntersectionObserver (native, performant) to trigger animations on scroll.

Interactive JS Script

script.js
document.addEventListener('DOMContentLoaded', () => {
  const milestones = document.querySelectorAll('.milestone');

  // IntersectionObserver for scroll reveal
  const observer = new IntersectionObserver((entries) => {
    entries.forEach(entry => {
      if (entry.isIntersecting) {
        entry.target.style.opacity = '1';
        entry.target.style.transform = 'translateY(0)';
      }
    });
  }, { threshold: 0.3 });

  milestones.forEach(milestone => {
    milestone.style.opacity = '0';
    milestone.style.transform = 'translateY(50px)';
    milestone.style.transition = 'opacity 0.6s ease, transform 0.6s ease';
    observer.observe(milestone);
  });

  // Hover effects
  milestones.forEach(milestone => {
    milestone.addEventListener('mouseenter', () => {
      const year = milestone.dataset.year;
      milestone.querySelector('h2').textContent += ` (${year})`;
    });
    milestone.addEventListener('mouseleave', () => {
      const year = milestone.dataset.year;
      milestone.querySelector('h2').textContent = milestone.querySelector('h2').textContent.replace(` (${year})`, '');
    });
  });

  // Smooth scroll to top
  window.addEventListener('scroll', () => {
    if (window.scrollY > 100) {
      // Add a back-to-top button if desired
    }
  });
});

This JS adds scroll reveal and hover effects that display the year. IntersectionObserver is 60fps-friendly compared to scroll listeners. Pitfall: DOMContentLoaded prevents errors if JS loads before HTML; test offline.

JSON Data for Customization

data.json
{
  "story": {
    "title": "Mon Voyage Dev",
    "milestones": [
      {
        "year": 2020,
        "icon": "🚀",
        "title": "Découverte du Code",
        "description": "Premier 'Hello World' en HTML. Passion immédiate pour le web !",
        "image": "https://via.placeholder.com/300x200?text=2020"
      },
      {
        "year": 2022,
        "icon": "💻",
        "title": "Premier Job Junior",
        "description": "Construction d'une app React pour un client local. Apprentissage intensif.",
        "image": "https://via.placeholder.com/300x200?text=2022"
      },
      {
        "year": 2024,
        "icon": "⭐",
        "title": "Projet Open-Source",
        "description": "500 stars sur GitHub pour mon CLI tool en Node.js.",
        "image": "https://via.placeholder.com/300x200?text=2024"
      },
      {
        "year": 2026,
        "icon": "🎯",
        "title": "Vision Future",
        "description": "Devenir Lead Dev Fullstack IA et mentor.",
        "image": "https://via.placeholder.com/300x200?text=2026"
      }
    ]
  }
}

This JSON centralizes your data for easy updates. Integrate it in JS with fetch('./data.json') for dynamic content. Benefit: non-coders can edit it; pitfall: validate JSON to avoid parse errors.

Deploy to GitHub Pages

terminal-deploy
git init
git add .
git commit -m "Initial storytelling portfolio"
git branch -M main
git remote add origin https://github.com/votreusername/storytelling-personnel.git
git push -u origin main
# Puis activez GitHub Pages dans Settings > Pages > Source: Deploy from branch main

Deploy for free in 1 minute on GitHub Pages. Replace votreusername. Final URL: username.github.io/storytelling-personnel. Pitfall: ensure index.html is at the root; Pages handles static assets perfectly.

Best Practices

  • Deeply personalize: replace placeholders with real anecdotes (project names, metrics like "+30% perf").
  • Optimize performance: compress images <100KB, minify CSS/JS with tools like Terser.
  • Accessibility: add aria-label to icons, WCAG AA contrasts.
  • SEO: meta title/desc with keywords like "dev portfolio [your name]".
  • Cross-browser testing: Chrome, Safari, Firefox.

Common Mistakes to Avoid

  • Generic stories: skip "I like coding"; say "I scaled an app from 1k to 100k users".
  • Overloaded animations: limit to 60fps; test with Lighthouse.
  • Non-responsive: always use media queries; test on phone.
  • Malformed JSON: use json validator to check.

Next Steps

Integrate with Next.js for SSR, or Framer Motion for advanced animations. Check our Learni web development courses and advanced portfolio tutorial. Resources: MDN Timeline, Awwwards inspirations.