CSS: adventures in the land of translucency

Recently I was asked to correct one landing page. Among what I found in his code was an image on top of which two translucent elements overlapping it were located. Both with the same RGB color values โ€‹โ€‹in the property background-color. It looked something like this:

<img src='myImage.jpg'/>
<div class='over1'></div>
<div class='over2'></div>

There was no need to use two such elements. This could be needed unless due to the fact that only one such element did not sufficiently tint the image. For some reason, the author of the page decided that adding another translucent element superimposed on the image was better than increasing the value of the opacityfirst parameter . As a result, I decided to get rid of one of the layers and set the parameter of the remaining one so that the external image looked the same as the previous one. All this is good, but the question arose: how to adjust the parameter of the remaining element so that the result is the same as when applying two translucent layers?



opacityopacity

If you read this my article on the composition of masks, then you may have already guessed how to choose the appropriate value. After all, the same formula is used here, which was used there for the composition of translucent elements using mask-composite: add. If there are two layers with transparency values โ€‹โ€‹equal to a0and a1, then the value of the resulting indicator is calculated as follows:

a0 + a1 - a0*a1

Here you can find an interactive demo, looking at which you can compare how the image looks, toned with two layers, the properties of opacitywhich ( a0and a1) can be controlled with the help of sliders, and the same image toned by a layer property opacitywhich is calculated according to the formula a0 + a1 โ€” a0*a1.


The options for tinting an image, two copies of which are displayed next to each other.

It is interesting that the areas in which two translucent elements are located, and one such element, look the same if the image below them is not displayed (you can disable the image output using the checkbox located at the bottom of the screen). But if an image is displayed under these layers, then its two options are slightly different. Perhaps this difference is just the result of optical illusion, maybe some parts of the images seem lighter or darker to me than they really are.

They definitely do not look different if you do not display them next to each other, but simply switch between two layers whose property valuesopacityare equal toa0anda1, and one layer, the value of opacitywhich is found by the formula a0 + a1 โ€” a0*a1. Here is a relevant example.


Variants of image tinting with the ability to switch between one and two translucent layers.

This example can be extended to more layers. In this case, first calculate the transparency of the new layer, equivalent to the transparency of the two lower layers. Then find the transparency of the layer, equivalent to the transparency of the new layer, and the layer immediately above it. This operation is repeated until all layers have been processed.


Reducing several translucent layers to one layer

Similar experiments made me think about how to calculate the parameters of an opaque background image, which is equivalent to an opaque layer (c0) and a translucent layer superimposed on it (c1whose transparency is set toa). In this case, the final image, which is a single layer, can be found by processing the original image channel by channel, while the color values โ€‹โ€‹of the resulting channels are calculated by the following formula:

ch0 + (ch1 - ch0)*a

Here ch0is the channel of the opaque lower layer ( red, greenor blue- for red, green and blue colors), ch1is the corresponding channel of the upper translucent layer, and the indicator ais an indicator that sets the transparency of the same translucent layer.

If you express these arguments in the form of SCSS-code, you get the following:

/*       */
@function res-ch($ch0, $ch1, $a) {
  @return $ch0 + ($ch1 - $ch0)*$a
}

@function res-col($c0, $c1, $a) {
  $ch: 'red' 'green' 'blue'; /*   */
  $nc: length($ch); /*   */
  $ch-list: ();

  @for $i from 0 to $nc {
    $fn: nth($ch, $i + 1);
    $ch-list: $ch-list, 
      res-ch(call($fn, $c0), call($fn, $c1), $a);
  }

  @return RGB($ch-list)
}

Here is an interactive example. By experimenting with it, you can compare how the two layers look and their equivalent, presented as a single layer. Here you can select the RGB color values โ€‹โ€‹of two layers, as well as the transparency level of the second layer.


Results of applying a translucent layer to an opaque layer

Depending on the device, operating system and browser, you will see that the color panels in this example look the same ... or not. The formula is correct, but how exactly the two source layers are processed in different environments may vary.


The left part of the image is the expected result of reducing two layers to one. The right side shows how, when two layers are combined (from the upper right part of the image), the layer shown at the bottom right can look different than expected.

I asked Twitter users to send me screenshots made using the simplified test version of this example. Judging by the feedback I received, it seems that the two panels always look the same in mobile browsers (both Android and iOS), as well as in the Firefox browser, regardless of the operating system. Almost always, panels look the same on Windows, although I got answers indicating that Chrome and Chromium Edge sometimes render panels differently than expected.

If we talk about WebKit-based browsers running on macOS and Linux, it can be noted that the results are very heterogeneous. In most cases, the color of the panels is slightly different. But using the sRGB color profile helps make the panels look the same. The most interesting thing begins if this example is considered in a system that uses two monitors. Dragging a window from one monitor to another can lead to the fact that the difference between the panels is either visible or not visible.

It should be noted that in real scenarios the difference is very small, and that a pair of such panels is unlikely to be next to each other. But even if there is a difference, no one will know about it until he tests the page in different environments. In any case, only a web developer can probably do this. In addition, there is a feeling that the colors of ordinary opaque elements can also look different when using different devices, operating systems and browsers. For example, the color #ffa800, which is widely used on css-tricks.com, looks different on my laptops with Ubuntu and Windows. But after all, the eyes of different people can perceive the same colors in different ways.

Dear readers! Have you encountered problems with different browsers, operating systems or devices displaying different colors of web pages?


All Articles