HTML Advanced (Part 2)

Master advanced HTML concepts including web components, HTML APIs, performance optimization, and SEO best practices.

HTML Advanced Content

This content has been divided into two parts for better readability:

Web Components

Web Components are a set of web platform APIs that allow you to create custom, reusable, encapsulated HTML elements. They consist of four main technologies:

Custom Elements

Custom Elements allow you to define your own custom HTML elements with their own behavior.

// Define a custom element
class UserCard extends HTMLElement {
    constructor() {
        super();
        
        // Element created
        this.render();
    }
    
    // Lifecycle callbacks
    connectedCallback() {
        // Element added to the DOM
        console.log('User card added to the page');
    }
    
    disconnectedCallback() {
        // Element removed from the DOM
        console.log('User card removed from the page');
    }
    
    attributeChangedCallback(name, oldValue, newValue) {
        // Attribute changed
        console.log(`Attribute ${name} changed from ${oldValue} to ${newValue}`);
        this.render();
    }
    
    static get observedAttributes() {
        // Attributes to watch for changes
        return ['name', 'avatar', 'email'];
    }
    
    render() {
        // Get attribute values
        const name = this.getAttribute('name') || 'Anonymous';
        const avatar = this.getAttribute('avatar') || 'default-avatar.png';
        const email = this.getAttribute('email') || '';
        
        // Create the card content
        this.innerHTML = `
            
${name}
`; } } // Register the custom element customElements.define('user-card', UserCard);

Using the custom element in HTML:

<user-card 
    name="John Doe" 
    avatar="https://example.com/avatar.jpg" 
    email="[email protected]">
</user-card>

Shadow DOM

Shadow DOM allows you to encapsulate the structure, style, and behavior of your custom elements, keeping them separate from the main document DOM.

class UserCardShadow extends HTMLElement {
    constructor() {
        super();
        
        // Create a shadow root
        this.attachShadow({ mode: 'open' });
        
        // Get attribute values
        const name = this.getAttribute('name') || 'Anonymous';
        const avatar = this.getAttribute('avatar') || 'default-avatar.png';
        const email = this.getAttribute('email') || '';
        
        // Create the shadow DOM content
        this.shadowRoot.innerHTML = `
            <style>
                /* Styles are encapsulated within the shadow DOM */
                .user-card {
                    display: flex;
                    align-items: center;
                    background-color: #f0f0f0;
                    border-radius: 8px;
                    padding: 16px;
                    width: 300px;
                    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
                }
                
                .user-card img {
                    width: 64px;
                    height: 64px;
                    border-radius: 50%;
                    margin-right: 16px;
                }
                
                .user-info h3 {
                    margin: 0 0 8px;
                    font-size: 18px;
                }
                
                .user-info p {
                    margin: 0;
                    color: #666;
                }
            </style>
            
            <div class="user-card">
                <img src="${avatar}" alt="${name}" />
                <div class="user-info">
                    <h3>${name}</h3>
                    ${email ? `<p>${email}</p>` : ''}
                </div>
            </div>
        `;
    }
}

customElements.define('user-card-shadow', UserCardShadow);

HTML Templates and Slots

The <template> element allows you to define fragments of HTML that can be cloned and inserted into the document. The <slot> element acts as a placeholder that you can fill with your own markup.

<!-- Define a template -->
<template id="user-card-template">
    <style>
        .user-card {
            display: flex;
            align-items: center;
            background-color: #f0f0f0;
            border-radius: 8px;
            padding: 16px;
            width: 300px;
            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
        }
        
        .user-card img {
            width: 64px;
            height: 64px;
            border-radius: 50%;
            margin-right: 16px;
        }
        
        .user-info h3 {
            margin: 0 0 8px;
            font-size: 18px;
        }
        
        .user-info p {
            margin: 0;
            color: #666;
        }
        
        .actions {
            margin-top: 16px;
        }
    </style>
    
    <div class="user-card">
        <img>
        <div class="user-info">
            <h3><slot name="user-name">Anonymous</slot></h3>
            <p><slot name="user-email"></slot></p>
            <div class="actions">
                <slot name="actions"></slot>
            </div>
        </div>
    </div>
</template>

