0

Background

I have a hover effect where two svgs mask to create a hole that the base image can be seen through on tiles of various sizes and dimensions. So far I've managed to mask the base rectangle with the custom path (there are multiple custom paths that can be chosen) but it's very rigid in that I have to try and set the viewBox to dimensions similar to size of the tile I'm testing on at that time, but then it doesn't fit the smaller one that might have a 16/9 aspect-ratio instead of a portrait one. I've also struggled to centre the inner SVG responsively, any CSS I seem to try to apply to it has no effect.

For instance I tried setting the x and y values of the custom path to 50% then add a transform: translate(-50%, -50%); but it only took the x and y inline values into consideration.

The Code

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 1600">
     <defs>
          <mask id="organic_1_mask" x="0" y="0" width="100%" height="100%" >
               <rect width="100%" height="100%" x="0" y="0" fill="white"/>
               <svg x="15%" y="25%" overflow="visible">
                    <path d="m-.56,898.39c0,165.39,134.08,299.46,299.47,299.46s299.46-134.07,299.46-299.46c0,165.39,134.07,299.46,299.46,299.46s299.47-134.07,299.47-299.46-134.07-299.46-299.47-299.46c165.39,0,299.47-134.07,299.47-299.46S1063.22,0,897.83,0s-299.46,134.07-299.46,299.46C598.37,134.07,464.3,0,298.91,0S-.56,134.07-.56,299.46s134.08,299.46,299.47,299.46C133.52,598.93-.56,733-.56,898.39Z"/>
               </svg>
          </mask>
     </defs>
     <rect width="100%" height="100%" x="0" y="0" fill="' . $overlay_colour . '" mask="url(#organic_1_mask)"></rect>
</svg>

The above code is one of a few different SVG paths I have that can be chosen to created the 'cut-out' effect, it uses a base <rect> to create the colour background and then the custom SVG path to mask through it. I end up with the SVG mostly not sizing up correctly to the parent container then once it is, it's a nightmare to responsively centre the inner SVG. I've added an image below so you can see how it currently displays on an example tile.

enter image description here

I've thought about maybe trying to generate the viewBox dimensions via JS but it's more of a last resort to save on load times, open to any ideas that might achieve the same effect where a custom SVG shape can be picked and 'cut through' a background colour.

Broken Inline Code

<div class="cut-out-shape" style="background: url(<?= the_post_thumbnail_url(); ?>);-webkit-mask-image: url('data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" width="200" height="200" viewBox="0 0 1200 1200"%3E%3Cpath d="m-.56,898.39c0,165.39,134.08,299.46,299.47,299.46s299.46-134.07,299.46-299.46c0,165.39,134.07,299.46,299.46,299.46s299.47-134.07,299.47-299.46-134.07-299.46-299.47-299.46c165.39,0,299.47-134.07,299.47-299.46S1063.22,0,897.83,0s-299.46,134.07-299.46,299.46C598.37,134.07,464.3,0,298.91,0S-.56,134.07-.56,299.46s134.08,299.46,299.47,299.46C133.52,598.93-.56,733-.56,898.39Z" fill="black"/%3E%3C/svg%3E');
                                mask-image: url('data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" width="200" height="200" viewBox="0 0 1200 1200"%3E%3Cpath d="m-.56,898.39c0,165.39,134.08,299.46,299.47,299.46s299.46-134.07,299.46-299.46c0,165.39,134.07,299.46,299.46,299.46s299.47-134.07,299.47-299.46-134.07-299.46-299.47-299.46c165.39,0,299.47-134.07,299.47-299.46S1063.22,0,897.83,0s-299.46,134.07-299.46,299.46C598.37,134.07,464.3,0,298.91,0S-.56,134.07-.56,299.46s134.08,299.46,299.47,299.46C133.52,598.93-.56,733-.56,898.39Z" fill="black"/%3E%3C/svg%3E');">
Sam St Aubyn
  • 127
  • 1
  • 9

1 Answers1

1

Perhaps you can give mask-image CSS property a try which allows you to cut-out an image using images such as SVG:

.wrapper {
  width: 200px;
  height: 200px;
  background: yellow;
  margin-bottom: 10px;
}

.cat {
  background-image: url('http://placekitten.com/200/200');
  width: 200px;
  height: 200px;
  background-size: cover;
  background-position: center;
  -webkit-mask-image:
    radial-gradient(circle at 35% 35%, black 0%, black 16.6%, transparent 16.6%),
    radial-gradient(circle at 65% 35%, black 0%, black 16.6%, transparent 16.6%),
    radial-gradient(circle at 35% 65%, black 0%, black 16.6%, transparent 16.6%),
    radial-gradient(circle at 65% 65%, black 0%, black 16.6%, transparent 16.6%),
    radial-gradient(circle at 50% 50%, black 0%, black 16%, transparent 16%);
  mask-image:
    radial-gradient(circle at 35% 35%, black 0%, black 16.6%, transparent 16.6%),
    radial-gradient(circle at 65% 35%, black 0%, black 16.6%, transparent 16.6%),
    radial-gradient(circle at 35% 65%, black 0%, black 16.6%, transparent 16.6%),
    radial-gradient(circle at 65% 65%, black 0%, black 16.6%, transparent 16.6%),
    radial-gradient(circle at 50% 50%, black 0%, black 16%, transparent 16%);
}
<div class="wrapper"><div class="cat"></div></div>
<div class="wrapper"><div class="cat" style="-webkit-mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22200%22%20height%3D%22200%22%20viewBox%3D%220%200%201200%201200%22%3E%3Cpath%20d%3D%22m-.56%2C898.39c0%2C165.39%2C134.08%2C299.46%2C299.47%2C299.46s299.46-134.07%2C299.46-299.46c0%2C165.39%2C134.07%2C299.46%2C299.46%2C299.46s299.47-134.07%2C299.47-299.46-134.07-299.46-299.47-299.46c165.39%2C0%2C299.47-134.07%2C299.47-299.46S1063.22%2C0%2C897.83%2C0s-299.46%2C134.07-299.46%2C299.46C598.37%2C134.07%2C464.3%2C0%2C298.91%2C0S-.56%2C134.07-.56%2C299.46s134.08%2C299.46%2C299.47%2C299.46C133.52%2C598.93-.56%2C733-.56%2C898.39Z%22%20fill%3D%22black%22%2F%3E%3C%2Fsvg%3E'); mask-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22200%22%20height%3D%22200%22%20viewBox%3D%220%200%201200%201200%22%3E%3Cpath%20d%3D%22m-.56%2C898.39c0%2C165.39%2C134.08%2C299.46%2C299.47%2C299.46s299.46-134.07%2C299.46-299.46c0%2C165.39%2C134.07%2C299.46%2C299.46%2C299.46s299.47-134.07%2C299.47-299.46-134.07-299.46-299.47-299.46c165.39%2C0%2C299.47-134.07%2C299.47-299.46S1063.22%2C0%2C897.83%2C0s-299.46%2C134.07-299.46%2C299.46C598.37%2C134.07%2C464.3%2C0%2C298.91%2C0S-.56%2C134.07-.56%2C299.46s134.08%2C299.46%2C299.47%2C299.46C133.52%2C598.93-.56%2C733-.56%2C898.39Z%22%20fill%3D%22black%22%2F%3E%3C%2Fsvg%3E')"></div></div>

(Here I used data URI but you can do the same with external SVG files, just replace the url() to your own url(path/to/svg.svg))

To generate a Data URI, you can use URL encoding tools, then append your generated result with data:image/svg+xml,

AngYC
  • 3,051
  • 6
  • 20
  • the issue is I need the inverted view of this, so I need the whole of the outside to be one colour and then see the image through it if that's possible. – Sam St Aubyn Apr 27 '23 at 11:58
  • Hi @SamStAubyn, both are the same, you just need to add another layer of wrapper (answer updated to include it) – AngYC Apr 27 '23 at 12:02
  • This is really helpful thankyou, let me give it a go! – Sam St Aubyn Apr 27 '23 at 12:12
  • how do I convert my SVG's into the same format as you have there? I've tried echoing them out after using this tool (https://yoksel.github.io/url-encoder/) to convert them but it just gets caught up on all of the quote marks – Sam St Aubyn Apr 27 '23 at 13:10
  • Hi @SamStAubyn, that link you have provided is exactly the one I am using, try to change the "External quotes" type to `single` to make it work. Alternatively, you can save it to a `.svg` file and import it directly like `url(svg.svg)` – AngYC Apr 27 '23 at 13:11
  • the code it's generating is just breaking, not sure what I'm doing differently here - I've posted the output code in the next comment down otherwise it breaks the character limit – Sam St Aubyn Apr 27 '23 at 13:37
  • background-image: url('data:image/svg+xml,%3Csvg id="organic_1" width="50%25" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 1200"%3E%3Cpath d="m-.56,898.39c0,165.39,134.08,299.46,299.47,299.46s299.46-134.07,299.46-299.46c0,165.39,134.07,299.46,299.46,299.46s299.47-134.07,299.47-299.46-134.07-299.46-299.47-299.46c165.39,0,299.47-134.07,299.47-299.46S1063.22,0,897.83,0s-299.46,134.07-299.46,299.46C598.37,134.07,464.3,0,298.91,0S-.56,134.07-.56,299.46s134.08,299.46,299.47,299.46C133.52,598.93-.56,733-.56,898.39Z"/%3E'); – Sam St Aubyn Apr 27 '23 at 13:37
  • Realsied this has output it in double quotes, I have been using single quotes – Sam St Aubyn Apr 27 '23 at 13:38
  • Hi @SamStAubyn, it seems like your SVG isn't correct (The `` isn't closed properly). In addition, the fill of the path must be `black` in order for `mask-image` to work. I have added your SVG into the answer above, press "Run code snippet" to see it working – AngYC Apr 27 '23 at 13:43
  • I've copied and pasted your code into mine (bearing in mind that mine is inline as I can't pass the shape variable into my scss file) and it's still not working correctly, see the full code below – Sam St Aubyn Apr 27 '23 at 13:48
  • Sorry see my code snippet above... – Sam St Aubyn Apr 27 '23 at 13:49
  • Hi @SamStAubyn, I have edited my code again using inline CSS now, it should work fine since the generated data URI will not have quotes now – AngYC Apr 27 '23 at 13:55
  • thanks so much I've finally got this working! Is there a tool for translating the basic SVG's into this format you used? – Sam St Aubyn Apr 27 '23 at 15:26
  • 1
    Hi @SamStAubyn, in the case of PHP, you can make use of [`urlencode` method](https://www.php.net/manual/en/function.urlencode.php). For JavaScript, you can make use of [encodeURIComponent() method](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent). For one-time usage, you can make use of the [tool](https://www.browserling.com/tools/url-encode) in the last paragraph of my answer above. Remember to also add `data:image/svg+xml,` in front of the converted code – AngYC Apr 27 '23 at 15:38