Tweaking Blogger HTML Without Destroying AdSense or Layouts
Disabling Blogger’s Auto Widget Wrapping Without Nuking Layout
If you’ve ever tried replacing a stock Blogger widget with custom HTML, you’ve probably run into the charming mess where Blogger decides your clean, hand-written divs actually need to be mashed inside their own <b:widget>
container, theme styles be damned. I once lost an entire navigation bar because I pasted a working Flexbox header into a layout section and Blogger re-wrapped it on save. The result: my flex items were suddenly inside invisible padding boxes.
The workaround is annoyingly simple but only if you know the exact syntax these autowrappers trigger on. Inside wherever you’re editing (usually under <b:section>
), do NOT place your HTML directly. Instead, use a <b:includable>
block with name='main'
. Blogger leaves that alone.
<b:widget id='CustomHTML1' type='HTML' visible='true'>
<b:includable id='main'>
<!-- your actual HTML here -->
</b:includable>
</b:widget>
This bypasses the runtime box generation and hands you raw control — no added margins, no phantom widgets. But fair warning: if it’s in a drag-and-drop layout section, this won’t work. Blogger will still replace it when you drag things.
Injecting Custom CSS Without Breaking Theme Variables
Blogger themes (especially the newer ones like Contempo or Emporio) rely on scoped inline styles stashed deep inside template variables. Dumping your own styles into <style>
blocks might seem like a fix, but then fonts start changing, inherited spacing breaks, or colors revert under dark mode themes. I thought I was losing my mind until I realized why: Blogger interpolates CSS using the <expr:b:class>
logic that’s hidden unless you manually unescape the entire template.
Best approach I’ve found:
- Use
skin.css
override via<b:skin>
. Put it after their dynamic section, not before. - Don’t override !important unless you like breaking mobile views.
- If you must override variables like background or color fonts, check for
theme:{{variable}}
use first. These are semi-dynamic and user-settable.
Styles you drop early in the template file might just…not apply. Took me two days to figure out where Blogger was silently injecting inline styles over mine. They don’t warn you anywhere.
AdSense Units Not Rendering After HTML Structural Changes
So here’s a thing I hit last month: I moved a Google AdSense in-article ad block from a sidebar widget to just above the first <h2>
using manual HTML insertion. The ad snippet was copy-paste correct, and the script was properly included once at bottom… but the ad flat-out refused to show on articles. No console errors. No logs. No gray space. Just… nothing.
Turns out: Blogger pages don’t always load adsbygoogle.js
dynamically if the corresponding widget has been removed from Layout. Even if <script async src="...">
is there, it sometimes won’t initialize unless a widget marked type='AdSense'
also exists in the layout config file (template.xml
). You’d never know unless you’ve opened the full template and seen this middle-of-nowhere logic punch through.
Add this snippet at the bottom of your template body manually if you’re working without widgets:
<script data-ad-client="ca-pub-123..." async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
Then window.adsbygoogle
will be defined properly and your manual insertions actually initialize.
Adding JSON-LD to Blogger Without Triggering Errors
Google wants JSON-LD schema. Blogger breaks it. Specifically: anything with {{}}
braces inside <script type="application/ld+json">
tags triggers Blogger’s template parser. So if you’re pasting a JSON-LD snippet from Google or Schema.org and it includes curly braces, you’ll get a cryptic “Could not parse…” error on save.
Here’s the fix: wrap the <script>
tag inside a <b:if cond="true">
block and escape your curly braces using {
and }
. Or just base64-encode the schema and decode+inject it via raw JS, which is what I ended up doing after three failed validation passes.
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BlogPosting",
"headline": "My Custom HTML Guide",
"author": { "@type": "Person", "name": "Me" }
}
</script>
This version will not save. But the encoded version below works:
<script>
var e = atob("eyJAY29udGV4dCI6ICJodHRwczovL3NjaGVtYS5...=");
document.head.insertAdjacentHTML("beforeend", '");
</script>
Yeah, it’s clunky. But Blogger’s HTML processor doesn’t give you many options.
Client-Side JS Hacks for Simulating Post/Page Detection
Blogger doesn’t have native dynamic flags to tell you whether you’re on a homepage vs a single post, unless you bake it into the template logic. In JavaScript, there’s no official support — but there is a weird little endpoint that gives away structure.
Watch what happens when this runs:
if (window.location.href.match(/d{4}/d{2}/.*.html/)) {
console.log("post")
} else {
console.log("not post")
}
That’s the only reliable way I’ve found client-side to detect whether you’re on a permalink. Every other Blogger metadata trick breaks once custom domains are involved. Found this messing around with someone else’s food blog that was applying AMP styles to every category index by mistake.
Hijacking Blogger’s Built-in Comment Form With Styled Fields
This is for those of you who’ve grabbed a template where the comment form looks like it was designed in 2006. Trying to replace the form field elements breaks Akismet validation and causes Blogger’s form controls to vanish, especially that weird login-required error box.
You have to leave <b:include name='comment-form'/>
in place, but you can style its inner elements using very specific combinator CSS — Blogger generates stable IDs for them but doesn’t document it.
These CSS selectors work even when you change themes:
#comment-editor input
for name/email#comment-editor textarea
for the body.comment-form input[type='submit']
— careful, sometimes replaced with a span#comment-editor .goog-inline-block
— this is actually the honeytrap widget
Had a moment where the entire page broke because I removed the submit button and Chrome dev tools showed display: none
injected by Blogger itself. Styling it instead of deleting it was the fix.
When Preview Lies: Why Updates Work in Live Only
This might be my favorite Blogger bug. When editing templates or pasting in new widgets, the “Preview” button doesn’t render injected scripts or updated AdSense code accurately. Ever. If your ad units or widget JS code needs document.body.appendChild
-style ops, you’ll think your changes are broken — until you hit save and reload the live site.
“In preview, your scripts run in an iframe shell that strips document writes.”
Found this buried in a Google forum thread. Also applies to adding <meta>
tags via <head>
overrides — they won’t render in preview but do load in live. Preview uses a stripped interpreter that doesn’t touch <body>
directly. Makes debugging double-hard if you don’t know this.