<script>
    class UserCardTemplate extends HTMLElement {
        constructor() {
            super();
            
            // Create a shadow root
            this.attachShadow({ mode: 'open' });
            
            // Get the template content
            const template = document.getElementById('user-card-template');
            const templateContent = template.content;
            
            // Clone the template
            this.shadowRoot.appendChild(templateContent.cloneNode(true));
            
            // Set the avatar
            const avatar = this.getAttribute('avatar') || 'default-avatar.png';
            this.shadowRoot.querySelector('img').src = avatar;
            this.shadowRoot.querySelector('img').alt = this.getAttribute('name') || 'Anonymous';
        }
    }
    
    customElements.define('user-card-template', UserCardTemplate);
</script>

Using the template-based custom element with slots:

<user-card-template avatar="https://example.com/avatar.jpg">
    <span slot="user-name">John Doe</span>
    <span slot="user-email">[email protected]</span>
    <div slot="actions">
        <button>View Profile</button>
        <button>Send Message</button>
    </div>
</user-card-template>

Building a Complete Web Component

Here's an example of a complete web component that combines custom elements, shadow DOM, and templates:

// Define the template
const template = document.createElement('template');
template.innerHTML = `
    <style>
        :host {
            display: block;
            font-family: Arial, sans-serif;
        }
        
        .toggle-switch {
            position: relative;
            display: inline-block;
            width: 60px;
            height: 34px;
        }
        
        .toggle-switch input {
            opacity: 0;
            width: 0;
            height: 0;
        }
        
        .slider {
            position: absolute;
            cursor: pointer;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background-color: #ccc;
            transition: .4s;
            border-radius: 34px;
        }
        
        .slider:before {
            position: absolute;
            content: "";
            height: 26px;
            width: 26px;
            left: 4px;
            bottom: 4px;
            background-color: white;
            transition: .4s;
            border-radius: 50%;
        }
        
        input:checked + .slider {
            background-color: #2196F3;
        }
        
        input:focus + .slider {
            box-shadow: 0 0 1px #2196F3;
        }
        
        input:checked + .slider:before {
            transform: translateX(26px);
        }
        
        .toggle-label {
            margin-left: 70px;
            line-height: 34px;
            vertical-align: top;
        }
    </style>
    
    <label class="toggle-switch">
        <input type="checkbox">
        <span class="slider"></span>
    </label>
    <span class="toggle-label"><slot>Toggle</slot></span>
`;

class ToggleSwitch extends HTMLElement {
    constructor() {
        super();
        
        // Create a shadow root
        this.attachShadow({ mode: 'open' });
        
        // Attach the template
        this.shadowRoot.appendChild(template.content.cloneNode(true));
        
        // Get elements
        this.checkbox = this.shadowRoot.querySelector('input');
        
        // Bind methods
        this.handleChange = this.handleChange.bind(this);
    }
    
    // Lifecycle callbacks
    connectedCallback() {
        // Set initial state
        if (this.hasAttribute('checked')) {
            this.checkbox.checked = true;
        }
        
        // Add event listener
        this.checkbox.addEventListener('change', this.handleChange);
    }
    
    disconnectedCallback() {
        // Remove event listener
        this.checkbox.removeEventListener('change', this.handleChange);
    }
    
    // Observed attributes
    static get observedAttributes() {
        return ['checked', 'disabled'];
    }
    
    // Attribute changed callback
    attributeChangedCallback(name, oldValue, newValue) {
        if (name === 'checked') {
            this.checkbox.checked = this.hasAttribute('checked');
        } else if (name === 'disabled') {
            this.checkbox.disabled = this.hasAttribute('disabled');
        }
    }
    
    // Event handlers
    handleChange() {
        const isChecked = this.checkbox.checked;
        
        if (isChecked) {
            this.setAttribute('checked', '');
        } else {
            this.removeAttribute('checked');
        }
        
        // Dispatch custom event
        this.dispatchEvent(new CustomEvent('toggle', {
            detail: { checked: isChecked },
            bubbles: true,
            composed: true
        }));
    }
    
    // Public API
    get checked() {
        return this.hasAttribute('checked');
    }
    
    set checked(value) {
        if (value) {
            this.setAttribute('checked', '');
        } else {
            this.removeAttribute('checked');
        }
    }
    
    get disabled() {
        return this.hasAttribute('disabled');
    }
    
    set disabled(value) {
        if (value) {
            this.setAttribute('disabled', '');
        } else {
            this.removeAttribute('disabled');
        }
    }
}

// Register the custom element
customElements.define('toggle-switch', ToggleSwitch);

Using the toggle switch component:

<toggle-switch checked>Dark Mode</toggle-switch>

<script>
    const toggleSwitch = document.querySelector('toggle-switch');
    
    toggleSwitch.addEventListener('toggle', (event) => {
        const isChecked = event.detail.checked;
        console.log('Toggle switch changed:', isChecked);
        
        // Apply dark mode
        document.body.classList.toggle('dark-mode', isChecked);
    });
</script>

Web Component Libraries

While you can build web components from scratch, there are several libraries that make it easier:

HTML APIs

Modern HTML comes with a rich set of JavaScript APIs that enable powerful functionality in web applications.

Geolocation API

The Geolocation API allows web applications to access the user's geographical location.

// Check if geolocation is supported
if ('geolocation' in navigator) {
    // Get current position
    navigator.geolocation.getCurrentPosition(
        // Success callback
        (position) => {
            const latitude = position.coords.latitude;
            const longitude = position.coords.longitude;
            const accuracy = position.coords.accuracy;
            
            console.log(`Latitude: ${latitude}, Longitude: ${longitude}`);
            console.log(`Accuracy: ${accuracy} meters`);
            
            // Use the coordinates (e.g., display on a map)
            displayMap(latitude, longitude);
        },
        // Error callback
        (error) => {
            switch (error.code) {
                case error.PERMISSION_DENIED:
                    console.error("User denied the request for geolocation");
                    break;
                case error.POSITION_UNAVAILABLE:
                    console.error("Location information is unavailable");
                    break;
                case error.TIMEOUT:
                    console.error("The request to get user location timed out");
                    break;
                case error.UNKNOWN_ERROR:
                    console.error("An unknown error occurred");
                    break;
            }
        },
        // Options
        {
            enableHighAccuracy: true, // Use GPS if available
            timeout: 5000, // Time to wait for a position
            maximumAge: 0 // Don't use a cached position
        }
    );
    
    // Watch position (for tracking)
    const watchId = navigator.geolocation.watchPosition(
        (position) => {
            // Update position as the user moves
            updatePosition(position.coords.latitude, position.coords.longitude);
        },
        (error) => {
            console.error("Error watching position:", error.message);
        }
    );
    
    // Stop watching
    // navigator.geolocation.clearWatch(watchId);
} else {
    console.error("Geolocation is not supported by this browser");
}

Drag and Drop API

The HTML Drag and Drop API allows you to implement drag-and-drop features in web applications.

<!-- Draggable element -->
<div id="draggable" draggable="true">Drag me</div>

<!-- Drop targets -->
<div id="drop-target-1" class="drop-target">Drop Zone 1</div>
<div id="drop-target-2" class="drop-target">Drop Zone 2</div>

<script>
    // Get elements
    const draggable = document.getElementById('draggable');
    const dropTargets = document.querySelectorAll('.drop-target');
    
    // Add event listeners to draggable element
    draggable.addEventListener('dragstart', (event) => {
        // Set data to be dragged
        event.dataTransfer.setData('text/plain', event.target.id);
        
        // Add a class for styling
        event.target.classList.add('dragging');
        
        // Set allowed effects
        event.dataTransfer.effectAllowed = 'move';
    });
    
    draggable.addEventListener('dragend', (event) => {
        // Remove styling class
        event.target.classList.remove('dragging');
    });
    
    // Add event listeners to drop targets
    dropTargets.forEach(target => {
        // Dragover event - prevent default to allow drop
        target.addEventListener('dragover', (event) => {
            event.preventDefault();
            event.dataTransfer.dropEffect = 'move';
            target.classList.add('dragover');
        });
        
        // Dragleave event - remove styling
        target.addEventListener('dragleave', (event) => {
            target.classList.remove('dragover');
        });
        
        // Drop event - handle the drop
        target.addEventListener('drop', (event) => {
            event.preventDefault();
            
            // Get the dragged element id
            const id = event.dataTransfer.getData('text/plain');
            const draggedElement = document.getElementById(id);
            
            // Append the dragged element to the drop target
            target.appendChild(draggedElement);
            
            // Remove styling
            target.classList.remove('dragover');
        });
    });
</script>

Web Storage API

The Web Storage API provides mechanisms for storing data in the browser. It includes localStorage (persistent storage) and sessionStorage (session-only storage).

// localStorage - persists even after browser is closed
// Store data
localStorage.setItem('username', 'JohnDoe');
localStorage.setItem('preferences', JSON.stringify({
    theme: 'dark',
    fontSize: 16,
    notifications: true
}));

