Some time ago I added excerpts to my blog. A small sample of the full blog text is now shown on the front page after the post heading, date, and tags. To make the excerpts look a bit nicer, I wanted to add an effect that makes the text fade into the background.
You can do this with the CSS mask-image property by setting its value to a linear-gradient.
.some-class {mask-image: linear-gradient(to top, rgba(0, 0, 0, 1.0) 0%, transparent 100%);}
I use Tailwind CSS to style my blog so I wanted to find a solution which doesn't require adding CSS classes or files to my project.
After I didn't find a solution I decided this would be a good time to learn how to make Tailwind CSS plugins.
Creating the plugin was straight forward. I started by reading Tailwind documentation on writing plugins. Then I opened Tailwind Playground and added the plugin skeleton from Tailwind documentation to the config.
// tailwind.config.jsconst plugin = require('tailwindcss/plugin')module.exports = {plugins: [plugin(function({ addUtilities, addComponents, e, prefix, config }) {// Add your custom styles here}),]}
I was only adding utilities, so I removed addComponents
, e
, prefix
, and config
from the parameters. In the function body, I added my code for generating the CSS. I wanted to do all combinations of directions (top, right, bottom, left) and the ability to select the linear gradients start percentage. The percentages would go from 0% to 100% with 10% intervals.
Adding utilities with a plugin works by creating a JavaScript object with all the utility class names as attributes and the matching CSS as the values of those attributes.
So for a utility class of gradient-mask-tr-50%
, I wanted to generate the following object
{"gradient-mask-tr-50%": {maskImage: `linear-gradient(to top right, rgba(0, 0, 0, 1.0) 50%, transparent 100%)`}}
The plugin has the directions and gradient steps configured as arrays. The code then uses a reduce
function to loop through the directions and steps to generate the classes and CSS rules. The returned object is then passed to addUtilities
. Here's the full source code listing of the plugin.
plugin(function ({ addUtilities }) {const directions = {t: "to top",tr: "to top right",r: "to right",br: "to bottom right",b: "to bottom",bl: "to bottom left",l: "to left",tl: "to top left",};const steps = ["0%","10%","20%","30%","40%","50%","60%","70%","80%","90%",];const utilities = Object.entries(directions).reduce((result, [shorthand, direction]) => {const variants = steps.map((step) => {const className = `.gradient-mask-${shorthand}-${step}`;return {[className]: {maskImage: `linear-gradient(${direction}, rgba(0, 0, 0, 1.0) ${step}, transparent 100%)`,},};});const stepClasses = Object.assign(...variants);return {...result,...stepClasses,};},{});addUtilities(utilities);})
Feel free to try the plugin in this Tailwind Playground.
The next step was to create an installable npm package of the plugin code. I created a new npm project with npm init
and copied my plugin code from the playground to a new file called index.js. It has a module.exports definition which contains my plugin function.
I had some confusion on what the module should export, because the plugins I checked didn't use Tailwinds plugin
function, but instead wrapped the plugin function into another anonymous function. In the end, I realized the correct way for me was to export the result of calling the plugin
function with my plugin code as a parameter.
Other than that, I added a readme with description and instructions and published the package to npm using npm publish
.
The full source code can be found from the plugins GitHub repository.
Developing a Tailwind plugin was a simple process, especially because I could test the plugin with the playground before starting a project locally.
If you have any feedback on the plugin, you can add an issue in Github or send me a message in Twitter.