Posts

Showing posts with the label Cappie

From Zero to Hero A Walkthrough of the Jekyll Directory for GitHub Pages Beginners

If you're a beginner, a Jekyll project folder might seem a little intimidating at first. You'll see a mix of files and folders, some with underscores and some without, and it's not immediately obvious what each one does. This guide is a step-by-step walkthrough designed to take you from a complete beginner to someone who confidently understands the Jekyll directory structure. We will break down each key file and folder, explaining its role in a simple and straightforward way. By the time you're done, you'll know exactly where to put your content, how to change your site's settings, and where to find your website's templates. This foundational knowledge is all you need to start building your own website on GitHub Pages and move from zero to hero.

Table of Contents

Your First Steps with Jekyll

Jekyll is an incredibly powerful tool because it automates much of the website creation process. It knows how to take your raw content and templates and turn them into a complete, static website. This is made possible by its predictable directory structure. You don't have to tell Jekyll where your blog posts are; it knows to look in the _posts folder. You don't have to specify where your templates are; it knows they're in the _layouts folder. Learning this system is the most efficient way to get up and running, so let's start with the files you'll see as soon as you open your project folder.


The Root Directory What You See First

The _config.yml File Your Sites Settings

When you look inside your Jekyll project, the most important file you will see at the top level is **_config.yml**. This is your site's main settings file, written in YAML. It’s where you define all the global information about your website, such as the title, description, and author. You also use this file to set your website's base URL, which is very important for GitHub Pages, and to configure your post's URL structure (permalinks). Any change you make here will apply to your entire site. For a beginner, this is the first place to look when you want to change your site's name or other core information.

This file is also where you tell Jekyll which plugins to use and which files or folders to ignore. For example, if you want Jekyll to ignore a folder of images you're not ready to use yet, you can add its name to the exclude list in this file. The _config.yml file is the single source of truth for your site’s behavior, making it a critical file to understand from the very beginning.

Posts, Pages, and index.md

In Jekyll, content is divided into two main categories: posts and pages. Pages are for static, standalone content like your home page, an "About" page, or a "Contact" page. You create a page by simply placing a Markdown or HTML file directly in the root directory. For example, your home page is typically named index.md or index.html. An "About" page could be about.md. When you build your site, these files become pages at the corresponding URLs, like /about/.

Posts, on the other hand, are for chronological content, like blog articles. All of your posts must be placed inside the **_posts** directory. These files must be named using a specific format: YYYY-MM-DD-your-post-title.md. This naming convention is not just for organization; it's how Jekyll knows the date of your post and what to name its URL. By keeping your blog articles in this separate folder, you keep your main directory clean and make it easy for Jekyll to handle your content automatically.


The Special Folders for Design and Structure

_layouts Your Site's Templates

How does your content get its final look? That's the job of the **_layouts** folder. This directory contains all the HTML templates for your website. Think of a layout as a blueprint for a page. You might have a default.html file that contains the common HTML for your header, navigation, and footer. Then, you might have a post.html file that uses the default.html layout but adds a special sidebar or comment section for blog posts. By using layouts, you avoid repeating the same HTML on every single page. Instead, you just tell a page or post which layout to use in its YAML front matter, and Jekyll does the rest.

This system is a great way to ensure consistency across your entire site. If you decide to change your site's navigation, you only have to edit the code in one place—the layout file—and the change will appear on every page that uses that layout. This is a fundamental concept for building a professional and maintainable website.

_includes Reusable Code Snippets

The **_includes** folder is like your personal toolbox of HTML components. This is where you put small, reusable snippets of code that you want to use across multiple layouts or pages. Common examples include a footer, a social media icon block, or a navigation bar. By placing these snippets in a file inside the _includes directory, you can then add them to a layout using a simple Liquid tag, like {% include footer.html %}. This keeps your code clean and organized. When you need to make an update, you just change the file in _includes, and the change automatically appears everywhere that snippet is used.