// Retrieve data
const username = localStorage.getItem('username');
const preferences = JSON.parse(localStorage.getItem('preferences'));

console.log('Username:', username);
console.log('Preferences:', preferences);

// Remove specific item
localStorage.removeItem('username');

// Clear all localStorage
// localStorage.clear();

// sessionStorage - cleared when page session ends
// Store data
sessionStorage.setItem('cart', JSON.stringify([
    { id: 1, name: 'Product 1', price: 29.99 },
    { id: 2, name: 'Product 2', price: 19.99 }
]));

// Retrieve data
const cart = JSON.parse(sessionStorage.getItem('cart'));
console.log('Cart:', cart);

// Storage event - listen for changes in other tabs/windows
window.addEventListener('storage', (event) => {
    console.log('Storage changed in another tab/window');
    console.log('Key:', event.key);
    console.log('Old value:', event.oldValue);
    console.log('New value:', event.newValue);
    console.log('Storage area:', event.storageArea);
});

IndexedDB API

IndexedDB is a low-level API for client-side storage of significant amounts of structured data, including files/blobs.

// Open a database
const request = indexedDB.open('MyDatabase', 1);

// Handle database upgrade (called when database is created or version changes)
request.onupgradeneeded = (event) => {
    const db = event.target.result;
    
    // Create an object store (similar to a table in SQL databases)
    const store = db.createObjectStore('users', { keyPath: 'id', autoIncrement: true });
    
    // Create indexes (for searching)
    store.createIndex('name', 'name', { unique: false });
    store.createIndex('email', 'email', { unique: true });
    
    console.log('Database setup complete');
};

// Handle success
request.onsuccess = (event) => {
    const db = event.target.result;
    console.log('Database opened successfully');
    
    // Add data
    addUser(db, {
        name: 'John Doe',
        email: '[email protected]',
        age: 30
    });
    
    // Get data
    getUserById(db, 1);
    
    // Get data using an index
    getUserByEmail(db, '[email protected]');
};

// Handle error
request.onerror = (event) => {
    console.error('Database error:', event.target.error);
};

// Function to add a user
function addUser(db, user) {
    // Start a transaction
    const transaction = db.transaction(['users'], 'readwrite');
    
    // Get the object store
    const store = transaction.objectStore('users');
    
    // Add the user
    const request = store.add(user);
    
    // Handle success
    request.onsuccess = (event) => {
        console.log('User added with ID:', event.target.result);
    };
    
    // Handle error
    request.onerror = (event) => {
        console.error('Error adding user:', event.target.error);
    };
}

// Function to get a user by ID
function getUserById(db, id) {
    const transaction = db.transaction(['users'], 'readonly');
    const store = transaction.objectStore('users');
    const request = store.get(id);
    
    request.onsuccess = (event) => {
        if (request.result) {
            console.log('User found:', request.result);
        } else {
            console.log('User not found');
        }
    };
}

// Function to get a user by email
function getUserByEmail(db, email) {
    const transaction = db.transaction(['users'], 'readonly');
    const store = transaction.objectStore('users');
    const index = store.index('email');
    const request = index.get(email);
    
    request.onsuccess = (event) => {
        if (request.result) {
            console.log('User found by email:', request.result);
        } else {
            console.log('User not found');
        }
    };
}

Intersection Observer API

The Intersection Observer API provides a way to asynchronously observe changes in the intersection of a target element with an ancestor element or with the viewport.

// Create an intersection observer
const observer = new IntersectionObserver((entries, observer) => {
    entries.forEach(entry => {
        // Check if the element is intersecting
        if (entry.isIntersecting) {
            console.log('Element is visible:', entry.target);
            
            // Do something with the visible element
            entry.target.classList.add('visible');
            
            // Load images lazily
            if (entry.target.dataset.src) {
                entry.target.src = entry.target.dataset.src;
                entry.target.removeAttribute('data-src');
            }
            
            // Optionally stop observing the element
            // observer.unobserve(entry.target);
        } else {
            console.log('Element is not visible:', entry.target);
            entry.target.classList.remove('visible');
        }
    });
}, {
    // Options
    root: null, // Use the viewport as the root
    rootMargin: '0px', // No margin
    threshold: 0.1 // Trigger when 10% of the element is visible
});

