Fading Coder

One Final Commit for the Last Sprint

Home > Tools > Content

Building a Dynamic Grid Morphing Navigation with HTML5, CSS3, and Fetch API

Tools 1

Grid morphing navigation delivers visually engaging transitions between interactive menu states by combining semantic markup, modern CSS transforms, and asynhcronous content loading. Key implementation pillars include grid-based posisioning for menu cells, CSS transitions/transforms for scaling/shifting effects, and Fetch API for seamless content updates.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Dynamic Morphing Grid Nav</title>
    <style>
        :root {
            --nav-blue: #0F52BA;
            --nav-green: #2ECC71;
            --nav-purple: #9B59B6;
            --nav-orange: #F39C12;
            --nav-pink: #E91E63;
            --nav-teal: #00BCD4;
            --nav-gray: #34495E;
            --transition-fast: 250ms cubic-bezier(0.4, 0, 0.2, 1);
            --transition-medium: 450ms cubic-bezier(0.4, 0, 0.2, 1);
        }

        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: 'Segoe UI', Roboto, sans-serif;
        }

        body {
            background-color: #F5F7FA;
            min-height: 100vh;
            padding: 2rem 1rem;
        }

        .site-wrapper {
            max-width: 1200px;
            margin: 0 auto;
        }

        .page-header {
            text-align: center;
            margin-bottom: 3rem;
            color: #2C3E50;
        }

        .morph-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
            gap: 1.2rem;
            margin-bottom: 3rem;
        }

        .grid-cell {
            position: relative;
            height: 140px;
            border-radius: 12px;
            overflow: hidden;
            cursor: pointer;
            transition: all var(--transition-medium);
            z-index: 1;
        }

        .grid-cell.active {
            transform: scale(1.15);
            box-shadow: 0 18px 40px rgba(0,0,0,0.2);
            z-index: 10;
        }

        .cell-inner {
            position: absolute;
            inset: 0;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            color: white;
            padding: 1rem;
            text-align: center;
            transition: all var(--transition-fast);
        }

        .cell-icon {
            font-size: 2.8rem;
            margin-bottom: 0.8rem;
            transition: transform var(--transition-medium);
        }

        .cell-label {
            font-weight: 600;
            font-size: 1rem;
            opacity: 0;
            transform: translateY(15px);
            transition: all var(--transition-fast);
        }

        .grid-cell:hover .cell-icon {
            transform: translateY(-18px) scale(0.85);
        }

        .grid-cell:hover .cell-label {
            opacity: 1;
            transform: translateY(0);
        }

        .content-panel {
            background-color: white;
            border-radius: 16px;
            padding: 2.5rem;
            box-shadow: 0 4px 20px rgba(0,0,0,0.08);
            opacity: 1;
            transform: translateY(0);
            transition: all var(--transition-medium);
        }

        .content-panel.fade-out {
            opacity: 0;
            transform: translateY(20px);
        }

        .content-panel h2 {
            color: var(--nav-blue);
            margin-bottom: 1rem;
        }
    </style>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css">
