Your browser is a miracle!
Every pixel you see on this page is the result of stacking hundreds of elements on top of each other and deciding, millions of times, pixel by pixel, what the result should look like.
Two important steps in this process are compositing and blending, and in this post, we'll get to see what they are, how they work, and where they can be useful when building fun effects on the web.
- What compositing is, and what it has to do with blend modes
- What a blend mode is and how you can reason about what it will do
- Which blend modes exist and which ones are commonly useful in real-world scenarios
- How blend modes can be used in CSS, and problems that you might run into
Let's dive in!
Compositing
Before we can talk about what a blend mode is, we have to talk about compositing. Compositing is "the process of combining an element with its backdrop", according to the W3C specification. What does this mean?
The pixels you see on your screen while you're reading this were drawn by your browser. This webpage consists of many HTML elements making up many layers, and the browser draws each layer and then combines them. If we simplify a bit, it looks like this:
The step of combining these layers with each other is called compositing. We'll call the layer that is drawn onto during compositing the backdrop, and the layer that is being drawn the source.
Let's look at how the browser might composite the input textbox of your favorite LLM tool, which consists of many different elements. We'll pretend that each element is a layer, but do note that in reality, layers are made up of multiple elements. Once a layer is painted, operations like transforming or fading it only require re-compositing, not re-painting, which saves time and increases performance.
For our general intro to compositing though, what exactly constitutes a layer in the browser is not of huge concern. Move the slider to pan through the compositing steps, and view the different compositing layers by clicking the small 3D button in the top corner.
In this example, we simply draw the current layer on top of the backdrop and call it a day. For a browser, this is sufficient. But compositing can be much more powerful: In different contexts, we can choose from many other ways to composite the source layer with the backdrop, like drawing it behind, or only drawing the overlap of both layers.
Let's look at the different operations which are possible. When we combine two images, each pixel falls into one of four regions, depending on whether this pixel exists in both the source and the backdrop, only one of them, or neither:
For each of these regions, we can choose what the composited pixel should be; for example, for the region in which only the source has visible pixels, we can either display these pixels in the composited image, or display nothing. The following table shows the available options:
| Region | Name | Description |
|---|---|---|
| Source Only | The pixel is present in the source but not the backdrop. 2 Options: Choose between showing source or nothing | |
| Backdrop Only | The pixel is present in the backdrop but not the source. 2 Options: Choose between showing backdrop or nothing | |
| Both | The pixel is present in both the source and the backdrop. 3 Options: Choose between showing source, backdrop or nothing | |
| Neither | The pixel is not present in either the source or the backdrop. 1 Option: Show nothing (as there is nothing to composite) |
The Porter-Duff Operators
If we count all the possible permutations, there are a total of ways to composite the four regions of two overlapping images. These 12 options are called the Porter-Duff compositing operators, after Thomas Porter and Tom Duff of Lucasfilm, who came up with them in 1984.
They define, mathematically, how to combine two pixels during compositing. The formula to calculate the resulting color for a pixel when compositing two layers is given by:
Variables with the letter are colors, which are given as a 3-dimensional vector in the form . is the output color, and and are the source and backdrop colors, respectively. We can calculate the resulting opacity in the same way:
Let's address the elephant in the room: What are the factors and ? These are set depending on the compositing operator in use, and they are central to determining how the compositing operation will behave.
For example, if we only want to keep the source color when both the source and backdrop have a color set, then we can set and . This will simplify the color formula to and the opacity formula to , which shows us that only the source color remains with its original opacity.
What really helped make these click for me was thinking about them as a sort of maximum contribution for both the source color and the backdrop color. For example, when we set , then the backdrop color can never contribute anything to the result. However, if we set , then the backdrop color could contribute fully to the result, depending on the opacity of the source at this pixel.
If we think back to the 12 operations we came up with above, we can now express them as maximum contribution factors and for each operator:
| Name | Description | |||
|---|---|---|---|---|
| Clear | Clear image | |||
| Source | Only source is visible | |||
| Backdrop | Only backdrop is visible | |||
| Source Over | Source covers backdrop | |||
| Backdrop Over | Backdrop covers source | |||
| Source In | Source visible in intersection | |||
| Backdrop In | Backdrop visible in intersection | |||
| Source Out | Source visible outside intersection | |||
| Backdrop Out | Backdrop visible outside intersection | |||
| Source Atop | Backdrop with source visible in intersection | |||
| Backdrop Atop | Source with backdrop visible in intersection | |||
| XOR | Intersection is cleared |
Because the raw formulas can be rather confusing, it's much easier to play with this yourself. In the following playground, you can choose the Porter-Duff operator of your choice and explore how the formulas behave for each pixel in the two overlapping squares:
Opacity and Coverage
I said before that the variables used in the general compositing formula describe the color's opacity, but that is only partially true. In reality, actually combines the opacity and the coverage. But what is the coverage of a pixel?
When shapes are rendered by the browser, their edges don't fit perfectly on the pixel grid onto which they are rendered:
In these cases, the rendering step will determine how much of a pixel is covered by a shape. This percentage value is the coverage. The color itself might also not be fully opaque, so the final alpha value is given by
So a fully opaque pixel at the edge of a shape might have an value of , but so would a semi-transparent pixel with full coverage: . In the end, the origin of the alpha value does not really matter. It's just important to know that the calculations in the compositing formula are used even for fully opaque objects in cases where they don't align perfectly with the pixel grid which they are rendered onto.
So next time you see a smooth rendered edge on a fully opaque font or rounded shape, you'll know that it only appears smooth because the compositing step combined the backdrop and source colors into faded color somewhere in between, depending on the pixel coverage. Neat!
Compositing in Practice
So, this is compositing. But what can it do for you? Unfortunately, in the DOM, you don't really get any control about Porter-Duff operators. Rendering simply uses source over compositing, which is sure to be the most intuitive and definitely what you would expect. But you cannot control it, it simply is.
In canvas land on the other hand, you get a say in all of this! On a canvas context, the globalCompositeOperation property can be set to change the compositing operator used when drawing new things onto the canvas. This way, you can combine different Porter-Duff operators to draw foreground elements, mask them if needed, and then draw the backgrounds behind them later.
To illustrate this, we'll draw a little Pac Man ghost using only simple shapes and compositing operators. Move the slider to see the little ghost come to life. At each step, the next shapes to be composited are shown as a dashed red outline.
This uses a few of the compositing operators we saw before: We carve out areas of our ghost for its "feet" using destination-out, and apply the pellets and black background at the end behind the finished ghost using destination-over. I encourage you to get creative with this; I'm sure there are lots of fun ideas left to explore!
Blending
Now that we know how the pixels on our screen are composited, we can look at how they are blended. When we composite two layers, blending happens in the region where the source and backdrop overlap (the Both region from before), and it allows us to change what the resulting color will be.
happens
here
Conceptually, the blending step happens before the compositing step: For every pixel in the region, the source color is first blended in place with the backdrop color, which results in a new source color. This new color is then composited with the backdrop to receive the final pixel color. Here is what that process looks like for a single pixel:
From now, let's focus on the blending step: The general formula for blending the source pixel with the backdrop pixel is:
The key thing to notice is that shows up on both sides of the equation: The source color is replaced with a new one before being composited later. That newly created color combines the original (if the backdrop is not fully opaque) with whatever produces. So what is this?
is what we'll call our blending function: It takes two colors as a parameter, and returns a new color. That's it.
In theory, we can choose any function for that we like. We could have a blending function that always returns hotpink, and this would totally work out. In practice though, we don't get to choose freely. Instead, the tools we use – in our case, the browser – give us some presets for from which we can choose. These presets are the common blend modes that you might have encountered before, and we can refer to them by name: lighten, darken, etc.
So now that we know that blend modes are essentially just named functions, that begs the question: What are the underlying functions? And what do they really do?
Channel Separation
The first thing that is important is that there are two types of blend modes: We differentiate between separable blend modes and non-separable blend modes.
A blend mode is called separable if it acts independently on each of the input colors' channels. In practice, this means that when we blend two colors, each of their channels is blended separately (thus, separable), and the result combined into the final color.
You can see this concept in the following demo: Both input colors are split into their R, G and B channels, and the resulting channels depend only on the corresponding input channels. There are no dependencies across different channels. In this example, our blending function will simply select the larger value of each channel:
All other separable blend modes work in the same way! The only thing that changes between them is the blending function used to determine the blended channel values, but the concept of channels being blended independently stays the same.
So what then are non-separable blend modes? In this category, the resulting color cannot be individually created by blending each RGB color channel. Instead, the blend modes operate on higher-level perceptual properties of the color – its hue, saturation, and luminosity – mixing and matching these properties between the backdrop and source color to produce the result.
We don't really do complex maths here at all; there is no formula to go by. We simply select different components from the original colors to receive our final color. Due to this, I find the term non-separable a bit misleading: While it is true when you think of colors in RGB, because all channels can contribute to each of the perceptual properties, along the hue/saturation/luminosity axes they are actually perfectly separable. The easier way is to think of the blend modes in terms of what they operate on: We have some RGB-channel blend modes, and some perceptual blend modes.
Visualizing blend modes
Now we have an idea of the types of blend modes, but its still not trivial to build an intuition for what a blend mode does. I'll be honest up front and tell you that even after reading this, you won't be able to tell exactly how a blend mode will behave on an image. The reason for this is that you'd need to consider every channel of every pixel at the same time, which is simply too much for our human brain.
So instead, we can make thinking about blend modes in general a bit easier by visualizing how they behave for a single pixel. In many circumstances, this can help us reason broadly about what outcome to expect.
Let's do a quick color recap: We know that in RGB, each channel can take values from to , inclusive. Every pixel is made up of these three components, and we can separate every image to look at each channel individually:

We can see that areas which are bright in one of the channels mean that this color contributes a lot in this area, whereas dark shades mean this color is not present. Note that dark here means the RGB channel value; the human perception of colors means that full green will always be perceived brighter than full blue, for example. When we combine these separate channels, we end up with our original image:




We have three channels, but we have also just learned that the blend mode works the same for each channel, so in theory, it should be sufficient to visualize how a blend mode works on just one channel to know how it will behave on the other two.
But instead of choosing a specific channel for our visualization, we can just use grayscale values as a generic representation of our channels. A value of (black) means the channel does not contribute to the final color at all, whereas (white) means the channel has full contribution.
This bar shows us one channel at a time, for one color. Extending this concept to blend modes, in which we combine two colors with each other, we can plot a two dimensional plane on which the x axis represents the channel value from the backdrop, and the y axis similarly represents the channel value from the source. This allows us to visualize how a blend mode behaves in one channel, but since we know that a blend mode works the same on all channels, a single generic visualization is sufficient.
For example, let's plot the visualization of a blend mode with , which always picks the larger, and thus lighter, value for the channel it is comparing:
The resulting visual is mostly light, indicating an overall lighter result after applying the blend mode. Looking closer, we can see that as long as either the source or the backdrop has a light value, the resulting value is also light. Finally, we can tell from the symmetry that the order of background and source does not matter. We will see that some other blend modes are asymmetrical, meaning they behave differently depending on the order of source and background.
You can hover over the diagram to see which values from the backdrop and source are being used for the computation, as well as the resulting value. Take a moment to really understand what's going on here, because we will use the same style of diagram to explore all the other blend modes later in this post.
Let's put our newly learned visualization to work by showing how this blend mode will act on an image. We'll blend the image with a solid layer so that we can see the interaction between the lightness of the image and the blending color. We'll again stick to grayscale colors, because that way we don't need to worry about how the colors would change in a full image.
This should give you a good intuition of what this formula does: Dark channels are "brought up" to the blend colors' channel value, while lighter channels remain unaffected. This formula we just explored is the one used by the lighten blend mode, and we'll now look at the remaining blend modes!
Categorizing blend modes
When we look at the different blend modes in CSS, we can split them into different categories based on the effect they result in on two given colors. For example, the lighten blend mode – as the name suggests – generally results in a lighter image, but it is not the only one with this effect.
Ignoring normal, because it does not result in any change, we group the blend modes into the following categories:
| Category | Description | Blend Modes |
|---|---|---|
| Lighten | Results in a lighter image | lighten, screen, color-dodge |
| Darken | Results in a darker image | darken, multiply, color-burn |
| Contrast | Combines lighten and darken effects | overlay, soft-light, hard-light |
| Inversion | Effects based on similarity | difference, exclusion |
| Component | Non-separable / HSL blend modes | hue, saturation, color, luminosity |
Let's dig into each of these categories a little bit to see what they do.
Lighten
Let's start with the category of blend modes which lighten the image. The simplest one of these we have already explored: The blend mode of the same name, lighten, picks the higher (and thus lighter) value for each RGB color channel, resulting in a brighter image.
Notably, lighten only ever picks one of the two input values. So if you combine two dark layers, the result is still just the lighter of the two. This is what causes the sharp diagonal line visible in the graph, because for two identical values, the resulting value will simply be the same.
To get a smoother result, we can use the screen blend mode, which has a similar lightening effect but blends smoothly instead of picking a winner. For photographic images screen is usually the more natural choice, but lighten can be useful when combining graphics where you don't want any color interpolation, like logos.
Finally, there is color-dodge, which has a very sharp edge in its transition where the sum of both channels approaches . We can see that almost half the area is full white, resulting in a very aggressive lightening effect, in which the result gets sharply brightened.
Darken
For every blend mode in the lighten category, we have a complementing option in the group of darkening blend modes. In the same order as above, these are darken, multiply, and color-burn:
The darken blend mode darkens each channel but suffers from the same "edge" as lighten, so multiply is almost always preferable for images due to its smoother transition. The complement to color-dodge is color-burn, which darkens the channel aggressively, more where the source is darker.
Contrast
The contrast blend modes are interesting, as they apply lighten or darken effects based on one of the channels. overlay is a mixture of screen and multiply, and combines them based on the backdrop color. If the backdrop channel is dark (< 0.5), it darkens the result, otherwise, it lightens it. Both are applied at half strength, so that the transition is a bit smoother.
The hard-light mode is essentially overlay with the source and backdrop swapped: the same screen/multiply mixture, but now the source channel is what decides whether to lighten or darken. A dark source channel darkens the result, while a light source channel lightens it.
Lastly, the soft-light blend mode does sort of the same thing as overlay, but its transitions are smoother. In many cases it is a better replacement, but depending on your colors you might get different results.
Inversion
Inversion blend modes can be thought of as comparing the two channels they are applied to and choosing the result based on how similar they are. The difference blend mode yields dark results where the input channels are identical, and brighter results the more they differ.
The exclusion blend mode is sort of a soft version of difference: It behaves the same for the extreme values of the input channels (close to or ), but when both are closer to , it results in a medium bright value instead of black, even though the values are similar.
Explore yourself
At this point we've seen how all the blend modes behave in theory, but we've not tested them on any real images yet. That changes now! First, let's now see how all those blend modes behave on our grayscale image from before. I encourage you to go back and look at the charts before toying around, to see if you can guess how they will behave:
Finally, let's add back some color to our theory. We stuck to grayscale because colors in images behave quite unpredictably, but we can certainly look at individual pixels. In the following demos, you can pick two colors of your choice as well as a blend mode and see what result you get.
This is also where I've hidden the maths aspect of blend modes: You can inspect the formula for each blend mode and see how it is applied to the colors in question.
Usage in the browser
Now that we know all the blend modes and the results they produce, we can finally put them to work! We do this by using the mix-blend-mode or background-blend-mode properties.
For blending elements, you simply use mix-blend-mode and pass it one of the 16 blend modes we discussed above. Your browser will take care of the rest, compositing the elements for you and applying the blending function.
.element {
mix-blend-mode: multiply;
}
Another way to use blend modes is to blend backgrounds. To do this, specify one or more values for the background-blend-mode property. That's right: You can stack multiple blend modes, one per background, to achieve layered effects.
.element {
background: url("..."), url("..."), hotpink;
background-blend-mode: multiply, lighten, normal;
}
And this is all you need to use blend modes in the browser of your choice!
Fun with Color Spaces
Unless...
Yup, sorry to disappoint, there's a catch. It turns out blend modes in the browser have a tiny detail that will make your life miserable if you rely on getting exact results. To explain, let's overlap two colored circles, a fully red one and a fully green one. We'll apply the darken blend mode, which we know takes the minimum for each channel.
By the maths alone, we should end up with the value for the overlapping area, so we expect to see black. But if you're reading this in Chrome or Safari on a MacBook manufactured after 2016, then you will see... brown? What??
The reason this happens is that blend modes are applied in the color space of the user's display. CSS colors are specified in sRGB by default, so if your display matches that, great! All the calculations should be spot on. But some displays – like modern MacBooks – actually support a wider color space called Display P3, which can represent more colors than sRGB. So when we specify our colors in sRGB, the browser first needs to convert them to P3.
This conversion is where things go wrong. sRGB isn't mapped linearly to Display P3; instead, the sRGB color space is kind of oddly embedded inside the P3 color space. Try it yourself by exploring what pure red, green and blue become in P3:
(1.000, 0.000, 0.000)(0.917, 0.200, 0.139)As you can see, in P3, our colors are super odd, for example, pure green in sRGB becomes in P3. This messes up our calculations quite a bit, because when we were expecting to multiply by , we were actually multiplying by numbers which are almost . To make matters worse, Firefox performs blending in sRGB regardless of the display's color space, so you will actually see different results in different browsers!
For most instances in which we use blend modes for stylistic purposes only, this isn't that big of a deal. But if you need precision, you can specify P3 colors directly to make sure the browser doesn't need to convert. To do this, you can use the CSS color() function. To get full green, you would then use:
background-color: color(display-p3 0 1 0);
This way, the calculations end up being correct, and you get properly mixed colors even in the P3 space. Yay!
Isolation
When we use blend modes in CSS, we may sometimes encounter a problem: We may want an element to blend with some elements of its backdrop, but not others. A good example is the classic RGB Venn Diagram:
In this diagram, we want the overlapping circles to blend with each other, but we most definitely don't want them to blend with the panel background! Lucky for us, CSS has a solution in the form of stacking contexts. Just when I thought this guy was wrapping up, he opens yet another can of worms...
On a high level, stacking contexts group some DOM elements together, and they come with an important property: only elements in the same context can be blended. This means that if we can create a new stacking context which groups the elements making up our Venn diagram from above, these elements would not blend with anything outside of the stacking context (e.g. the panel background). Awesome!
We can manually create a new stacking context by setting the isolation property to isolate (instead of its default value of auto). The element on which we set this will be part of the stacking context, so we need to make sure it does not have a background on it.
Unfortunately for us, there are many other properties in CSS which implicitly create a new stacking context, like the opacity property. But instead of digging into that here, I will leave it to the wonderful Josh Comeau, who has already perfectly captured the weird footguns of stacking contexts here.
Thanks Josh!
Real world applications
This is the section of the post that I believe is the trickiest. I was primarily motivated to write this post because I wanted to understand what was going on under the hood of blend modes, not because I use them particularly often. That said, there have been some instances where they came in really handy, and I want to highlight those here!
Image Text
A scenario I've seen quite often is the need to put some text on top of an image. The common solution to this problem is to make the text semi-transparent, but that only darkens or brightens the area where the text sits, which can look a bit dull. Blend modes can help in this case by selectively merging the text and image while retaining the underlying colors. Specifically, the overlay blend mode is incredibly well suited for this!
Try it yourself by toggling between a solid, semi-transparent and blended text on the following image:

In this case I have also added a crisp text shadow for a cutout 3D effect! This method will work best for big, bold text, so it's certainly not for every scenario. But it's a nice trick to have up your sleeve when you need it.
Image effects
It turns out that blend modes aren't only useful for text: You can also combine one or more layers with blend modes to create fun effects on images using only CSS.
For example, by using both the lighten and darken blend modes so that bright areas get darkened to one color, and dark areas get lightened to another color, we can introduce two separate colors into an image to create a duotone effect:

I've first seen this done by Una Kravets, who also has an amazing collection of other blend mode image effects on her website (search for "CSS Image Effects").
Such image effects can be really powerful in cases where you have a number of images, maybe even in different styles or lighting conditions, and want to align them with the look and feel of the website they are embedded in. It doesn't have to be as drastic of an effect as we've done here, but some small effects can go a long way to unify the style of different images.
Odd shaped borders
In CSS, round and square outlines are rather easy to get, but for anything more involved, we have to resort to some tricks. Take the following message bubble, which may be familiar to you from iOS, for example. How would you add a border or a ring to this shape?
Of course we could cheat a bit and just use SVG for the whole thing, but we want the main bubble to be an HTML element. For the little corner effect, we use a small SVG. But if we add rings to both of these elements, one always overlaps the other. You can see what I mean a bit easier in the following example with two circles:
When we add blending using the lighten blend mode to the circle on top however, the dark border that overlaps the back circle will disappear, leaving us with one continuous outline. Because borders and outlines are almost always consistently lighter or consistently darker than the shapes that they surround, this is a great technique for any outline. Pretty neat, huh? Let's apply it to our message bubble:
In a real world scenario, you would likely choose a less... bold border style. But for our demo purposes, this is great! A common case where this approach is useful is when styling tooltip arrows.
I don't think I've ever seen this technique used anywhere, so maybe it is quite novel. I hope you find it useful!
Blobs and fun effects
The last example I want to show off makes use of more than just blend modes, it also quite heavily relies on filters, which we've not discussed in this post. I still want to show it because when I first saw it, I couldn't believe this was pure CSS!
This effect can be achieved by heavily blurring the element and increasing its contrast using filters, which results in a black blobby effect. Unless you specifically want a black blob though, this only gets you half way there. But by overlaying our desired image or color and then applying a lighten blend mode, we can force our own foreground onto the black blob.
I think this is a ridiculously creative approach! I'm not sure who first came up with this technique, but if you know, please reach out so I can credit them. There are many more creative effects that can be achieved by combining filters and blend modes in this way. For example, this effect I shared on Bluesky recently uses similar concepts. See if you can figure out how it works!
Endless possibilities
I'm sure there are a ton of cool things that can be done with blend modes which I didn't cover here. If you have a use case that you think is worth sharing, please tell me and I will include it here and attribute you!
Further reading
Thank you for coming this far, and I hope you've enjoyed my take on introducing compositing and blending. As always, there is more to learn, so to wrap things up, I want to share a few resources that I found useful which contain more information on the topic.
The math I've introduced in this post for compositing was a bit simplified: Browsers actually store colors using a format called premultiplied alpha, which has a bunch of benefits that we didn't touch on in this post. For a deeper dive into compositing that talks about this, as well as other topics like intermediate buffers or group opacity, Bartosz Ciechanowski's Alpha Compositing is a wonderful read!
If you want to learn more about the origins of compositing and combine it with a small history lesson, the original 1984 paper by Thomas Porter and Tom Duff is also worth looking at.
Lastly, for a more technical explanation of how your browser handles compositing and blending, the W3C specification is not as scary as it seems.