<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Riccardo Mario Battiato</title>
    <description>The latest articles on DEV Community by Riccardo Mario Battiato (@riccardobattiato).</description>
    <link>https://dev.to/riccardobattiato</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2797111%2F5e7c38f1-bc08-4ea9-93f1-f834f36e5cbb.jpeg</url>
      <title>DEV Community: Riccardo Mario Battiato</title>
      <link>https://dev.to/riccardobattiato</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/riccardobattiato"/>
    <language>en</language>
    <item>
      <title>How to make mix-blend-mode round to black or white only</title>
      <dc:creator>Riccardo Mario Battiato</dc:creator>
      <pubDate>Fri, 31 Jan 2025 12:42:43 +0000</pubDate>
      <link>https://dev.to/riccardobattiato/how-to-make-mix-blend-mode-round-to-black-or-white-only-425b</link>
      <guid>https://dev.to/riccardobattiato/how-to-make-mix-blend-mode-round-to-black-or-white-only-425b</guid>
      <description>&lt;p&gt;One of the coolest CSS effects I know, used by many websites since when it started being supported by modern browsers, is the &lt;code&gt;mix-blend-mode: difference&lt;/code&gt; property. It's generally used on elements of sticky headers such as logos and text, since it creates a nice contrasting visual effect with the background below it as the user scrolls.&lt;/p&gt;

&lt;p&gt;However, one of the issues developers &lt;a href="https://www.reddit.com/r/css/comments/1542qf7/is_there_a_way_to_round_a_color_value_with/?utm_source=share&amp;amp;utm_medium=web3x&amp;amp;utm_name=web3xcss&amp;amp;utm_term=1&amp;amp;utm_content=share_button" rel="noopener noreferrer"&gt;experience&lt;/a&gt; &lt;a href="https://stackoverflow.com/q/67544643/29254483" rel="noopener noreferrer"&gt;the&lt;/a&gt; &lt;a href="https://discourse.webflow.com/t/mix-blend-mode-black-white/116734" rel="noopener noreferrer"&gt;most&lt;/a&gt; with the property is that you can't really control the colors that the &lt;code&gt;difference&lt;/code&gt; or &lt;code&gt;exclusion&lt;/code&gt; between the sticky elements and the background will produce. &lt;strong&gt;Specifically, how to make it so that &lt;code&gt;mix-blend-mode&lt;/code&gt; will display only black or white colors&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Today we'll see a &lt;strong&gt;pure CSS solution&lt;/strong&gt; to this known issue that uses a combination of backdrop and normal filters. &lt;em&gt;Note: the solution is currently only supported by Chromium-based browsers (Chrome, Edge, etc.).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/riccardobattiato/embed/PwYLGWd?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  CSS filters in action
&lt;/h2&gt;

&lt;p&gt;The key to the solution is simple: &lt;strong&gt;the same element which blends with the background, must set a grayscale and contrast filter&lt;/strong&gt;. The code responsible for the effect shown in the Pen above is as simple as the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.blending-element&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;mix-blend-mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;difference&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;backdrop-filter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;grayscale&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;contrast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="err"&gt;//&lt;/span&gt; &lt;span class="err"&gt;be&lt;/span&gt; &lt;span class="py"&gt;careful&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="n"&gt;matters&lt;/span&gt;&lt;span class="err"&gt;!&lt;/span&gt;
  &lt;span class="n"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;black&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Setting a background color isn't always required, but remember that &lt;strong&gt;in order for &lt;code&gt;mix-blend-mode&lt;/code&gt; to work, both the blending element and the background must have an actual color&lt;/strong&gt;. If your body looks &lt;code&gt;white&lt;/code&gt; but is really &lt;code&gt;transparent&lt;/code&gt;, there will be no colors to blend.&lt;/p&gt;

&lt;p&gt;Once &lt;code&gt;mix-blend-mode&lt;/code&gt; is set, you'll have the typical inverted-colors look: unless you have a perfectly black or white background, the blending element may show unwanted colors. This is where CSS filters come into action: &lt;strong&gt;grayscale&lt;/strong&gt; will force any color into a tint of black or white, while setting a really high &lt;strong&gt;contrast&lt;/strong&gt; value will "round" the grayscale tints to pure black or white.&lt;/p&gt;