This folder is a fantastic resource for beginners because it helps you start thinking about modular design. Instead of writing the same code over and over again, you can create a single component and reuse it wherever you need it, making your site more efficient and easier to manage.

Assets for Images and Styles

When you're building a website, you will need images, CSS stylesheets, and JavaScript files. For these, it's a best practice to create a folder at the root of your project, often named **assets**. Inside, you can create subfolders for css, js, and images. Any file that does not start with an underscore is considered a static asset, and Jekyll will simply copy it directly to the final website without processing it. This means you can link to your files using a simple path. For example, your stylesheet might be located at /assets/css/style.css. This approach keeps your project organized and prevents your root directory from becoming cluttered with unrelated files.


Building and Publishing Your Site

Once you've added your content and set up your templates, you'll need to "build" your site. This is when Jekyll takes all of your source files and compiles them into a complete, ready-to-publish website in a new directory named **_site**. This folder contains all the static HTML, CSS, and images that a web browser needs. It is the folder that gets deployed to GitHub Pages. It's very important to know that you should never edit files inside the _site folder. It is a temporary output directory that is deleted and rebuilt every time you run the build command. To make sure you don't accidentally commit it to your Git repository, it's a great habit to add _site/ to your .gitignore file.

How to keep dark mode fast

Why performance matters for dark mode

Dark mode should feel instant and unobtrusive. If toggling theme adds measurable delay, causes layout shifts, or increases page load time, users perceive the site as sluggish and unreliable. For Mediumish — a content-first theme — readers expect fast rendering and smooth interactions. A slow dark mode can lead to higher bounce rates, poorer user engagement, and lower perceived quality.

Performance matters not only for UX but also for SEO: slower pages often score lower on Core Web Vitals and search rankings. The goal is to add dark mode while keeping initial paint, interaction readiness, and cumulative layout shift (CLS) under control.

Common performance pitfalls

Before implementing optimizations, know where slowdowns usually come from:

  • Large or blocking CSS: Loading big stylesheets that must be parsed before paint.
  • Late theme detection: Relying on full JS bundles to decide theme, causing flash of wrong theme or delayed switch.
  • Multiple large image assets: Serving extra files for dark mode without lazy loading or optimized formats.
  • Heavy JavaScript toggles: Running expensive DOM operations when toggling theme.
  • Unnecessary repaints or reflows: Triggering style changes in ways that force layout recalculation for many elements.

Critical CSS strategy

Keep the initial CSS minimal and critical for above-the-fold content. This reduces time to first meaningful paint and lets users see a usable page quickly.

Steps to apply:

  1. Extract a small critical CSS chunk that covers body background, typography, header, and the toggle control. Inline it in the document head to avoid a render-blocking request.
  2. Place the CSS variables and the minimal theme-related styles in that inline critical CSS so the correct colors can apply immediately.
  3. Load the full stylesheet asynchronously (for example, using rel="preload" as="style" onload="this.rel='stylesheet'"), ensuring the page becomes functional while full styles load in the background.
