A Gatsby plugin to add interactive animated gifs to markdown files. Check it out!
npm install --save gatsby-remark-interactive-gifs
- Add a gif to your markdown with the gif protocol in inline code.
gif:<filename>.gif
. There are options to customize it defined later on. - A still image is extracted and saved in the
dest
asstill-<filename>.gif
. - Click events will toggle between play and playing.
Gotchas: A fresh copy needs to be downloaded to play a gif from the beginning.
- All caching strategies are bypassed.
- This plugin is designed for images that fill a container. Custom styling is required to cater for gifs not of 100% width.
Tips:
- Optimize your gifs!
- For imagery, I use icons from www.flaticon.com and make sure I attribute them.
- For spinners/loading indicators, I use loading.io.
This plugin requires node >=10.
gatsby-config.json:
{
resolve: `gatsby-transformer-remark`,
options: {
plugins: [
{
resolve: `gatsby-remark-interactive-gifs`,
options: {
root: `${__dirname}`,
src: `${__dirname}/src/gifs`,
dest: `${__dirname}/public/static/gifs`,
play: `${__dirname}/src/images/play.gif`,
placeholder: `${__dirname}/src/images/placeholder.gif`,
loading: `${__dirname}/src/images/loading.gif`,
relativePath: `/static/gifs`
},
},
]
},
}
root
- The root of your project.src
- Where all the gifs you want processed are stored. Absolute path.dest
- A path inpublic
where your gifs are stored. Absolute path.play
- An image to indicate that the gif can be interacted with. Absolute path.placeholder
- An image to show when the gif is missing in action. Absolute path.loading
- An image which shows when the gif is downloading. Absolute path.relativePath
- The relative path served frompublic/
.
Your animated gifs are available in GraphQL and the nodes can be access via allInteractiveGif
.
query MyQuery {
allInteractiveGif {
edges {
node {
height
absolutePath
base64
relativePath
sourcePath
stillRelativePath
width
}
}
}
}
Simply reference your gif file name (relative to the configured src
directory) in the gif protocol in order to embed the interactive gif.
`gif:dolphin.gif`
You can customize it by adding attributes. They are in no particular order and neither are mandatory.
`gif:dolphin.gif:id=hitchikers-guide-to-the-galaxy;class=dolphin;caption=So long and thanks for all the fish`
id
adds element an ids on the gif container and astill-<id>
on the still container.class
adds a class to the parent interactive gif container.caption
adds text to the bottom of the image.
Below is sample styling in CSS
to get you started.
.interactive-gif {}
/* Responsive flicker-less display */
.interactive-gif .embedded {
position: relative;
width: 100%;
height: auto;
}
.interactive-gif .loading,
.interactive-gif .still-container,
.interactive-gif .gif-container {
position: absolute;
top: 0;
width: 100%;
height: 100%;
}
.interactive-gif .still,
.interactive-gif .gif {
width: 100%;
height: 100%;
cursor: pointer;
}
/* Loading indicator */
.interactive-gif .loading .indicator {
position: absolute;
bottom: 0;
left: 0;
width: 80px;
filter: contrast(0.5);
}
/* Play button */
.interactive-gif .still-container .play {
cursor: pointer;
filter: grayscale(100%);
width: 20%;
position: absolute;
opacity: 0.9;
left: 50%;
top: 50%;
transform: translateX(-50%) translateY(-50%);
}
/* Text underneath the gif */
.interactive-gif .caption {
font-size: 90%;
font-style: italic;
}
/* Image displayed when the gif cannot be found */
.interactive-gif .placeholder {
filter: grayscale(100%);
text-align: center;
}
.interactive-gif .placeholder img {
width: 200px;
}
You can convert the above CSS to scss, sass or less.
`gif:nyancat.gif:caption=Nyanyanyanyanyanyanya`
<div class="interactive-gif ">
<div class="embedded"
style="padding-top: 56.28517823639775%">
<div id="loading-nyancat.gif"
class="loading"
style="background-size: cover; background-image: url('/static/gifs/still-nyancat.gif');">
<img class="indicator" src="/static/gifs/loading.gif">
</div>
<div id="nyancat.gif"
class="gif-container"
style="display: block;"
onclick="document.getElementById('nyancat.gif').style.display = 'none';
document.getElementById('still-nyancat.gif').style.display = 'block';">
<img id="image-nyancat.gif"
class="gif"
data-original="/static/gifs/nyancat.gif"
src="/static/gifs/nyancat.gif?t=1587914555745">
</div>
<div id="still-nyancat.gif"
class="still-container"
onclick="var gif = document.getElementById('image-nyancat.gif');
gif.src = gif.dataset.original + '?t=' + new Date().getTime();
document.getElementById('still-nyancat.gif').style.display = 'none';
document.getElementById('nyancat.gif').style.display = 'block';" style="display: none;">
<img id="image-still-nyancat.gif" class="still" src="/static/gifs/still-nyancat.gif">
<img class="play" src="/static/gifs/play.gif">
</div>
</div>
<div class="caption">Nyanyanyanyanyanyanya</div>
</div>
Note:
padding-top
is calculated using the aspect ratio of the image. The embedded container is given enough room to responsively contain the children images and containers.
Run a gatsby clean
when your source nodes are no longer generated.
The order of this plugin only matters when you use it together with gatsby-remark-prismjs
. Prism transforms code blocks and I kind
of slapped a gif protocol in one which will confuse the daylight out of prism. Just reference this plugin somewhere above Prism.
Read the guidelines to contribute to this plugin.
MIT, by Clarice Bouwer