I've been tinkering with the bleak Ghost theme recently, getting it ready with some cool new features for its version 1.0.0 release.
Amongst those features is a bleak implementation for Ghost's new /amp
pages (if you weren't aware, new versions of Ghost support AMP out of the box by appending /amp
to their post URLs), since the default implementation uses a standard Ghost theme. Good for mobile search speed, bad for branding!
Supporting AMP in your Ghost theme boils down to implementing the amp.hbs
top level template file, which will be used in place of the traditional post.hbs
. However, it's not so simple - AMP's by-design strictness means that you need to be careful to design using amp-xxx
tags such as amp-img
instead of their vanilla HTML counterparts. This is pretty easily done using the #is
handlebars helper:
{{#is "amp"}}
<amp-img src="https://my.image.url/img.jpg" width="800" height="600" layout="responsive"></amp-img>
{{else}}
<img src="https://my.image.url/img.jpg"></img>
{{/is}}
However, one more pain point is the requirement of AMP to have a single, in-HTML <style amp-custom>
tag containing styling, rather than one or multiple externally linked stylesheets. I'll show you how I extended bleak's Grunt build process to accomplish this.
Setting the scene
Let's assume for the sake of things that you've got the following file structure, with the relevant bits for our task left in:
scss/
post.scss <-- source SCSS
partials/
...
css/
post.compiled.css <-- compiled from post.scss
partials/ <-- handlebars template partials
...
default.hbs
bleak already used Grunt for compiling post.scss
to post.css
with the grunt-contrib-sass plugin, so I decided to extend by Grunt builds to inline that CSS to the AMP page template.
Compiling a template
We're going to create a handlebars template to go into partials/
which can be post-processed by a Grunt task and filled with the contents of post.css
. That way, the CSS can be included directly in the template and we can pass AMP validation.
With that in mind, the key new file to create is partials/inline_css.hbs
:
<style amp-custom>
@@compiled_css
</style>
If you're following along, you'll be able to use that file as-is: nothing in that is specific to bleak. The whole file simply defines a <style amp-custom>
tag with the slightly odd content of @@compiled_css
. This is the string which will be replaced in a second with the full CSS code.
Let's see how we can do that. First up, we need to add a Grunt plugin to do the replacement:
$ npm install --save-dev grunt-replace
Next, we'll add a replace:inlinecss
task to our Gruntfile:
var fs = require('fs');
module.exports = function(grunt) {
// ...
grunt.loadNpmTasks('grunt-replace');
// ...
replace: {
inlinecss: {
options: {
patterns: [
{
match: 'compiled_css',
replacement: function () {
return fs.readFileSync('./css/post.compiled.css');
}
}
]
},
files: [
{expand: true, flatten: true, src: ['partials/inline_css.hbs'], dest: 'partials/compiled'}
]
}
}
}
After adding this definition you should be able to run grunt replace:inlinecss
and you'll end up with a new file in your structure:
scss/
post.scss <-- source SCSS
partials/
...
css/
post.compiled.css <-- compiled from post.scss
partials/ <-- handlebars template partials
inline_css.hbs <-- original
compiled/
inline_css.hbs <-- compiled and full of CSS
...
default.hbs
The original template at partials/inline_css.hbs
is untouched, but you've now got a new template file at partials/compiled/inline_css.hbs
! This one is full of the styles from post.css
.
Integrating into your pages
Finally, we need a bit of boilerplate to include this partial when we're in AMP (although you could easily make the case for inlining your styles always, especially if they're quite light).
In your default.hbs
, or wherever you handle the contents of your <head>
:
{{#is "amp"}}
{{>compiled/inline_css}}
{{else}}
<link rel="stylesheet" ...>
{{/is}}
Simples! To make the actual styling of the AMP page easier, I'd also recommend another tiny tweak to default.hbs
:
<body class="{{body_class}} {{#is "amp"}}amp{{/is}}">
That .amp
class on the body will enable you to make different styling decisions for elements in the page.
There you have it! One of the trickiest migration tasks for your themes to AMP-compatibility needn't be so scary. ⚡️⚡️⚡️
Hi! I am a content-detection robot. I found similar content that readers might be interested in:
http://unwttng.com/inline-css-to-your-ghost-theme-with-grunt-for-great-amp/