Can i create a scss gradient from black to transparent with a noise texture?

66 Views Asked by At

I found this old thread on how to create noise gradients, but it doesn't properly fade to transparent which creates a hard border effect. I was wondering if it was possible to have only the gradient be noisy, not the transparency in the end.

Here is what I tried so far:

.black-bar {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100px;
    background-size: cover;
    background-position: center;
    background-repeat: repeat;
    stop-color: black;
    background-image: linear-gradient(to bottom,
            rgba(0, 0, 0, 1) 0%,
            rgba(0, 0, 0, 1) 50%,
            rgba(0, 0, 0, 0) 100%),
            url('/noise.svg');
    z-index: -1;  
}
<svg viewBox='0 0 250 250' xmlns='http://www.w3.org/2000/svg'>
  <filter id='noiseFilter'>
    <feTurbulence 
      type='fractalNoise' 
      baseFrequency='5' 
      numOctaves='3' 
      stitchTiles='stitch'/>
  </filter>
  
  <rect width='100%' height='100%' filter='url(#noiseFilter)'/>
</svg>

And here is the border effect I'm talking about:

Hard border effect I don't want

Noisy gradient I'm looking for (Mockup created in Photoshop)

2

There are 2 best solutions below

0
Rasmus On BEST ANSWER

I found the solution. Inverting the noise while fading itself to transparent while applying it after the gradient seemed to create the transition I'm looking for. Here is the scss

.black-bar {
    position: absolute;
    width: 100%;
    height: 300px;
    background: linear-gradient(180deg, 
        rgba(0,0,0,1) 0%,
        rgba(0,0,0,1) 20%,
        rgba(0, 0, 0, 0) 100%);
    z-index: 1;
}

.black-bar::after {
    content: '';
    position: absolute; 
    width: 100%;
    height: 100%;
    background: url('/noise.svg');
    filter: contrast(200%) brightness(100%) invert(100%) saturate(0%);
    mask-image: linear-gradient(180deg, 
        rgba(0,0,0,0) 0%,
        rgba(0,0,0,.3) 40%,
        rgba(0,0,0,0) 100%);
    z-index: -1;
}

And here is the final result

2
chrwahl On

I don't get the requirements 100%, but is it something like this. The SVG has a rectangle with both a filter and a mask. The mask creates the gradient. Therefore the noise filter is not visible in the transparent part of the rectangle. The part I don't get is the black color. Should the gradient cover the black?

.black-bar {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100px;
  background-size: contain;
  background-position: center;
  background-repeat: repeat;
  background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICA8ZGVmcz4KICA8ZmlsdGVyIGlkPSJub2lzZUZpbHRlciI+CiAgICA8ZmVUdXJidWxlbmNlIAogICAgICB0eXBlPSJmcmFjdGFsTm9pc2UiCiAgICAgIGJhc2VGcmVxdWVuY3k9Ii40IiAKICAgICAgbnVtT2N0YXZlcz0iLjQiIAogICAgICBzdGl0Y2hUaWxlcz0ic3RpdGNoIiAvPgogIDwvZmlsdGVyPgogIDxsaW5lYXJHcmFkaWVudCBpZD0ibGcwMSIgZ3JhZGllbnRUcmFuc2Zvcm09InJvdGF0ZSg5MCkiPgogICAgPHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1vcGFjaXR5PSIxIiBzdG9wLWNvbG9yPSJ3aGl0ZSIgLz4KICAgIDxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1vcGFjaXR5PSIwIiBzdG9wLWNvbG9yPSJ3aGl0ZSIgLz4KICA8L2xpbmVhckdyYWRpZW50PgogIDxtYXNrIGlkPSJtMDEiPgogICAgPHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0idXJsKCNsZzAxKSIvPgogIDwvbWFzaz4KICA8L2RlZnM+CiAgPHJlY3Qgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgbWFzaz0idXJsKCNtMDEpIiBmaWx0ZXI9InVybCgjbm9pc2VGaWx0ZXIpIi8+Cjwvc3ZnPg==');
  z-index: -1;
}
<div class="black-bar"></div>

<p>The SVG used as background image:</p>
<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg">
  <defs>
  <filter id="noiseFilter">
    <feTurbulence 
      type="fractalNoise"
      baseFrequency=".4" 
      numOctaves=".4" 
      stitchTiles="stitch" />
  </filter>
  <linearGradient id="lg01" gradientTransform="rotate(90)">
    <stop offset="0%" stop-opacity="1" stop-color="white" />
    <stop offset="100%" stop-opacity="0" stop-color="white" />
  </linearGradient>
  <mask id="m01">
    <rect width="100%" height="100%" fill="url(#lg01)"/>
  </mask>
  </defs>
  <rect width="100%" height="100%" mask="url(#m01)" filter="url(#noiseFilter)"/>
</svg>

Second attempt

Maybe this is more like it. The filter is now part of the mask. And the mask is going from white to black with a opaque (.5) part in the middle. The opaque part will make the filter visible. The mask is applied to a black rectangle making the top black and the bottom transparent.

