Catalin Farcas
Catalin Farcas

Reputation: 655

How do I create a clipping mask for background?

On the first layer i have a the background image, then comes the blur(transparency) layer, and finaly i want a group of divs that makes this clean effect:

enter image description here

My Html is a bit too large to copy it here, but i just want an ideea or maybe a quick example of how can i do it if it's possible.

I know that one way is to make a single picture file like this, but i want to build it using CSS. I have tried to make the image relative, then blur div absolute and z-index -1 and the robs group absolute as well and z-index 1, and it's not working.

Upvotes: 1

Views: 865

Answers (3)

tao
tao

Reputation: 90113

Here's how I'd do this:

body {
  margin: 0;
}

[flex-container] {
  background: transparent url("https://images.unsplash.com/photo-1445251836269-d158eaa028a6?dpr=1&auto=format&fit=crop&w=1080&h=720&q=80&cs=tinysrgb&crop=&bg=") no-repeat 50% 50% / cover;
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

[flex-container] svg {
  max-width: 90vw;
  max-height: 90vh;
  height: auto;
  width: auto;
}

[flex-container] [flex-white] {
  flex-grow: 1;
  background-color: rgba(255, 255, 255, 0.35);
}

[flex-container] [center-flex] {
  flex-grow: 0;
  display: flex;
  max-height: 90vw;
}
<div flex-container>
  <div flex-white></div>
  <div center-flex>
    <div flex-white></div>
    <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 620 620" preserveAspectRatio="xMidYMid meet" height="620" width="620">
      <defs>
        <mask id="clip-path">
          <rect fill="white" x="0" y="0" width="620" height="620" />
          <path fill="black" d="M1.032193281120934,2.9326408166644313v-1.6000000000000005a2,2,0,0,0,-2,-2h-4a2,2,0,0,0,-2,2v4a2,2,0,0,0,2,2h4a2,2,0,0,0,2,-2Z" transform="matrix(17.8246 17.6867 -17.6867 17.8246 419.289 145.797)" />
          <path fill="black" d="M9.837478544552232,2.9766420664520377v-1.6000000000000005a2,2,0,0,0,-2,-2h-4a2,2,0,0,0,-2,2v4a2,2,0,0,0,2,2h4a2,2,0,0,0,2,-2Z" transform="matrix(17.8246 17.6867 -17.6867 17.8246 419.289 145.797)" />
          <path fill="black" d="M9.837478544552228,11.737917113101712v-1.6000000000000005a2,2,0,0,0,-2,-2h-4a2,2,0,0,0,-2,2v4a2,2,0,0,0,2,2h4a2,2,0,0,0,2,-2Z" transform="matrix(17.8246 17.6867 -17.6867 17.8246 419.289 145.797)" />
          <path fill="black" d="M1.032197869095377,11.693911484294599v-1.6000000000000005a2,2,0,0,0,-2,-2h-4a2,2,0,0,0,-2,2v4a2,2,0,0,0,2,2h4a2,2,0,0,0,2,-2Z" transform="matrix(17.8246 17.6867 -17.6867 17.8246 419.289 145.797)" />
        </mask>
      </defs>
      <rect mask="url(#clip-path)" x="0" y="0" width="620" height="620" fill="rgba(255,255,255,.35)" />
    </svg>
    <div flex-white></div>
  </div>
  <div flex-white></div>
</div>

For masking, you want to look inside the <svg>. If you don't like the paths I used, replace them. The only important rule in masks is: fills are white and holes are black.

The only problem is: if you stretch an svg across the viewport, it will end up distorted. To avoid that, I centered it in the viewport and wrapped it in flex containers that cover the remaining space, responsively.

Upvotes: 4

Kyle Becker
Kyle Becker

Reputation: 1440

This would be difficult with html and divs for reasons people have mentioned. However, I created a fiddle that accomplishes something similar with a canvas and some javascript.

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");

ctx.fillStyle = "rgba(255, 255, 255, 0.7)";
ctx.fillRect(0,0,512,512);
ctx.globalCompositeOperation = 'destination-out';
ctx.fillStyle = "rgba(255, 0, 0)";
ctx.beginPath();
ctx.moveTo(150,10);
ctx.lineTo(180,40);
ctx.lineTo(150, 70);
ctx.lineTo(120, 40);
ctx.closePath();
ctx.fill();
ctx.beginPath();
ctx.moveTo(190,50);
ctx.lineTo(220,80);
ctx.lineTo(190, 110);
ctx.lineTo(160, 80);
ctx.closePath();
ctx.fill();
ctx.beginPath();
ctx.moveTo(150,90);
ctx.lineTo(180,120);
ctx.lineTo(150, 150);
ctx.lineTo(120, 120);
ctx.closePath();
ctx.fill();
ctx.beginPath();
ctx.moveTo(110,50);
ctx.lineTo(140,80);
ctx.lineTo(110, 110);
ctx.lineTo(80, 80);
ctx.closePath();
ctx.fill();
.image-container {
    position: relative;
    width: 512px;
    height: 512px;
}
.image-container .after {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    display: none;
    color: #FFF;
}
.image-container .after {
    display: block;
    background: rgba(0, 0, 0, 0);
}
<div class="image-container">
    <img src="https://homepages.cae.wisc.edu/~ece533/images/baboon.png">
    <canvas class="after" id="myCanvas"></canvas>
</div>

Upvotes: 1

smilebomb
smilebomb

Reputation: 5483

To the best of my knowledge, a child element cannot have less opacity than it's parent element. i.e. if a parent is 50% "see through" than the child cannot be 100% "see through", it will at most be 50% see through as well.

I could be wrong, I just know I've run into this problem before and I never solved it myself.

I'm upvoting and patiently waiting for someone that knows more than me... but I believe this is the case.

Upvotes: -2

Related Questions