Build a Blog from Scratch
Build a Blog from Scratch: Vanilla JavaScript Tutorial
Master web fundamentals by building a complete blog with pure HTML, CSS, and JavaScriptโno frameworks needed. This tutorial teaches core web development concepts including DOM manipulation, local storage, and dynamic content rendering. Perfect for beginners learning JavaScript or developers wanting to understand what frameworks do under the hood.
What You'll Build
- Fully functional blog with posts and categories
- Dynamic content loading with vanilla JavaScript
- Local storage for data persistence
- Responsive design with pure CSS
- Markdown-like formatting for posts
- Search and filter functionality
Core Web Development Skills You'll Learn
- DOM Manipulation: Create, read, update, delete elements with JavaScript
- Event Handling: User interactions without jQuery
- Local Storage API: Client-side data persistence
- CSS Flexbox & Grid: Modern responsive layouts
- JavaScript Modules: Organize code without build tools
- Template Literals: Dynamic HTML generation
- Array Methods: Filter, map, and reduce for data manipulation
Prerequisites
- Basic HTML knowledge (tags, attributes, structure)
- CSS fundamentals (selectors, properties, box model)
- JavaScript basics (variables, functions, conditionals)
- Code editor (VS Code recommended)
- Modern web browser with developer tools
Time Commitment: 4-6 hours. Perfect weekend project to solidify your JavaScript fundamentals.
Why Learn Vanilla JavaScript?
Before reaching for React, Vue, or Angular, understanding vanilla JavaScript is crucial. Frameworks come and go, but core JavaScript skills remain valuable. Building without frameworks teaches you how the web actually worksโDOM APIs, event loops, and browser capabilities. This knowledge makes you a better developer regardless of which framework you eventually use.
This tutorial focuses on modern JavaScript (ES6+) features and best practices. You'll write clean, maintainable code that runs directly in the browserโno build step, no dependencies, just pure web development. Learn more about modern JavaScript features.
Build a Blog from Scratch
Build a blog the old-school way with pure HTML, CSS, and vanilla JavaScript - no frameworks, no dependencies, no complexity. This approach strips away all the abstractions to reveal the fundamental web technologies that power everything. You will gain deep understanding of the DOM, CSS layouts, event handling, and client-side storage while creating a fully functional blog. Perfect for learning the foundations, understanding what frameworks do under the hood, or when you need a lightweight solution that loads instantly and runs anywhere without a build step.
Web Development Blog Setup: Installation and Project Configuration
Create project folder structure
Create a well-organized folder structure for a vanilla HTML/CSS/JavaScript blog Set up the following directories: root directory with index.html, /css for stylesheets (style.css, reset.css), /js for JavaScript files (main.js, posts.js, utils.js), /data for blog post data (posts.json), /assets for images (images/, icons/), and /posts for individual post HTML pages Initialize a git repository with git init and create a .gitignore file Add a README.md with project description and setup instructions.
Configure VS Code with Live Server
Configure VS Code for efficient vanilla web development Install the Live Server extension by Ritwick Dey for hot-reloading during development Add Prettier extension for code formatting and ESLint for JavaScript linting Create .vscode/settings.json with formatting preferences (2-space indent, single quotes for JS, format on save enabled) Install additional helpful extensions: HTML CSS Support, JavaScript (ES6) code snippets, Path Intellisense, and Auto Rename Tag Configure Live Server settings to open on port 5500 and auto-refresh on file changes.
Create semantic HTML layout
Build a semantic HTML5 structure in index.html Include proper doctype, html lang attribute, head section with meta charset UTF-8, viewport meta tag for responsiveness, title tag, and links to CSS files Create semantic structure with <header> containing site logo and navigation <nav>, <main> with <section> for blog post listing, <aside> for sidebar (categories, recent posts, search), and <footer> with copyright and social links Use semantic tags like <article> for blog posts, <time> for dates, <h1>-<h6> for headings hierarchy Add proper ARIA labels for accessibility Include meta tags for SEO (description, keywords, author).
Database and Environment Configuration for Web Development
Vanilla CSS or Tailwind CDN
Choose between vanilla CSS or Tailwind CSS for styling For vanilla CSS: create css/reset.css with CSS reset (normalize.css or custom reset), then css/style.css with CSS custom properties for colors, fonts, spacing, and breakpoints Organize CSS with sections: global styles, typography, layout (header, nav, main, footer), components (cards, buttons, forms), and utilities For Tailwind: add Tailwind CDN link in HTML head: <script src="https://cdn.tailwindcss.com"></script>, configure custom theme in a <script> tag if needed Implement a mobile-first approach with clear responsive breakpoints. Choose a readable font stack with web-safe fallbacks (e.g., system-ui, -apple-system, "Segoe UI", Roboto, sans-serif).
Set up ES6 modules structure
Set up a modular JavaScript architecture using ES6 modules Create js/main.js as the entry point with type="module" in the script tag Build js/posts.js module for post-related functions (fetchPosts, renderPostList, renderSinglePost, filterPostsByCategory, sortPostsByDate) Create js/utils.js for utility functions (formatDate, truncateText, slugify, escapeHTML, debounce) Use export/import syntax to organize code Implement async/await for data fetching Add error handling with try/catch blocks Set up event delegation for dynamic content Include comments and JSDoc annotations for better code documentation Ensure compatibility with modern browsers (ES6+).
Choose JSON file or localStorage
Choose and implement a data storage solution for blog posts. Option 1 (JSON file): Create data/posts.json with an array of post objects, each containing id, title, slug, author, date (ISO format), excerpt, content (markdown or HTML), category, tags, and featuredImage. Fetch data using fetch() API in JavaScript. Option 2 (localStorage): Store posts in localStorage with a "blogPosts" key, implement functions to addPost(), getPost(id), getAllPosts(), updatePost(id), deletePost(id) For demo purposes, create a seed data script that populates initial posts. Structure each post with unique IDs, timestamps, and all necessary metadata Consider using both: JSON for initial data, localStorage for user preferences (theme, viewed posts, bookmarks).
Building Blog Features: Core Functionality and Admin Panel
Build header, main, footer sections
Build a complete page layout with header, main content, and footer. Header: Create a sticky/fixed navigation bar with site logo/title, navigation menu (Home, About, Categories, Contact), search input, and optional theme toggle (light/dark mode) Style the header with flexbox or grid for alignment. Main: Design the main content area with a blog post grid/list using CSS Grid (3 columns on desktop, 2 on tablet, 1 on mobile) or flexbox Each post card should display featured image, title, excerpt, author, date, category badge, and read more link Add hover effects with smooth transitions. Footer: Include copyright notice, social media icons (GitHub, Twitter, LinkedIn), navigation links, and optional newsletter signup Ensure all sections are responsive and maintain proper spacing with margin/padding.
Display posts dynamically with JavaScript
Implement dynamic blog post listing using JavaScript Create a renderPostList() function that fetches posts from data source, maps through the array, and generates HTML for each post card using template literals or createElement() Each card should display: thumbnail image with alt text, title, truncated excerpt (150-200 chars), author name, formatted date (e.g., "January 15, 2024"), category tags, and a "Read More" link with proper URL Add loading state (skeleton screens or spinner) while fetching data Implement pagination (10 posts per page) with previous/next buttons or infinite scroll Add filtering by category/tag with filter buttons that update the displayed posts Include a search functionality that filters posts by title or content in real-time Use CSS classes for styling and ensure smooth fade-in animations when posts load.
Create individual post pages
Create individual post pages at /posts/post-slug.html or implement a single-page application approach with URL parameters For separate HTML files: Generate a template with header, post container, and footer For SPA approach: Use URL hash (#post/slug) or query parameters (?post=slug) to identify posts, then dynamically render post content in the main element. Display full post with: large featured image, title in <h1>, author info with avatar, publication date, estimated reading time, full content with proper typography, category and tag badges, social share buttons (Twitter, Facebook, LinkedIn), and author bio section Add navigation links to previous/next posts Implement a "Back to Blog" button Handle 404 errors for non-existent posts Use meta tags to update page title and description for each post Add a comments section placeholder or integrate a third-party commenting system like Disqus or Facebook Comments.
Integrate marked.js or similar
Integrate a markdown parser to render blog post content from markdown format Add marked.js library via CDN in HTML: <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script> or install via npm Configure marked.js options: enable GFM (GitHub Flavored Markdown), sanitize HTML to prevent XSS attacks using DOMPurify (<script src="https://cdn.jsdelivr.net/npm/dompurify/dist/purify.min.js"></script>), set custom renderer for code blocks with syntax highlighting using Prism.js or highlight.js Store post content as markdown in posts.json, then convert to HTML when rendering: const html = DOMPurify.sanitize(marked.parse(markdownContent)) Style markdown elements in CSS: headings hierarchy, blockquotes with left border, code blocks with dark background and monospace font, inline code with light background, lists with proper indentation, links with hover effects, and images with max-width 100% for responsiveness Add copy button to code blocks for better UX.
Image Optimization & Lazy Loading
Implement image optimization and lazy loading for better performance.
Organize images in /assets/images/ directory with subdirectories for featured images, thumbnails, and inline content images.
Optimize all images before adding to project: compress images using tools like TinyPNG, ImageOptim, or Squoosh, convert large images to modern formats (WebP with JPG/PNG fallback), resize images to actual display size (no 4K images for 400px cards), aim for file sizes under 200KB for featured images, under 100KB for thumbnails.
Implement responsive images using srcset and sizes attributes: <img src="image-800.jpg" srcset="image-400.jpg 400w, image-800.jpg 800w, image-1200.jpg 1200w" sizes="(max-width: 600px) 400px, (max-width: 1000px) 800px, 1200px" alt="descriptive text" loading="lazy">.
Add native lazy loading to all images below the fold with loading="lazy" attribute for instant performance boost with zero JavaScript.
For featured images in posts.json: store multiple image sizes and formats: { "featuredImage": { "jpg": { "small": "/assets/images/post-1-400.jpg", "medium": "/assets/images/post-1-800.jpg", "large": "/assets/images/post-1-1200.jpg" }, "webp": { ... } } }.
Create a JavaScript utility function to generate responsive image HTML with proper srcset based on data structure.
Add CSS for image loading states: placeholder background color or blur-up effect using low-quality image placeholder (LQIP) technique.
Implement intersection observer for custom lazy loading if more control needed over loading behavior and animations.
For inline images in markdown: ensure marked.js outputs images with loading="lazy" by customizing the renderer.
Add proper alt text to all images for accessibility and SEO, use descriptive filenames for images (post-react-hooks-tutorial.jpg not IMG_1234.jpg).
Optional: implement an image lightbox/modal for viewing full-size images when clicked using vanilla JavaScript or a lightweight library like GLightbox.Make mobile-friendly with media queries
Implement comprehensive responsive design using CSS media queries and mobile-first approach Define breakpoints: mobile (320px-767px), tablet (768px-1023px), desktop (1024px+) For mobile: Stack layout vertically, hamburger menu for navigation (implement with JavaScript toggle), full-width post cards, larger touch-friendly buttons (min 44x44px), adjust font sizes (base 16px, scale down if needed) For tablet: 2-column grid for post listings, expanded navigation menu, adjust spacing and padding For desktop: 3-column grid, fixed sidebar, larger featured images, optimal line length for readability (60-80 characters) Use CSS techniques: flexbox with flex-wrap, CSS Grid with auto-fit/auto-fill, percentage-based widths, max-width for content containers (1200px), relative units (rem, em, %), clamp() for fluid typography Test with Chrome DevTools device emulation. Optimize images with srcset for different screen resolutions Ensure tap targets are large enough and text remains legible at all sizes Add viewport height units (vh) for full-screen sections where appropriate.
Testing Your Web Development Blog Application
Manual testing checklist
Create a comprehensive manual testing checklist document (TESTING.md or testing-checklist.html) Organize testing into categories: Functionality Testing (all links work, navigation menu functions, post filtering works, search returns correct results, pagination navigates correctly, theme toggle persists), Visual Testing (layout displays correctly on all devices, images load properly, fonts render correctly, colors match design, spacing and alignment are consistent, no content overflow), Browser Compatibility (test on Chrome, Firefox, Safari, Edge, check CSS Grid/Flexbox support, verify ES6 module support or add fallbacks), Performance Testing (page load time under 3 seconds, images are optimized, no console errors or warnings, smooth animations at 60fps), Accessibility Testing (keyboard navigation works, ARIA labels present, sufficient color contrast ratio 4.5:1, screen reader friendly, semantic HTML structure), SEO Testing (proper meta tags, descriptive alt text for images, semantic heading hierarchy, clean URLs) Create a spreadsheet or checklist template with pass/fail columns for each test case.
Test homepage loads and displays posts
Perform your first comprehensive test of the homepage Test that page loads successfully: index.html loads without errors in browser console, all CSS files load correctly (check Network tab), JavaScript files load without errors, page renders within 2-3 seconds Verify blog posts display: posts fetch from data source successfully, correct number of posts render on initial load (10 posts if paginated), each post card displays required fields (title, excerpt, image, date, author, category), images load with proper alt text, dates format correctly (human-readable), excerpt text truncates at correct length with ellipsis Test post card interactions: hover effects work smoothly, "Read More" links navigate to correct post pages, clicking category tags filters posts, all links are clickable with proper cursor Check for visual issues: layout is aligned correctly, no overlapping elements, consistent spacing between cards, responsive grid adjusts to viewport. Open browser DevTools console and verify no JavaScript errors Test with browser cache disabled to ensure fresh load performance.
Test on mobile, tablet, desktop
Conduct thorough responsive design testing across all device sizes Use Chrome DevTools Device Mode to test various screen sizes: Mobile (375x667 iPhone SE, 390x844 iPhone 12/13, 360x800 Galaxy S20), Tablet (768x1024 iPad, 820x1180 iPad Air), Desktop (1366x768, 1920x1080, 2560x1440) For mobile testing: verify hamburger menu icon appears and functions correctly (toggle open/close with smooth animation), test that menu closes when clicking outside or on a link, ensure post cards stack vertically in single column, check that images scale properly without stretching, verify touch targets are large enough (minimum 44x44px), test that no horizontal scrolling occurs, confirm font sizes are readable (minimum 16px for body text), test form inputs are easy to tap and use For tablet testing: verify 2-column post grid displays correctly, check navigation expands to full menu or remains as hamburger based on design, test portrait and landscape orientations, ensure sidebar adjusts or stacks appropriately For desktop testing: verify 3-column grid layout, test hover effects on interactive elements, ensure maximum content width is maintained (not too wide), verify fixed/sticky elements work correctly, test window resizing smoothly transitions between breakpoints Test on real devices if possible: iPhone, Android phone, iPad, various desktop browsers Check for visual issues: text overflow, image distortion, misaligned elements, broken layouts at breakpoint transitions Test landscape and portrait orientations on mobile/tablet Verify touch gestures (swipe, tap, scroll) work smoothly on touch devices.
Deploying Your Web Development Blog to Production
Deploy to GitHub Pages or Netlify
Deploy the vanilla HTML/CSS/JavaScript blog to a hosting platform For GitHub Pages: create GitHub repository, push code to main branch, go to repository Settings > Pages, select source branch (main) and root directory, save and wait for deployment (GitHub provides URL like username.github.io/repo-name), configure custom domain if available (add CNAME file) For Netlify: create account at netlify.com, drag and drop project folder for manual deploy OR connect GitHub repository for automatic deployments, configure build settings (none needed for vanilla sites), set publish directory to root or dist if using build tools, deploy site (Netlify provides random URL like random-name-123.netlify.app), configure custom domain in Netlify DNS settings, enable HTTPS (automatic with Netlify). Post-deployment checklist: test deployed site URL loads correctly, verify all pages are accessible, check that images and assets load (use absolute paths or root-relative paths, not relative paths like ./images/), test navigation works across all pages, verify fetch() requests work (ensure JSON data is accessible), check browser console for errors on live site, test on mobile device using live URL, verify SEO meta tags are present in page source, test social media sharing with proper Open Graph tags, add site to Google Search Console for SEO, create and submit sitemap.xml. Optional improvements: set up continuous deployment so git push automatically deploys, configure cache headers for performance, add analytics (Google Analytics or Plausible), set up form handling if contact form exists (Netlify Forms or Formspree).