I made a SVG for the content of the page, so it looks more like your mock-up.

This is the SVG that is used at a background image in the CSS:

<?xml version="1.0" encoding="utf-8"?>
<svg width="10000" height="400" xmlns="http://www.w3.org/2000/svg">
  <defs>
    <filter id="noiseFilter">
      <feTurbulence type="fractalNoise"
        stitchTiles="stitch"
        numOctaves="4"
        baseFrequency=".2"
        result="turbulence" />
      <feDisplacementMap
        in="turbulence"
        scale="2000" />
    </filter>
    <linearGradient id="lg01" gradientTransform="rotate(90)">
      <stop offset="0%" stop-opacity="1" stop-color="white" />
      <stop offset="20%" stop-opacity="1" stop-color="white" />
      <stop offset="60%" stop-opacity=".5" stop-color="black" />
      <stop offset="90%" stop-opacity="1" stop-color="black" />
    </linearGradient>
    <mask id="m01">
      <rect width="100%" height="100%" filter="url(#noiseFilter)"/>
      <rect width="100%" height="100%" fill="url(#lg01)" />
    </mask>
  </defs>
  <rect width="100%" height="100%" mask="url(#m01)" fill="black"/>
</svg>

body {
  background-color: #a2d6e9;
}

.black-bar {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 400px;
  background-repeat: repeat-x;
  background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB3aWR0aD0iMTAwMDAiIGhlaWdodD0iNDAwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgogIDxkZWZzPgogICAgPGZpbHRlciBpZD0ibm9pc2VGaWx0ZXIiPgogICAgICA8ZmVUdXJidWxlbmNlIHR5cGU9ImZyYWN0YWxOb2lzZSIKICAgICAgICBzdGl0Y2hUaWxlcz0ic3RpdGNoIgogICAgICAgIG51bU9jdGF2ZXM9IjQiCiAgICAgICAgYmFzZUZyZXF1ZW5jeT0iLjIiCiAgICAgICAgcmVzdWx0PSJ0dXJidWxlbmNlIiAvPgogICAgICA8ZmVEaXNwbGFjZW1lbnRNYXAKICAgICAgICBpbj0idHVyYnVsZW5jZSIKICAgICAgICBzY2FsZT0iMjAwMCIgLz4KICAgIDwvZmlsdGVyPgogICAgPGxpbmVhckdyYWRpZW50IGlkPSJsZzAxIiBncmFkaWVudFRyYW5zZm9ybT0icm90YXRlKDkwKSI+CiAgICAgIDxzdG9wIG9mZnNldD0iMCUiIHN0b3Atb3BhY2l0eT0iMSIgc3RvcC1jb2xvcj0id2hpdGUiIC8+CiAgICAgIDxzdG9wIG9mZnNldD0iMjAlIiBzdG9wLW9wYWNpdHk9IjEiIHN0b3AtY29sb3I9IndoaXRlIiAvPgogICAgICA8c3RvcCBvZmZzZXQ9IjYwJSIgc3RvcC1vcGFjaXR5PSIuNSIgc3RvcC1jb2xvcj0iYmxhY2siIC8+CiAgICAgIDxzdG9wIG9mZnNldD0iOTAlIiBzdG9wLW9wYWNpdHk9IjEiIHN0b3AtY29sb3I9ImJsYWNrIiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxtYXNrIGlkPSJtMDEiPgogICAgICA8cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWx0ZXI9InVybCgjbm9pc2VGaWx0ZXIpIi8+CiAgICAgIDxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjbGcwMSkiIC8+CiAgICA8L21hc2s+CiAgPC9kZWZzPgogIDxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIG1hc2s9InVybCgjbTAxKSIgZmlsbD0iYmxhY2siLz4KPC9zdmc+');
  z-index: 1;
}
<div class="black-bar"></div>
<svg viewBox="0 0 100 50" height="400" xmlns="http://www.w3.org/2000/svg">
  <defs>
    <linearGradient id="lg01" gradientTransform="rotate(90)">
      <stop offset="0%" stop-opacity="0" stop-color="black" />
      <stop offset="80%" stop-opacity="1" stop-color="black" />
    </linearGradient>
    <mask id="m01">
      <circle cx="20" cy="25" r="15" fill="white"/>
      <circle cx="40" cy="35" r="15" fill="white"/>
      <rect width="100" height="50" fill="url(#lg01)" />
      <path d="M 0 0 L -0.5 30 c 0 2 1 2 1 0 Z" transform="translate(10 -10)" fill="white" opacity=".8" />
      <path d="M 0 0 L -0.5 30 c 0 2 1 2 1 0 Z" transform="translate(20 0)" fill="white" opacity=".8" />
      <path d="M 0 0 L -0.5 30 c 0 2 1 2 1 0 Z" transform="translate(30 10)" fill="white" opacity=".8" />
      <path d="M 0 0 L -0.5 30 c 0 2 1 2 1 0 Z" transform="translate(80 10)" fill="white" opacity=".8" />
    </mask>
  </defs>
  <rect width="100" height="50" fill="white" mask="url(#m01)" />
</svg>