/software
🖼️ Automatic captioning of images with js
I like to caption my images and I like to write in Markdown. However, it is currently not possible to make captioned images, i.e. make an HTML figure using just Markdown - at least at the current spec (version 0.27) at the time of this writing.
One way to do this, since Markdown
supports HTML, is to just write a “<figure>
” tag everywhere
instead of writing with the Markdown “![]()
” image syntax. However, I want to use the
“![]()
” syntax! So, here is a nice trick for captioning images using only the Markdown syntax with a little Javascript.
Use jQuery
The trick is to use Javascript to find images with non-zero alt
attributes and convert them to figures with the caption filled in with the content of the alt
attribute. Someone came up with this before me, and here is their script:
$("img").each(
function() {
if ($(this).attr("alt")) {
$(this).wrap(
'<figure class="image"></figure>'
).after(
'<figcaption>' +
$(this).attr(
"alt") +
'</figcaption>'
);
}
}); // from https://blog.kchung.co/adding-image-captions-to-ghost/
Use vanilla Javascript
The above code works great, but it requires JQuery. I don’t want to use JQuery so I carefully followed oneuijs/You-Dont-Need-jQuery and I was able to convert this to just plain Javascript:
function ready(fn) {
if (document.attachEvent ? document.readyState === "complete" :
document.readyState !== "loading") {
var elements = document.querySelectorAll("img");
Array.prototype.forEach.call(elements, function(el, i) {
if (el.getAttribute("alt")) {
const caption = document.createElement('figcaption');
var node = document.createTextNode(el.getAttribute("alt"));
caption.appendChild(node);
const wrapper = document.createElement('figure');
wrapper.className = 'image';
el.parentNode.insertBefore(wrapper, el);
el.parentNode.removeChild(el);
wrapper.appendChild(el);
wrapper.appendChild(caption);
}
});
} else {
document.addEventListener('DOMContentLoaded', fn);
}
}
window.onload = ready;
Of course this looks a little more complicated, but it works just the same.
Smooth experience
The only issue here is that when you load a page you will see all the figures “jump” into place as the captions are written to them, about one hundred milliseconds after the page loads. To avoid this, you can cover up the page until it is totally ready with a div:
<div id="loadingMask" style="width: 100%; height: 100%; position: fixed; background: #fff;"></div>
Then you can add a fade out to this div in the Javascript ready()
function:
el = document.getElementById('loadingMask');
fadeOut(el);
The fadeOut()
function is adapted from the youmightnotneedjquery.com fadeIn()
function:
function fadeOut(el) {
el.style.opacity = 1;
var last = +new Date();
var tick = function() {
el.style.opacity = +el.style.opacity - (new Date() - last) / 80;
last = +new Date();
// console.log(el.style.opacity);
if (el.style.opacity > 0) {
(window.requestAnimationFrame && requestAnimationFrame(tick)) || setTimeout(tick, 16);
} else {
el.style.display='none';
}
};
tick();
}
Go ahead and copy that to whatever site you want! The full code is here.