// Observe elements
document.querySelectorAll('.observe-me').forEach(element => {
    observer.observe(element);
});

// Example of lazy loading images
document.querySelectorAll('img[data-src]').forEach(img => {
    observer.observe(img);
});

Web Workers API

Web Workers allow you to run JavaScript in background threads, separate from the main execution thread of a web application.

// Main script (main.js)
// Create a worker
const worker = new Worker('worker.js');

// Send message to worker
worker.postMessage({
    command: 'calculate',
    data: { numbers: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] }
});

// Receive message from worker
worker.onmessage = (event) => {
    console.log('Result from worker:', event.data);
    
    // Update UI with the result
    document.getElementById('result').textContent = event.data.result;
};

// Handle errors
worker.onerror = (error) => {
    console.error('Worker error:', error.message);
};

// Terminate worker when done
function terminateWorker() {
    worker.terminate();
    console.log('Worker terminated');
}

// Worker script (worker.js)
// Listen for messages from the main script
self.onmessage = (event) => {
    console.log('Message received in worker:', event.data);
    
    const { command, data } = event.data;
    
    if (command === 'calculate') {
        // Perform CPU-intensive calculation
        const result = calculateSum(data.numbers);
        
        // Send result back to main script
        self.postMessage({ result });
    }
};

// CPU-intensive function
function calculateSum(numbers) {
    // Simulate a complex calculation
    let sum = 0;
    for (let i = 0; i < 1000000000; i++) {
        sum += i % 10;
    }
    
    // Calculate the actual sum
    const actualSum = numbers.reduce((total, num) => total + num, 0);
    
    return actualSum;
}

Service Workers API

Service Workers act as proxy servers that sit between web applications, the browser, and the network. They enable features like offline support, background sync, and push notifications.

// Register a service worker (main.js)
if ('serviceWorker' in navigator) {
    window.addEventListener('load', () => {
        navigator.serviceWorker.register('/service-worker.js')
            .then(registration => {
                console.log('Service Worker registered with scope:', registration.scope);
            })
            .catch(error => {
                console.error('Service Worker registration failed:', error);
            });
    });
}

// Service Worker script (service-worker.js)
const CACHE_NAME = 'my-site-cache-v1';
const urlsToCache = [
    '/',
    '/index.html',
    '/styles/main.css',
    '/scripts/main.js',
    '/images/logo.png'
];

// Install event - cache assets
self.addEventListener('install', event => {
    event.waitUntil(
        caches.open(CACHE_NAME)
            .then(cache => {
                console.log('Opened cache');
                return cache.addAll(urlsToCache);
            })
    );
});

// Activate event - clean up old caches
self.addEventListener('activate', event => {
    const cacheWhitelist = [CACHE_NAME];
    
    event.waitUntil(
        caches.keys().then(cacheNames => {
            return Promise.all(
                cacheNames.map(cacheName => {
                    if (cacheWhitelist.indexOf(cacheName) === -1) {
                        return caches.delete(cacheName);
                    }
                })
            );
        })
    );
});

// Fetch event - serve from cache or network
self.addEventListener('fetch', event => {
    event.respondWith(
        caches.match(event.request)
            .then(response => {
                // Cache hit - return response
                if (response) {
                    return response;
                }
                
                // Clone the request
                const fetchRequest = event.request.clone();
                
                return fetch(fetchRequest).then(response => {
                    // Check if valid response
                    if (!response || response.status !== 200 || response.type !== 'basic') {
                        return response;
                    }
                    
                    // Clone the response
                    const responseToCache = response.clone();
                    
                    caches.open(CACHE_NAME)
                        .then(cache => {
                            cache.put(event.request, responseToCache);
                        });
                    
                    return response;
                });
            })
    );
});

Performance Optimization

Optimizing the performance of your HTML documents is crucial for providing a good user experience.

Resource Hints

Resource hints allow you to inform the browser about resources that will be needed in the future, enabling it to prepare accordingly.

<!-- Preconnect to important third-party origins -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://analytics.example.com" crossorigin>

<!-- Prefetch resources likely to be needed for the next page -->
<link rel="prefetch" href="/next-page.html">
<link rel="prefetch" href="/images/hero-next.jpg">

<!-- Preload critical resources for the current page -->
<link rel="preload" href="/fonts/webfont.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/css/critical.css" as="style">
<link rel="preload" href="/js/critical.js" as="script">