<style>
/* Critical styles only */
:root{ --bg:#fff; --text:#111; }
:root[data-theme="dark"]{ --bg:#0b0f12; --text:#e6eef8; }
html,body{ background:var(--bg); color:var(--text); }
</style>

<link rel="preload" href="/css/main.css" as="style" onload="this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="/css/main.css"></noscript>

Fast theme detection and FOIT prevention

To avoid flash of wrong theme and keep paint fast, run a tiny synchronous script at the top of the head that reads the saved preference and sets a data-theme attribute before the browser paints.

Keep this script under ~1 KB. It should not import external code or rely on frameworks. The goal is to set the theme attribute so CSS variables apply immediately.

<script>(function(){
try{
  var t=localStorage.getItem('site-theme-preference');
  if(t){ document.documentElement.setAttribute('data-theme', t); }
  else if(window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches){
    document.documentElement.setAttribute('data-theme','dark');
  }
}catch(e){};})();</script>

This tiny script prevents layout jank and removes the need for heavier JS to run before paint.

Minimizing assets and safe swapping

Avoid loading duplicate or heavy assets for dark mode unless necessary. When you must swap assets (icons, logos, illustrations), do it efficiently:

  • Prefer SVG icons with CSS-controlled fills so a single file adapts to both themes without swapping.
  • For raster images that need replacements, lazy-load the alternate asset only when theme changes and the image is visible in the viewport.
  • Use modern image formats (WebP, AVIF) and provide properly sized sources via srcset to reduce bytes.
<img src="/img/logo-light.svg" data-dark="/img/logo-dark.svg" class="theme-aware" alt="Site logo">

<script>
document.addEventListener('DOMContentLoaded',function(){
  var imgs=document.querySelectorAll('img.theme-aware');
  imgs.forEach(function(img){
    var dark=img.getAttribute('data-dark');
    if(document.documentElement.getAttribute('data-theme')==='dark' && dark){
      img.src=dark;
    }
  });
});
</script>

Note: the script above is intentionally small; only swap visible elements and avoid bulk DOM writes.

Efficient JavaScript patterns

When toggling theme, follow patterns that minimize work and avoid forcing synchronous layout calculations.

  • Toggle a single attribute: Set data-theme on document.documentElement rather than toggling many class names. CSS will cascade efficiently.
  • Batch DOM writes: If you must update multiple elements, perform writes separately from reads to avoid layout thrashing.
  • Avoid expensive selectors: Use variables and simple selectors in CSS so repaint cost is lower when theme changes.
  • Debounce non-critical work: If toggling triggers analytics or heavy sync, defer those tasks using requestIdleCallback or setTimeout.
// Efficient toggle example
function setTheme(t){
  document.documentElement.setAttribute('data-theme', t);
  try{ localStorage.setItem('site-theme-preference', t); }catch(e){}
  // defer analytics or heavy tasks
  if('requestIdleCallback' in window){
    requestIdleCallback(function(){ /* send analytics */ });
  } else { setTimeout(function(){ /* send analytics */ }, 200); }
}

Image and media optimizations

Images often dominate bytes on content sites. Optimize them carefully for dark mode:

  • Compress and convert to WebP/AVIF where supported.
  • Use loading="lazy" for below-the-fold images.
  • Prefer CSS filters for minor adjustments rather than loading full alternate assets.
  • Use vector graphics (SVG) for icons and UI elements so they adapt without extra payload.

Testing and measuring performance

Measure before and after changes. Useful tools and metrics:

  • Lighthouse: Check performance score and Core Web Vitals.
  • WebPageTest: Analyze first paint, speed index, and visual progress.
  • Chrome DevTools: Throttle CPU/network to simulate slower devices and observe theme toggling behavior.
  • Real User Monitoring (RUM): Collect data from actual visitors to see real-world impact.

Key metrics to watch when adding dark mode:

  • First Contentful Paint (FCP)
  • Largest Contentful Paint (LCP)
  • Cumulative Layout Shift (CLS)
  • Time to Interactive (TTI)

Quick production checklist

ItemStatus
Inline critical CSS with variables
Tiny head script for fast theme detection
Preload main stylesheet
Use SVGs and CSS for icons
Lazy-load dark-mode-only assets
Batch DOM writes on toggle
Test on slow CPU/network
Monitor RUM metrics post-launch

FAQ

Q: Will dark mode always add extra bytes?

A: Not necessarily. If you use CSS variables and SVGs, dark mode can be mostly zero-byte from an asset perspective. Extra bytes come from alternate images or larger CSS, so optimize to avoid that.

Q: Is inlining CSS safe for caching?

A: Inline critical CSS helps first paint. Keep it minimal; larger CSS should still be cached as external files using preload and proper cache headers.

Q: Should I always swap images for dark mode?

A: Only when necessary. Prefer adaptive SVGs or subtle CSS filters to avoid extra network requests and complexity.