&lt;p&gt;You may have noticed that we're using a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/backdrop-filter" rel="noopener noreferrer"&gt;&lt;strong&gt;backdrop-filter&lt;/strong&gt;&lt;/a&gt; rather than a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/filter" rel="noopener noreferrer"&gt;normal one&lt;/a&gt;. There are two reasons for this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;First, it's becauase moving the &lt;code&gt;grayscale(1)&lt;/code&gt; parameter to a normal, non-backdrop filter simply won't work. The solution is slightly hacky, and it needs for the backdrop to filter its colors to grayscale.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;contrast(/* really high value here */)&lt;/code&gt; on direct elements makes them look way worse. It's better to rely on the backdrop and let the &lt;code&gt;mix-blend-mode&lt;/code&gt; do its job on the actual element anyway.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Relying on &lt;code&gt;backdrop-filter&lt;/code&gt; has one issue: even if you have a transparent background behind your blending element, &lt;strong&gt;the rectangle behind it will look black or white too&lt;/strong&gt;. This is fine for rectangular elements such as the simple scroller inside the CodePen example, but not for complex shapes such as the &lt;a href="https://thenounproject.com/icon/planet-7302521/" rel="noopener noreferrer"&gt;planet logo&lt;/a&gt; from the &lt;a href="https://thenounproject.com/" rel="noopener noreferrer"&gt;Noun Project&lt;/a&gt; shown in the same example.&lt;/p&gt;

&lt;h2&gt;
  
  
  What about complex shapes?
&lt;/h2&gt;

&lt;p&gt;There's another really useful CSS property that will solve our problem: &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/clip-path" rel="noopener noreferrer"&gt;clip-path&lt;/a&gt;. Thanks to it, we're able to clip our visual page elements to simple shapes, custom polygons and &lt;strong&gt;custom SVG paths&lt;/strong&gt;. The latter is the most flexible approach and the one I like the most.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Get your complex shape and/or text as SVG code.&lt;/strong&gt; This could be an external file or an inline SVG such as in the example below.&lt;/li&gt;
&lt;li&gt;Move the paths and other elements inside a &lt;code&gt;&amp;lt;clipPath&amp;gt;&lt;/code&gt; definition element, as done below.&lt;/li&gt;
&lt;li&gt;Set an &lt;code&gt;id="..."&lt;/code&gt; for the &lt;code&gt;&amp;lt;clipPath&amp;gt;&lt;/code&gt; element: the CSS code will need to reach it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You should get something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;  &lt;span class="nt"&gt;&amp;lt;svg&lt;/span&gt; &lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/2000/svg"&lt;/span&gt; &lt;span class="na"&gt;version=&lt;/span&gt;&lt;span class="s"&gt;"1.1"&lt;/span&gt; &lt;span class="na"&gt;viewBox=&lt;/span&gt;&lt;span class="s"&gt;"-5.0 -10.0 110.0 135.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;defs&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;clipPath&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"complex-shape"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;path&lt;/span&gt; &lt;span class="na"&gt;d=&lt;/span&gt;&lt;span class="s"&gt;"m36.438 79.031c-2 1.5-3.9375 2.8438-5.75 4.0312-2.6289-1.5703-5.0547-3.4609-7.2188-5.625-9.4805-9.4805-13.18-23.293-9.7109-36.242 3.4688-12.949 13.582-23.062 26.531-26.531 12.949-3.4688 26.762 0.23047 36.242 9.7109 2.1719 2.1719 4.0625 4.6055 5.625 7.25-1.2188 1.8125-2.5312 3.7188-4.0312 5.7188-5.9023 7.9023-12.391 15.348-19.406 22.281-6.9336 7.0156-14.379 13.504-22.281 19.406zm26.625-15.062c-6.1797 6.207-12.723 12.039-19.594 17.469-2.125 1.6875-4.2188 3.25-6.2812 4.6875 8.9844 3.2617 18.875 2.9688 27.652-0.82031 8.7734-3.7891 15.77-10.785 19.559-19.562 3.7891-8.7734 4.082-18.664 0.82031-27.648-1.4688 2.0625-3.0312 4.1562-4.6562 6.25-5.4414 6.8828-11.285 13.434-17.5 19.625zm-38.25 22.719c-8.1875 4.6562-13.625 5.9062-15.062 4.4688s-0.1875-6.8438 4.4688-15.031c-1.3711-1.9453-2.5703-4.0078-3.5938-6.1562-6.9688 11.219-9.9062 20.844-5.2188 25.531 1.6641 1.5742 3.8984 2.3984 6.1875 2.2812 5.0938 0 11.906-2.8438 19.375-7.4688 2.0312-1.25 4.0938-2.6562 6.2188-4.1875-2.2695-0.78906-4.4453-1.8164-6.5-3.0625-2.0938 1.375-4.0625 2.5938-5.875 3.625zm69.781-80.375c-4.0938-4.0938-12.125-2.6562-23.844 4.25-0.53125 0.3125-1.0938 0.65625-1.625 1 2.1172 1.0117 4.1484 2.2031 6.0625 3.5625 3.9414-2.6719 8.4609-4.3672 13.188-4.9375 0.66016-0.058594 1.3203 0.10547 1.875 0.46875 1.4375 1.4375 0.1875 6.875-4.4688 15.062-1.0312 1.8438-2.25 3.8125-3.625 5.9062 1.2461 2.043 2.2734 4.2109 3.0625 6.4688 1.5-2.125 2.9062-4.2188 4.1562-6.25 6.9688-11.219 9.9062-20.844 5.2188-25.531z"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;text&lt;/span&gt; &lt;span class="na"&gt;x=&lt;/span&gt;&lt;span class="s"&gt;"0.0"&lt;/span&gt; &lt;span class="na"&gt;y=&lt;/span&gt;&lt;span class="s"&gt;"117.5"&lt;/span&gt; &lt;span class="na"&gt;font-size=&lt;/span&gt;&lt;span class="s"&gt;"5.0"&lt;/span&gt; &lt;span class="na"&gt;font-weight=&lt;/span&gt;&lt;span class="s"&gt;"bold"&lt;/span&gt; &lt;span class="na"&gt;font-family=&lt;/span&gt;&lt;span class="s"&gt;"Arbeit Regular, Helvetica, Arial-Unicode, Arial, Sans-serif"&lt;/span&gt; &lt;span class="na"&gt;fill=&lt;/span&gt;&lt;span class="s"&gt;"#000000"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Created
          by Ricons&lt;span class="nt"&gt;&amp;lt;/text&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;text&lt;/span&gt; &lt;span class="na"&gt;x=&lt;/span&gt;&lt;span class="s"&gt;"0.0"&lt;/span&gt; &lt;span class="na"&gt;y=&lt;/span&gt;&lt;span class="s"&gt;"122.5"&lt;/span&gt; &lt;span class="na"&gt;font-size=&lt;/span&gt;&lt;span class="s"&gt;"5.0"&lt;/span&gt; &lt;span class="na"&gt;font-weight=&lt;/span&gt;&lt;span class="s"&gt;"bold"&lt;/span&gt; &lt;span class="na"&gt;font-family=&lt;/span&gt;&lt;span class="s"&gt;"Arbeit Regular, Helvetica, Arial-Unicode, Arial, Sans-serif"&lt;/span&gt; &lt;span class="na"&gt;fill=&lt;/span&gt;&lt;span class="s"&gt;"#000000"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;from
          Noun Project&lt;span class="nt"&gt;&amp;lt;/text&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/clipPath&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/defs&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/svg&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Afterwards, you need to prepare a &lt;code&gt;&amp;lt;div /&amp;gt;&lt;/code&gt; or other element to be the one that will be clipped by your custom path. Personally, I like to reuse my SVG as an inline element in the page, both for providing the &lt;code&gt;&amp;lt;clipPath&amp;gt;&lt;/code&gt; definition &lt;em&gt;and&lt;/em&gt; for providing a visual element to clip.&lt;/p&gt;