<!-- DNS prefetch (older, less powerful version of preconnect) -->
<link rel="dns-prefetch" href="https://api.example.com">

<!-- Prerender a page that's very likely to be visited next -->
<link rel="prerender" href="/very-likely-next-page.html">

Lazy Loading

Lazy loading defers the loading of non-critical resources until they are needed, improving initial page load performance.

<!-- Native lazy loading for images -->
<img src="image.jpg" alt="Description" loading="lazy">

<!-- Native lazy loading for iframes -->
<iframe src="video-player.html" loading="lazy"></iframe>

<!-- Custom lazy loading with data attributes and Intersection Observer -->
<img data-src="large-image.jpg" alt="Description" class="lazy-image">

<script>
    // Set up Intersection Observer for custom lazy loading
    const lazyImageObserver = new IntersectionObserver((entries, observer) => {
        entries.forEach(entry => {
            if (entry.isIntersecting) {
                const lazyImage = entry.target;
                lazyImage.src = lazyImage.dataset.src;
                lazyImage.classList.remove('lazy-image');
                observer.unobserve(lazyImage);
            }
        });
    });
    
    // Observe all lazy images
    document.querySelectorAll('.lazy-image').forEach(image => {
        lazyImageObserver.observe(image);
    });
</script>

Responsive Images

Responsive images ensure that users download appropriately sized images for their device, saving bandwidth and improving load times.

<!-- Using srcset for different resolutions -->
<img src="image-400w.jpg"
     srcset="image-400w.jpg 400w,
             image-800w.jpg 800w,
             image-1200w.jpg 1200w"
     sizes="(max-width: 600px) 100vw,
            (max-width: 1200px) 50vw,
            33vw"
     alt="Responsive image">

<!-- Using picture element for art direction -->
<picture>
    <source media="(max-width: 600px)" srcset="image-mobile.jpg">
    <source media="(max-width: 1200px)" srcset="image-tablet.jpg">
    <img src="image-desktop.jpg" alt="Art-directed responsive image">
</picture>

<!-- Using picture for different image formats -->
<picture>
    <source type="image/webp" srcset="image.webp">
    <source type="image/jpeg" srcset="image.jpg">
    <img src="image.jpg" alt="Format-responsive image">
</picture>

Critical CSS

Critical CSS is the practice of inlining the CSS required for above-the-fold content, allowing the page to render quickly while the rest of the CSS loads asynchronously.

