npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

postcss-gradient-transparency-fix

v4.1.0

Published

PostCSS plugin to fix gradient transparency for Safari and older browsers

Downloads

4,282

Readme

PostCSS Gradient Transparency Fix

npm Build Status Project Status

A PostCSS plugin to fix gradient transparency for older versions of the Safari browser (anything earlier than version 15.4).

:warning: Since the release of Safari 15.4, this plugin is in a maintenance-only mode.

What it does

The short version

Finds all instances of the transparent keyword being used in CSS gradients and tries to replace them with specific colour values.

The long version (a.k.a. Why it’s needed)

Back when the CSS gradients specification was first written, it defined colour transitions as simple interpolations in the RGB colour space. A lot of web developers started being caught out by gradients that faded to full transparency, and noticed dark greys in their gradients.

Gradient using old spec

The reason for the darkness is that the CSS keyword transparent is actually an alias for rgba(0, 0, 0, 0) — that is, fully transparent black. A simple definition like linear-gradient(red, transparent) would not only fade the colour from fully opaque to fully transparent, but it would also fade from red to black at the same time.

While this was correct from a technical view, it was unintuitive behaviour to web developers. Eventually the spec was changed to codify the use of a special graphics technique called pre-multiplied alpha. While the specifics of this technique are not important here, the results are. Effectively it means that gradients fading to/from a fully transparent colour now eliminate the “fade to black” part, and look much more like developers expect them to.

Gradient using new spec

Of course, there was a catch — not all the browsers implemented the updated version of the spec at the same time. If you wrote a gradient with a transparent value, it would look the way you intended in some browsers but not in others.

When this plugin was first written in 2016, some browsers had started to support the new spec. Very soon afterwards, Safari was left as the only browser that supported CSS gradients but did not support the updated spec. This applied to both desktop and iOS Safari.

In March 2022, Safari 15.4 was released with full support for pre-multiplied alpha transparency, completing the last piece of the support puzzle. But not all devices can upgrade to 15.4, so a compatibility solution is still required.

The solution for those older browser versions is to not use the transparent keyword at all, but instead use specific rgba() or hsla() values that have full transparency but keep the colour the same:

/* Original */
.thingy {
    background-image: linear-gradient(green, transparent);
}

/* Compatible version */
.thingy {
    background-image: linear-gradient(green, rgba(0, 128, 0, 0));
}

If you have colours either side of a transparent keyword, you need to create two transparent colour stops at the same position in order to keep the colour transitions the same:

/* Original */
.thingy {
    background-image: linear-gradient(green, transparent 50%, blue);
}

/* Compatible version */
.thingy {
    background-image: linear-gradient(green, rgba(0, 128, 0, 0) 50%,
                                             rgba(0, 0, 255, 0) 50%, blue);
}

If you’re manually editing your gradients to do this, it can become easy to make mistakes — especially if you have to convert from #rgb hex values in the process.

That’s where this plugin comes in. You can continue to author your gradients with transparent values, and the plugin will transform them into the more compatible version for you.

It will only transform transparent values that are found in gradients. Using background-color: transparent, for example, will be left unchanged.

Examples

Input:

.simple {
    background-image: linear-gradient(transparent, red);
}
.keep-stop-positions {
    background-image: linear-gradient(transparent 40%, #f00 60%);
}
.complex {
    background: transparent radial-gradient(farthest-side at 30px 2em, red, transparent),
                linear-gradient(hsl(230, 45%, 86%), transparent 3em, peachpuff);
}

Output:

.simple {
    background-image: linear-gradient(rgba(255, 0, 0, 0), red);
}
.keep-stop-positions {
    background-image: linear-gradient(rgba(255, 0, 0, 0) 40%, #f00 60%);
}
.complex {
    background: transparent radial-gradient(farthest-side at 30px 2em, red, rgba(255, 0, 0, 0)),
                linear-gradient(hsl(230, 45%, 86%), hsla(230, 45%, 86%, 0) 3em, rgba(255, 218, 185, 0) 3em, peachpuff);
}

Usage

Install the plugin via npm: npm install postcss-gradient-transparency-fix

Then include it in your project in the same way as other PostCSS plugins. For example:

postcss([ require('postcss-gradient-transparency-fix') ])

See the PostCSS docs for examples for your environment.

Caveats, warnings, etc.

transparent only

Only values of the keyword transparent will be altered. Any other transparent colours, including rgba(0, 0, 0, 0), will be left unchanged as they could be specifically intended as those values.

Define stop positions

For best results, define explicit stop positions for the transparent colour stops. The plugin will try to guess missing stop positions where possible, but due to the nature of gradient calculations, some position values can only be calculated by the browser at the time of rendering. Do you really understand CSS linear-gradients gives many details of how browsers calculate stop positions.

Some examples of what is supported:

/* No positions at all, assumes 50% */
(red, transparent, green) -> (red, transparent 50%, green)

/* One stop has a percentage value, context can be calculated */
(red 50%, transparent, green) -> (red 50%, transparent 75%, green)

/* Surrounding stops have positions with the same unit type */
(red 30px, transparent, green 80px) -> (red 30px, transparent 55px, green 80px)

Examples of positions that cannot be calculated at all:

/* One stop has a non-percentage value, context depends on final rendered size */
(red 100px, transparent, green)

/* Surrounding stops have different unit types */
(red 100px, transparent, green 80%)

/* Surrounding stops use calc() */
(red 1em, transparent, green calc(100% - 1em))