How to use SVG clipPath with Pattern via CSS clip-path property?

Viewed 1161

The initial SVG figure with pattern:

<svg width="200" height="200" viewBox="0 0 100 100">
  <defs>
    <pattern id="img-dotted-dots" x="0" y="0" height=".08" width="7.69%">
      <circle cx="2" cy="2" fill="white" r="0.8"></circle>
    </pattern>
    <mask id="img-dotted-mask">
      <rect width="100" height="100" fill="url(#img-dotted-dots)"></rect>
    </mask>
  </defs>
  <path d="M0 0 H 100 V 100 H 0 Z" mask="url(#img-dotted-mask)" fill="#1063B1"></path>
</svg>

Need to achieve:

One instance of the SVG figure with pattern for refferencing with CSS as clip-path.

I have tried to create SVG clipPath element and bind to CSS clip-path by this way

.figure {
  width: 300px;
  height: 300px;
  clip-path: url(#img-dotted-clip-path);
  background-color: #1063B1;
}
<div class="figure"></div>

<svg width="0" height="0" viewBox="0 0 100 100">
  <defs>
    <clipPath
      clipPathUnits="objectBoundingBox"
      id="img-dotted-clip-path"> 
        <pattern
        patternUnits="objectBoundingBox"
        patternContentUnits="objectBoundingBox"
        x="0" y="0" height="0.1" width="0.1">
        <circle cx="0" cy="0" fill="white" r="0.5"></circle>
      </pattern>
    </clipPath>
  </defs>
</svg>

Nothing happens. Expected result - the same as the previous snippet.

For comparing:

If I use SVG rect - CSS clip-path works. If pattern - doesn't

.figure {
  width: 300px;
  height: 300px;
  clip-path: url(#img-dotted-clip-path);
  background-color: #1063B1;
}
<div class="figure"></div>

<svg width="0" height="0" viewBox="0 0 100 100">
  <defs>
    <clipPath
      clipPathUnits="objectBoundingBox"
      id="img-dotted-clip-path"> 
        <rect width="1" height="1"></rect>
    </clipPath>
  </defs>
</svg>

2 Answers

You can recreate the same thing using mask combined with radial-gradient

.figure {
  width: 300px;
  height: 300px;
  background:linear-gradient(to right,red,#1063B1);  
                          /*radius here                           size here*/
  -webkit-mask:radial-gradient(3px, #fff 97%,transparent 100%) 0 0/20px 20px;
          mask:radial-gradient(3px, #fff 97%,transparent 100%) 0 0/20px 20px;
}


body {
  background:#f2f2f2;
}
<div class="figure"></div>

Or consider the SVG inside the mask property. Make sure to escape the # and correctly set the viewbox and width/height to have a perfect repeat

.figure {
  width: 300px;
  height: 300px;
  background:linear-gradient(to right,red,#1063B1);  
  -webkit-mask:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="200" height="192" viewBox="0 0 100 90"><defs><pattern id="img-dotted-dots" x="0" y="0" height=".08" width="7.69%"><circle cx="2" cy="2" fill="white" r="0.8"></circle></pattern><mask id="img-dotted-mask"><rect width="100" height="100" fill="url(%23img-dotted-dots)"></rect></mask></defs><path d="M0 0 H 100 V 100 H 0 Z" mask="url(%23img-dotted-mask)" fill="%231063B1"></path></svg>');
          mask:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="200" height="192" viewBox="0 0 100 90"><defs><pattern id="img-dotted-dots" x="0" y="0" height=".08" width="7.69%"><circle cx="2" cy="2" fill="white" r="0.8"></circle></pattern><mask id="img-dotted-mask"><rect width="100" height="100" fill="url(%23img-dotted-dots)"></rect></mask></defs><path d="M0 0 H 100 V 100 H 0 Z" mask="url(%23img-dotted-mask)" fill="%231063B1"></path></svg>');
}


body {
  background:#f2f2f2;
}
<div class="figure"></div>

The only things that are valid inside a clip path are:

  • Shape elements (‘circle’, ‘ellipse’, ‘line’, ‘path’, ‘polygon’, ‘polyline’, ‘rect’)
  • ‘text’
  • ‘use’

Plus you can use animation elements etc to animate the clip path. However, only the shapes of those elements are used. Effects such as patterns, filters, etc are ignored.

The only way you could get the effect you want to work as a clipping path would be to add numerous <circle> elements to your <clipPath>.

<clipPath>
   <circle>
   <circle>
   <circle>
   <circle>
   ... etc ...
</clipPath>

But you could use a mask instead. Masks allow patterns.

.figure {
  width: 300px;
  height: 300px;
  -webkit-mask: url(#img-dotted-mask);
          mask: url(#img-dotted-mask);
  background-color: #1063B1;
}
<p>This only works in Firefox</p>

<div class="figure"></div>

<svg width="0" height="0">
  <defs>
    <pattern id="img-dotted-pattern"
      viewBox="0 0 1 1"
      patternUnits="userSpaceOnUse" x="0" y="0" width="20" height="20">
      <rect width="1" height="1" fill="black"/>
      <circle cx="0.5" cy="0.5" fill="white" r="0.15"></circle>
    </pattern>

    <mask id="img-dotted-mask">
      <rect width="2000" height="2000" fill="url(#img-dotted-pattern)"/>
    </mask>
  </defs>
</svg>

However inline SVG masks applied to HTML elements, like my example above, only work in Firefox. To get an SVG mask to work in Chrome, you would need to use mask or mask-image with an external or Data URL (as Temani has done in their answer).

Related