<!-- Inline critical CSS -->
<style>
    /* Critical CSS for above-the-fold content */
    body { margin: 0; font-family: sans-serif; }
    header { background-color: #333; color: white; padding: 1rem; }
    .hero { height: 50vh; background-color: #f0f0f0; display: flex; align-items: center; justify-content: center; }
    /* ... other critical styles ... */
</style>

<!-- Load non-critical CSS asynchronously -->
<link rel="preload" href="styles.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="styles.css"></noscript>

Script Loading Strategies

How you load JavaScript can significantly impact page performance.

<!-- Defer non-critical scripts -->
<script src="non-critical.js" defer></script>

<!-- Async for scripts that don't depend on DOM or other scripts -->
<script src="analytics.js" async></script>

<!-- Module scripts are deferred by default -->
<script type="module" src="app.js"></script>

<!-- Inline critical JavaScript -->
<script>
    // Critical initialization code
    document.addEventListener('DOMContentLoaded', () => {
        // Initialize critical functionality
    });
</script>

<!-- Load non-critical scripts dynamically -->
<script>
    // Load script after page load
    window.addEventListener('load', () => {
        const script = document.createElement('script');
        script.src = 'non-critical-feature.js';
        document.body.appendChild(script);
    });
</script>

Content Delivery Networks (CDNs)

Using CDNs can significantly improve load times by serving assets from servers closer to the user.

<!-- Using a CDN for libraries -->
<link rel="stylesheet" href="https://cdn.example.com/bootstrap/5.0.2/css/bootstrap.min.css">
<script src="https://cdn.example.com/jquery/3.6.0/jquery.min.js"></script>

<!-- Using a CDN for your own assets -->
<img src="https://cdn.yourdomain.com/images/hero.jpg" alt="Hero image">
<script src="https://cdn.yourdomain.com/js/app.min.js"></script>

Performance Measurement

Measuring performance is essential for identifying bottlenecks and verifying improvements.

<!-- Server Timing header for backend performance metrics -->
<script>
    // Access Server-Timing metrics
    if (performance.getEntriesByType) {
        const serverTiming = performance.getEntriesByType('navigation')[0].serverTiming;
        if (serverTiming) {
            serverTiming.forEach(timing => {
                console.log(`${timing.name}: ${timing.duration}ms - ${timing.description}`);
            });
        }
    }
    
    // Performance marks and measures
    performance.mark('start-process');
    
    // Do some work...
    
    performance.mark('end-process');
    performance.measure('process-time', 'start-process', 'end-process');
    
    // Log the measurement
    const measures = performance.getEntriesByName('process-time');
    console.log(`Process took ${measures[0].duration}ms`);
    
    // Web Vitals reporting
    window.addEventListener('load', () => {
        // Report Core Web Vitals
        if ('web-vitals' in window) {
            webVitals.getCLS(console.log); // Cumulative Layout Shift
            webVitals.getFID(console.log); // First Input Delay
            webVitals.getLCP(console.log); // Largest Contentful Paint
            webVitals.getFCP(console.log); // First Contentful Paint
            webVitals.getTTFB(console.log); // Time to First Byte
        }
    });
</script>

SEO Best Practices

Search Engine Optimization (SEO) is the practice of improving your website to increase its visibility in search engine results.

Semantic HTML for SEO

Using semantic HTML helps search engines understand the structure and content of your pages.

<!-- Use semantic elements -->
<header>
    <h1>Main Page Title</h1>
</header>

<nav>
    <!-- Navigation links -->
</nav>

<main>
    <article>
        <h2>Article Title</h2>
        <p>Article content...</p>
        
        <section>
            <h3>Section Title</h3>
            <p>Section content...</p>
        </section>
    </article>
    
    <aside>
        <h3>Related Content</h3>
        <!-- Related content -->
    </aside>
</main>

<footer>
    <!-- Footer content -->
</footer>

Meta Tags for SEO

Meta tags provide information about your page to search engines and social media platforms.

<!-- Essential meta tags -->
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Page Title | Site Name</title>
<meta name="description" content="A concise and compelling description of the page content (150-160 characters).">

<!-- Canonical URL -->
<link rel="canonical" href="https://example.com/page-url">

<!-- Language -->
<html lang="en">

<!-- Open Graph meta tags for social sharing -->
<meta property="og:title" content="Page Title">
<meta property="og:description" content="A description for social media sharing.">
<meta property="og:image" content="https://example.com/image.jpg">
<meta property="og:url" content="https://example.com/page-url">
<meta property="og:type" content="website">

<!-- Twitter Card meta tags -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="Page Title">
<meta name="twitter:description" content="A description for Twitter sharing.">
<meta name="twitter:image" content="https://example.com/image.jpg">

<!-- Robots meta tag -->
<meta name="robots" content="index, follow">
<!-- Or to prevent indexing: -->
<meta name="robots" content="noindex, nofollow">

Structured Data

Structured data helps search engines understand the content of your page and can enable rich results in search engine results pages (SERPs).

<!-- JSON-LD for a product page -->
<script type="application/ld+json">
{
    "@context": "https://schema.org",
    "@type": "Product",
    "name": "Executive Leather Chair",
    "image": "https://example.com/chair.jpg",
    "description": "A comfortable executive leather chair for your office.",
    "brand": {
        "@type": "Brand",
        "name": "OfficeBrand"
    },
    "offers": {
        "@type": "Offer",
        "price": "199.99",
        "priceCurrency": "USD",
        "availability": "https://schema.org/InStock"
    },
    "aggregateRating": {
        "@type": "AggregateRating",
        "ratingValue": "4.8",
        "reviewCount": "89"
    }
}
</script>

<!-- JSON-LD for an article -->
<script type="application/ld+json">
{
    "@context": "https://schema.org",
    "@type": "Article",
    "headline": "Article Title",
    "image": "https://example.com/article-image.jpg",
    "datePublished": "2025-03-15T08:00:00+08:00",
    "dateModified": "2025-03-16T09:20:00+08:00",
    "author": {
        "@type": "Person",
        "name": "John Doe"
    },
    "publisher": {
        "@type": "Organization",
        "name": "Example Publication",
        "logo": {
            "@type": "ImageObject",
            "url": "https://example.com/logo.png"
        }
    },
    "description": "A brief description of the article content."
}
</script>

Image Optimization for SEO

Properly optimized images improve both user experience and SEO.

<!-- Well-optimized image -->
<img src="office-chair.jpg" 
     alt="Executive Leather Office Chair with Ergonomic Design" 
     width="800" 
     height="600" 
     loading="lazy">

<!-- Image with caption -->
<figure>
    <img src="office-chair.jpg" 
         alt="Executive Leather Office Chair" 
         width="800" 
         height="600">
    <figcaption>Our best-selling executive leather office chair with ergonomic design</figcaption>
</figure>

URL Structure

Clean, descriptive URLs are better for both users and search engines.

<!-- Good URL structure examples -->

<!-- Category page -->
<a href="https://example.com/office-furniture/">Office Furniture</a>

<!-- Product page -->
<a href="https://example.com/office-furniture/chairs/executive-leather-chair">Executive Leather Chair</a>

<!-- Blog post -->
<a href="https://example.com/blog/2025/03/ergonomic-office-setup-guide">Ergonomic Office Setup Guide</a>

Internal Linking

Proper internal linking helps search engines discover and understand the structure of your website.

<!-- Descriptive anchor text -->
<p>Learn more about <a href="/ergonomic-chairs">ergonomic office chairs</a> and how they can improve your posture.</p>

<!-- Breadcrumb navigation -->
<nav aria-label="Breadcrumb">
    <ol itemscope itemtype="https://schema.org/BreadcrumbList">
        <li itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem">
            <a itemprop="item" href="/">
                <span itemprop="name">Home</span>
            </a>
            <meta itemprop="position" content="1" />
        </li>
        <li itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem">
            <a itemprop="item" href="/office-furniture/">
                <span itemprop="name">Office Furniture</span>
            </a>
            <meta itemprop="position" content="2" />
        </li>
        <li itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem">
            <a itemprop="item" href="/office-furniture/chairs/">
                <span itemprop="name">Chairs</span>
            </a>
            <meta itemprop="position" content="3" />
        </li>
        <li itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem">
            <span itemprop="name">Executive Leather Chair</span>
            <meta itemprop="position" content="4" />
        </li>
    </ol>
</nav>

Mobile-Friendly Design

Mobile-friendliness is a ranking factor for search engines.

<!-- Responsive viewport meta tag -->
<meta name="viewport" content="width=device-width, initial-scale=1.0">

<!-- Responsive design with media queries -->
<style>
    /* Base styles for mobile devices */
    .container {
        width: 100%;
        padding: 15px;
    }
    
    /* Styles for tablets and larger */
    @media (min-width: 768px) {
        .container {
            width: 750px;
            margin: 0 auto;
        }
    }
    
    /* Styles for desktops */
    @media (min-width: 1024px) {
        .container {
            width: 980px;
        }
    }
</style>

Practice Exercises

Now that you've learned advanced HTML concepts, it's time to practice! Here are some exercises to help you reinforce what you've learned.

Exercise 1: Create a Semantic Blog Layout

Create a blog layout using semantic HTML elements and structured data:

  • Use appropriate semantic elements for the header, navigation, main content, sidebar, and footer
  • Include a blog post with proper heading hierarchy
  • Add structured data using JSON-LD for the blog post
  • Implement breadcrumb navigation
  • Ensure the layout is accessible with proper ARIA attributes where needed

Exercise 2: Build an Accessible Form

Create a multi-step form with advanced features:

  • Use appropriate input types and validation attributes
  • Implement custom validation with JavaScript
  • Add ARIA attributes for accessibility
  • Create a progress indicator for the multi-step process
  • Implement client-side form storage using localStorage

Exercise 3: Create a Custom Web Component

Build a reusable web component:

  • Create a custom element that extends HTMLElement
  • Use shadow DOM for encapsulation
  • Implement lifecycle callbacks
  • Add custom events
  • Make the component accessible with ARIA attributes

Exercise 4: Implement a Service Worker

Add offline capabilities to a website:

  • Register a service worker
  • Cache essential resources for offline use
  • Implement a fallback page for when the user is offline
  • Add background sync for form submissions
  • Implement a cache-first strategy for static assets

Exercise 5: Optimize a Web Page

Improve the performance of a web page:

  • Implement resource hints (preconnect, preload, prefetch)
  • Add lazy loading for images and iframes
  • Implement responsive images with srcset and sizes
  • Optimize script loading with async and defer
  • Add performance measurement using the Performance API

Next Steps

Now that you've mastered advanced HTML concepts, you can continue your learning journey with: