Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .jules/bolt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## 2025-05-15 - [Blogger Image Serving & FOUC Prevention]
**Learning:** Blogger's `resizeImage` operator is essential for performance, but often ignored in themes. Serving original images and resizing with CSS is a massive bottleneck for LCP. Also, placing dark mode logic at the end of the `<body>` causes a distinct FOUC that impacts perceived performance.
**Action:** Always use `resizeImage` with `srcset` and `sizes` for Blogger templates. Move critical theme-switching logic to the `<head>` to ensure correct rendering from the first frame.
27 changes: 23 additions & 4 deletions gridsense.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,15 @@
-->
<b:include data='blog' name='all-head-content'/>
<title><data:blog.pageTitle/></title>
<script>
//<![CDATA[
// ⚡ Bolt: Immediate theme application to prevent Flash of Unstyled Content (FOUC)
(function() {
const theme = localStorage.getItem('theme') || (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
document.documentElement.setAttribute('data-theme', theme);
})();
//]]>
</script>
<b:if cond='data:view.isHomepage'>
<script type='application/ld+json'>
{
Expand Down Expand Up @@ -1419,7 +1428,14 @@

<!-- Helper for Responsive Image -->
<b:includable id='responsiveImage' var='info'>
<img expr:src='data:info.image' loading='lazy' style='width: 100%; height: 200px; object-fit: cover;'/>
<!-- ⚡ Bolt: Optimized image serving using Blogger's resizeImage for better LCP and data savings -->
<img decoding='async'
expr:alt='data:post.title'
expr:src='resizeImage(data:info.image, 600)'
expr:srcset='resizeImage(data:info.image, 300) + " 300w, " + resizeImage(data:info.image, 600) + " 600w"'
loading='lazy'
sizes='(max-width: 768px) 100vw, 400px'
style='width: 100%; height: 200px; object-fit: cover;'/>
</b:includable>

</b:widget>
Expand Down Expand Up @@ -1755,6 +1771,10 @@
function setTheme(theme) {
html.setAttribute('data-theme', theme);
localStorage.setItem('theme', theme);
updateIcons(theme);
}

function updateIcons(theme) {
if (theme === 'dark') {
iconMoon.style.display = 'none';
iconSun.style.display = 'block';
Expand All @@ -1764,9 +1784,8 @@
}
}

// Check preference
const savedTheme = localStorage.getItem('theme') || (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
setTheme(savedTheme);
// ⚡ Bolt: Use theme already applied in <head> to avoid re-calculating or flashing
updateIcons(html.getAttribute('data-theme') || 'light');

if(toggleBtn) {
toggleBtn.addEventListener('click', () => {
Expand Down