</head>
<body>
    <div class="site-wrapper">
        <header class="page-header">
            <h1>Morphing Grid Navigation</h1>
            <p>Interactive, animating navigation with smooth content updates</p>
        </header>

        <nav id="morph-nav" class="morph-grid"></nav>

        <section id="content-display" class="content-panel">
            <h2>Welcome</h2>
            <p>Select a tile from the morphing grid above to view dynamic content. Hover over tiles to see subtle animation previews.</p>
        </section>
    </div>

    <script>
        const navTiles = [
            { id: 'home', icon: 'fa-house', label: 'Dashboard', color: 'var(--nav-blue)', source: 'data/dashboard.json' },
            { id: 'about', icon: 'fa-building', label: 'Company', color: 'var(--nav-green)', source: 'data/company.json' },
            { id: 'services', icon: 'fa-tools', label: 'Solutions', color: 'var(--nav-purple)', source: 'data/solutions.json' },
            { id: 'portfolio', icon: 'fa-images', label: 'Showcase', color: 'var(--nav-orange)', source: 'data/showcase.json' },
            { id: 'blog', icon: 'fa-newspaper', label: 'Updates', color: 'var(--nav-pink)', source: 'data/updates.json' },
            { id: 'contact', icon: 'fa-headset', label: 'Support', color: 'var(--nav-teal)', source: 'data/support.json' },
            { id: 'analytics', icon: 'fa-chart-line', label: 'Metrics', color: 'var(--nav-gray)', source: 'data/metrics.json' },
            { id: 'security', icon: 'fa-lock', label: 'Privacy', color: '#1ABC9C', source: 'data/privacy.json' }
        ];

        let selectedTile = null;

        function renderNavigation() {
            const navContainer = document.getElementById('morph-nav');
            navTiles.forEach(tile => {
                const tileEl = document.createElement('div');
                tileEl.className = 'grid-cell';
                tileEl.style.backgroundColor = tile.color;
                tileEl.dataset.tileId = tile.id;
                tileEl.dataset.contentSource = tile.source;
                tileEl.innerHTML = `
                    <div class="cell-inner">
                        <i class="cell-icon fa-solid ${tile.icon}"></i>
                        <span class="cell-label">${tile.label}</span>
                    </div>
                `;
                tileEl.addEventListener('click', () => activateTile(tileEl));
                navContainer.appendChild(tileEl);
            });
        }

        function activateTile(tileEl) {
            if (selectedTile) {
                selectedTile.classList.remove('active');
            }
            tileEl.classList.add('active');
            selectedTile = tileEl;
            updateContent(tileEl.dataset.contentSource);
        }

        async function updateContent(sourceUrl) {
            const panel = document.getElementById('content-display');
            panel.classList.add('fade-out');
            
            try {
                const response = await fetch(sourceUrl);
                if (!response.ok) throw new Error(`HTTP error! Status: ${response.status}`);
                const data = await response.json();
                setTimeout(() => {
                    panel.innerHTML = `<h2>${data.title}</h2><p>${data.description}</p>`;
                    panel.classList.remove('fade-out');
                }, 250);
            } catch (error) {
                setTimeout(() => {
                    panel.innerHTML = `<h2 style="color:#E74C3C">Content Unavailable</h2><p>${error.message}</p>`;
                    panel.classList.remove('fade-out');
                }, 250);
            }
        }

        document.addEventListener('DOMContentLoaded', renderNavigation);
    </script>
</body>
</html>

Key Technical Components

  1. Semantic HTML5 Structure: Uses <header>, <nav>, and <section> for accessibility and clarity, with grid container holding dynamically generated navigation cells.
  2. CSS3 Grid & Animations: Implements responisve grid layout with auto-fit and minmax for adaptive tile sizing, transform for scaling/shifting hover/active states, and transition with cubic-bezier easing for smooth movement.
  3. Fetch API for Asynchronous Loading: Replaces XMLHttpRequest with modern Fetch API for simpler promise-based content fetching, including error handling and content panel fade transitions during updates.

Create sample JSON files in a data/ directory (e.g., dashboard.json) to test content loading:

{
  "title": "Dashboard Overview",
  "description": "Track key performance indicators, recent activities, and quick access shortcuts from your personalized dashboard."
}

Related Articles

Efficient Usage of HTTP Client in IntelliJ IDEA

IntelliJ IDEA incorporates a versatile HTTP client tool, enabling developres to interact with RESTful services and APIs effectively with in the editor. This functionality streamlines workflows, replac...

Installing CocoaPods on macOS Catalina (10.15) Using a User-Managed Ruby

System Ruby on macOS 10.15 frequently fails to build native gems required by CocoaPods (for example, ffi), leading to errors like: ERROR: Failed to build gem native extension checking for ffi.h... no...

Resolve PhpStorm "Interpreter is not specified or invalid" on WAMP (Windows)

Symptom PhpStorm displays: "Interpreter is not specified or invalid. Press ‘Fix’ to edit your project configuration." This occurs when the IDE cannot locate a valid PHP CLI executable or when the debu...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.