Greetings, brave artisan! Welcome to The Artisan’s Forge — an epic journey that will transform you from a coder who patches things together into a true component architect. This quest guides you through the real-world process of turning hard-coded, inline Jekyll theme elements into modular, configurable, and reusable components.
Whether you are a novice learning your first Liquid incantation or a seasoned theme-smith looking to sharpen your craft, this adventure will reward you with practical, production-tested knowledge.
In the ancient theme-forges of Zer0-Mistakes, a progress bar once lived hard-coded inside a layout — tangled in the markup like a vine choking a tower. And far below, a footer section was trapped inside container walls, unable to stretch its dark wings to the edges of the viewport. Two artisans, guided by an AI familiar, ventured into the codebase to reshape these elements. This quest retells their journey so that you may learn the craft yourself.
By the time you complete this quest, you will have mastered:
_includes/ component that reads its settings from _config.ymltop and bottom nanobar placement via configurationYou’ll know you’ve truly mastered this quest when you can:
!importantgraph TD
A[🏰 Start: Examine the Layout] --> B[🔍 Phase 1: Diagnose the Nanobar]
B --> C[⚒️ Phase 2: Extract the Include]
C --> D[🎨 Phase 3: Create the Stylesheet]
D --> E[⚙️ Phase 4: Wire Up Configuration]
E --> F[🔍 Phase 5: Diagnose the Footer]
F --> G[🛠️ Phase 6: Fix Full-Width Layout]
G --> H[✅ Phase 7: Validate Everything]
H --> I[🏆 Quest Complete!]
Before you can forge a new tool, you must understand the old one.
Open your theme’s main layout file (e.g., _layouts/default.html or _layouts/root.html). Look for a <div> with an inline <style> block that creates a thin progress bar — the nanobar.
Signs you’ve found it:
<style> tag inside the <body>, not in <head>position: fixed, height: 2px or 3px, a bright background-colorCreate a checklist of the nanobar’s behaviour:
🧙 Artisan’s Tip: Use your browser’s DevTools → Elements panel to inspect the nanobar in a running site. Right-click → Inspect is your fastest friend.
Now we move the code out of the layout and into its own file.
# Create the include file
touch _includes/components/nanobar.html
Move all the nanobar markup from the layout into this new file. The layout should now contain only:
{% include components/nanobar.html %}
Wrap the entire include in a config check so the nanobar only renders when enabled:
{% if site.nanobar.enabled %}
<div class="nanobar nanobar--{{ site.nanobar.position | default: 'top' }}"
role="progressbar"
aria-label="Reading progress"
aria-valuemin="0"
aria-valuemax="100"
aria-valuenow="0">
<div class="nanobar__bar"></div>
</div>
{% endif %}
Add a nanobar: block to _config.yml:
nanobar:
enabled: true
position: top # top | bottom
height: 3px
color: "#0d6efd" # Bootstrap primary blue
z_index: 1050
step_animation: false
🧙 Artisan’s Tip: Using
_config.ymlmeans site owners can customise the nanobar without touching any HTML or CSS — they only edit a YAML file.
Style belongs in stylesheets, not inline <style> tags.
mkdir -p _sass/components
touch _sass/components/_nanobar.scss
// _sass/components/_nanobar.scss
// Nanobar reading-progress indicator
// All selectors scoped under .nanobar to prevent leakage
.nanobar {
position: fixed;
left: 0;
width: 100%;
height: var(--nanobar-height, 3px);
background: transparent;
z-index: var(--nanobar-z-index, 1050);
pointer-events: none;
&--top { top: 0; }
&--bottom { bottom: 0; }
}
.nanobar__bar {
width: 0%;
height: 100%;
background: var(--nanobar-color, #0d6efd);
transition: width 0.2s ease-out;
}
Bridge your YAML config values into the stylesheet by setting CSS custom properties via a style attribute directly on the nanobar root element — keeping all CSS in the stylesheet where it belongs:
{% if site.nanobar.enabled %}
<div class="nanobar nanobar--{{ site.nanobar.position | default: 'top' }}"
role="progressbar"
aria-valuemin="0"
aria-valuemax="100"
aria-valuenow="0"
style="--nanobar-height: {{ site.nanobar.height | default: '3px' }}; --nanobar-color: {{ site.nanobar.color | default: '#0d6efd' }}; --nanobar-z-index: {{ site.nanobar.z_index | default: 1050 }};">
<div class="nanobar__bar"></div>
</div>
{% endif %}
🧙 Artisan’s Tip: Setting CSS custom properties on the component’s root element (not in a
<style>block) keeps all CSS rules in the stylesheet where they belong. Thestyleattribute only carries values, while the stylesheet owns the rules — no inline styles, no duplication.
Add a small script that updates the bar width on scroll:
<script>
document.addEventListener('scroll', function() {
var bar = document.querySelector('.nanobar__bar');
if (!bar) return;
var scrollTop = window.scrollY;
var docHeight = document.documentElement.scrollHeight - window.innerHeight;
var progress = docHeight > 0 ? (scrollTop / docHeight) * 100 : 0;
bar.style.width = progress + '%';
bar.parentElement.setAttribute('aria-valuenow', Math.round(progress));
});
</script>
Checkpoint: Rebuild your site (bundle exec jekyll build) and verify the nanobar appears at the configured position with the configured colour.
The nanobar is forged. Now turn your attention to the footer.
Open your footer include or layout section. Look for a pattern like this:
<footer>
<div class="container"> <!-- 👈 This constrains the width -->
<div class="bg-dark text-light p-4">
Footer content...
</div>
</div>
</footer>
The container class adds horizontal padding and a max-width, preventing the dark background from reaching the viewport edges.
<div>container parentcontainer class off in the Styles panel — watch the background snap to full widthChange the footer structure so the dark background section is outside any width-constraining wrapper:
<!-- BEFORE (constrained) -->
<div class="container">
<div class="bg-dark text-light p-4">
Content here
</div>
</div>
<!-- AFTER (full-width background, contained content) -->
<div class="bg-dark text-light p-4">
<div class="container">
Content here
</div>
</div>
| Layer | Class | Purpose |
|---|---|---|
| Outer | bg-dark text-light p-4 |
Full-width dark background |
| Inner | container |
Centers and constrains the text content only |
🧙 Artisan’s Tip: The principle is “backgrounds go wide, content stays centred.” Apply this pattern any time you need a full-bleed section with contained text.
Checkpoint: Rebuild and verify the footer’s dark section stretches edge-to-edge while text remains centred.
# Full Jekyll build — must exit 0
bundle exec jekyll build
# If using Docker:
docker-compose exec -T jekyll bundle exec jekyll build \
--config '_config.yml,_config_dev.yml'
_config.yml value# Temporarily disable nanobar — site should render without it
nanobar:
enabled: false
Rebuild and confirm no nanobar appears and no build errors occur.
Congratulations, artisan! You have forged two powerful improvements:
| Reward | Description |
|---|---|
| 🛠️ Component Architecture | You can extract any inline element into a reusable, configurable include |
| 🎨 CSS Scoping Mastery | Your styles stay contained — no leakage, no !important hacks |
| 📐 Layout Control | You understand the “backgrounds wide, content centred” pattern |
| ⚙️ Config-Driven Design | Site owners can customise components without touching code |
_config.yml and site-level settingsGo forth, artisan, and may your components be modular, your styles scoped, and your layouts ever full-width when they need to be. ⚒️
_config.yml and site-level settings