&lt;p&gt;If you use an empty element or an SVG which doesn't display actual elements by itself (as in my example), remember to specify a width or height you're about to clip:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.complex-shape&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;6.875rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="err"&gt;//&lt;/span&gt; &lt;span class="py"&gt;Warning&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;this&lt;/span&gt; &lt;span class="n"&gt;has&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;be&lt;/span&gt; &lt;span class="n"&gt;really&lt;/span&gt; &lt;span class="n"&gt;precise&lt;/span&gt;&lt;span class="err"&gt;!&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the element is in page and has some dimensions, set the &lt;code&gt;clip-path&lt;/code&gt; property so that it references your SVG definition:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.complex-shape&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;6.875rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;clip-path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sx"&gt;url(#clipping-shape)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can make your black and white backdrop appear, and it will have the same shape or text from your SVG:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.complex-shape&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;6.875rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;clip-path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sx"&gt;url(#clipping-shape)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;mix-blend-mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;difference&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;backdrop-filter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;grayscale&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;contrast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="err"&gt;//&lt;/span&gt; &lt;span class="err"&gt;be&lt;/span&gt; &lt;span class="py"&gt;careful&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="n"&gt;matters&lt;/span&gt;&lt;span class="err"&gt;!&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Feel free to be creative with &lt;code&gt;clip-path&lt;/code&gt; — there are many ways to use it, and many other ways to provide a valid SVG &lt;code&gt;&amp;lt;clipPath&amp;gt;&lt;/code&gt; definition.&lt;/p&gt;

&lt;p&gt;Let me know if you have any improvements to this solution or find even easier ways to accomplish the effect!&lt;/p&gt;

</description>
      <category>codepen</category>
      <category>frontend</category>
      <category>css</category>
    </item>
  </channel>
</rss>
