Have you ever needed to generate an image from your HTML? Whether it be for design purposes or for marketing purposes with social media, knowing how to get a screenshot of your HTML design without manually taking the screenshot can be a great thing.
A use-case I was interested in was around feature graphics for each of my blog posts. Sure I could open a graphic design tool like Affinity Photo, or use the same feature graphic for every tutorial, but what if I wanted to automatically generate them based on certain criteria?
In this tutorial we’re going to see how to use Puppeteer to take screenshots of our HTML through a headless Gulp task.
To get an idea of what we want to accomplish, take the following as an example:
The above image was created entirely with HTML and could satisfy my use case of being a feature image for a tutorial on the blog. In fact, I got the idea after seeing similar feature graphics on DEV.to articles. While I don’t know what their strategy is, I thought I’d invent my own.
Before we dive into the process of taking screenshots, we should come up with some HTML to capture. To be clear, any HTML elements would work, but let’s focus on being creative, matching the example I presented earlier.
Create a project with an index.html file, a style.css file, and a few image files. For this particular example, we’ll being using a lot of Flexbox.
Open the project’s style.css file and include the following code:
html, body {
height: 100vh;
margin: 0;
display: flex;
width: 100vw;
}
#container {
flex: 1;
display: flex;
flex-direction: column;
border: 10px solid black;
background-color: #931c22;
padding: 25px;
color: #FFFFFF;
}
#body {
flex-grow: 1;
font-size: 4rem;
display: flex;
align-items: center;
text-transform: uppercase;
font-weight: bold;
line-height: 6rem;
}
#footer {
display: flex;
flex-grow: 0;
flex-direction: row;
align-items: center;
}
#author {
flex-grow: 1;
display: flex;
flex-direction: row;
align-items: center;
}
#author-img {
width: 75px;
height: 75px;
margin-right: 25px;
border: 2px solid #FFFFFF;
}
#author-name {
font-size: 2.5rem;
margin-right: 10px;
text-transform: uppercase;
}
#brand-icon {
width: 75px;
height: 75px;
border: 2px solid #FFFFFF;
}
I am by no means a CSS or design expert, so the CSS above may be able to be optimized. However, everything worked as expected when combined with my HTML.
With the CSS in place, open the project’s index.html file and include the following markup:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div id="container">
<div id="body">
Execute HTTP Requests in JavaScript Applications
</div>
<div id="footer">
<div id="author">
<img id="author-img" src="nraboy.jpg">
<div id="author-name">
Nic Raboy
</div>
</div>
<img id="brand-icon" src="icon.png">
</div>
</div>
</body>
</html>
In my example, I’ve already downloaded an nraboy.jpg image and an icon.png image. However, feel free to change the CSS, HTML, and images to meet your needs.
Now that we have some HTML in place, we can focus on generating a screenshot of it. To do this we’ll be using Puppeteer, which is a headless Chrome Node.js API.
Within the project, we’ll need to install a few dependencies, which will require Node.js. From the command line, execute the following:
npm install puppeteer gulp gulp-tap --save-dev
While Puppeteer will be doing most of the work, we’ll be using Gulp to manage the task. Since we’ll be using a Gulp file pipeline, we need to be able to tap into the pipeline and gather various information about the files being processed, hence the extra package.
Now that the dependencies are in place, create a gulpfile.js file with the following JavaScript code:
const gulp = require("gulp");
const puppeteer = require("puppeteer");
const tap = require("gulp-tap");
const path = require("path");
gulp.task("build", function () {
return gulp.src(["**/*.html", "!node_modules/**/*"])
.pipe(tap(async (file) => {
const browser = await puppeteer.launch({ headless: true });
const page = await browser.newPage();
await page.setViewport({
width: 1200,
height: 600,
deviceScaleFactor: 1,
});
await page.goto("file://" + file.path);
await page.screenshot({ path: path.basename(file.basename, ".html") + ".png" });
await browser.close();
}));
});
This particular Gulp configuration has a single task for building the images. The task looks for all HTML files in the directory and excludes anything in the node_modules directory.
For every file in the pipeline, a headless browser is created with the specified viewport configuration. The filename and path is extracted and used for rendering the HTML, then saving the render to an image.
You just saw how to use Puppeteer to capture a screenshot of an HTML render without using browser based JavaScript, meaning completely headless.
There are plenty of use-cases for this, but for me, using HTML as a template for marketing images is great. These images can be generated automatically without having to open a common multimedia editing application.