How to add border in my clip-path: polygon(); CSS style

Can border be applied to a clipped element along the clip path?

No, adding border property to the clipped element would not apply the borders along the clipped path because the border is applied to the original rectangle (or square) container before the clip-path is applied and so, it also gets clipped out. You can see this in the below snippet:

div {
  display: inline-block;
  height: 200px;
  width: 200px;
  border: 3px solid;
  background: darkseagreen;
}
div + div {
  -webkit-clip-path: polygon(50% 0%, 100% 100%, 100% 0%);
  clip-path: polygon(50% 0%, 100% 100%, 100% 0%);
}
<div></div>
<div></div>

Are there any alternate ways to create such a border effect?

We can mimic it by applying the same clip-path on a container element. The container element's background color will look as though it is the border of the inner element because both are clipped and the container has slightly higher dimensions than the inner element.

.poligon {
  display: inline-block;
  position: relative;
  width: 150px;
  height: 150px;
  background: red;
  box-sizing: border-box;
  -webkit-clip-path: polygon(92.32051% 40%, 93.79385% 43.1596%, 94.69616% 46.52704%, 95% 50%, 94.69616% 53.47296%, 93.79385% 56.8404%, 92.32051% 60%, 79.82051% 81.65064%, 77.82089% 84.50639%, 75.35575% 86.97152%, 72.5% 88.97114%, 69.3404% 90.44449%, 65.97296% 91.34679%, 62.5% 91.65064%, 37.5% 91.65064%, 34.02704% 91.34679%, 30.6596% 90.44449%, 27.5% 88.97114%, 24.64425% 86.97152%, 22.17911% 84.50639%, 20.17949% 81.65064%, 7.67949% 60%, 6.20615% 56.8404%, 5.30384% 53.47296%, 5% 50%, 5.30384% 46.52704%, 6.20615% 43.1596%, 7.67949% 40%, 20.17949% 18.34936%, 22.17911% 15.49361%, 24.64425% 13.02848%, 27.5% 11.02886%, 30.6596% 9.55551%, 34.02704% 8.65321%, 37.5% 8.34936%, 62.5% 8.34936%, 65.97296% 8.65321%, 69.3404% 9.55551%, 72.5% 11.02886%, 75.35575% 13.02848%, 77.82089% 15.49361%, 79.82051% 18.34936%);
  clip-path: polygon(92.32051% 40%, 93.79385% 43.1596%, 94.69616% 46.52704%, 95% 50%, 94.69616% 53.47296%, 93.79385% 56.8404%, 92.32051% 60%, 79.82051% 81.65064%, 77.82089% 84.50639%, 75.35575% 86.97152%, 72.5% 88.97114%, 69.3404% 90.44449%, 65.97296% 91.34679%, 62.5% 91.65064%, 37.5% 91.65064%, 34.02704% 91.34679%, 30.6596% 90.44449%, 27.5% 88.97114%, 24.64425% 86.97152%, 22.17911% 84.50639%, 20.17949% 81.65064%, 7.67949% 60%, 6.20615% 56.8404%, 5.30384% 53.47296%, 5% 50%, 5.30384% 46.52704%, 6.20615% 43.1596%, 7.67949% 40%, 20.17949% 18.34936%, 22.17911% 15.49361%, 24.64425% 13.02848%, 27.5% 11.02886%, 30.6596% 9.55551%, 34.02704% 8.65321%, 37.5% 8.34936%, 62.5% 8.34936%, 65.97296% 8.65321%, 69.3404% 9.55551%, 72.5% 11.02886%, 75.35575% 13.02848%, 77.82089% 15.49361%, 79.82051% 18.34936%);
}
.poligon img {
  position: absolute;
  top: 2px; /* equal to border thickness */
  left: 2px; /* equal to border thickness */
  width: 146px; /* container height - (border thickness * 2) */
  height: 146px; /* container height - (border thickness * 2) */
  -webkit-clip-path: polygon(92.32051% 40%, 93.79385% 43.1596%, 94.69616% 46.52704%, 95% 50%, 94.69616% 53.47296%, 93.79385% 56.8404%, 92.32051% 60%, 79.82051% 81.65064%, 77.82089% 84.50639%, 75.35575% 86.97152%, 72.5% 88.97114%, 69.3404% 90.44449%, 65.97296% 91.34679%, 62.5% 91.65064%, 37.5% 91.65064%, 34.02704% 91.34679%, 30.6596% 90.44449%, 27.5% 88.97114%, 24.64425% 86.97152%, 22.17911% 84.50639%, 20.17949% 81.65064%, 7.67949% 60%, 6.20615% 56.8404%, 5.30384% 53.47296%, 5% 50%, 5.30384% 46.52704%, 6.20615% 43.1596%, 7.67949% 40%, 20.17949% 18.34936%, 22.17911% 15.49361%, 24.64425% 13.02848%, 27.5% 11.02886%, 30.6596% 9.55551%, 34.02704% 8.65321%, 37.5% 8.34936%, 62.5% 8.34936%, 65.97296% 8.65321%, 69.3404% 9.55551%, 72.5% 11.02886%, 75.35575% 13.02848%, 77.82089% 15.49361%, 79.82051% 18.34936%);
  clip-path: polygon(92.32051% 40%, 93.79385% 43.1596%, 94.69616% 46.52704%, 95% 50%, 94.69616% 53.47296%, 93.79385% 56.8404%, 92.32051% 60%, 79.82051% 81.65064%, 77.82089% 84.50639%, 75.35575% 86.97152%, 72.5% 88.97114%, 69.3404% 90.44449%, 65.97296% 91.34679%, 62.5% 91.65064%, 37.5% 91.65064%, 34.02704% 91.34679%, 30.6596% 90.44449%, 27.5% 88.97114%, 24.64425% 86.97152%, 22.17911% 84.50639%, 20.17949% 81.65064%, 7.67949% 60%, 6.20615% 56.8404%, 5.30384% 53.47296%, 5% 50%, 5.30384% 46.52704%, 6.20615% 43.1596%, 7.67949% 40%, 20.17949% 18.34936%, 22.17911% 15.49361%, 24.64425% 13.02848%, 27.5% 11.02886%, 30.6596% 9.55551%, 34.02704% 8.65321%, 37.5% 8.34936%, 62.5% 8.34936%, 65.97296% 8.65321%, 69.3404% 9.55551%, 72.5% 11.02886%, 75.35575% 13.02848%, 77.82089% 15.49361%, 79.82051% 18.34936%);
}
<div class="poligon">
  <img src="https://picsum.photos/600/400">
</div>

Pseudo-Element

A nice way to do this would be with a pseudo-element like a ::before

Make exactly the same shape but slightly smaller which holds the main color you want and position it correctly and you get the border you want.

The below example isn't the correct shape but shows how to achieve this effect:

.shape {
  width: 400px;
  height: 40px;
  background-color: black;
  position: relative;
}
.shape:before {
  content: '';
  width: 398px;
  height: 38px;
  background: #00c000;
  display: block;
  position: absolute;
  top: 1px;
  left: 1px;
}
.shape, .shape:before {
  -webkit-clip-path: polygon(5% 0, 100% 0, 100% 100%, 0 100%, 0 100%);
  clip-path: polygon(5% 0, 100% 0, 100% 100%, 0 100%, 0 100%);
}
  
<div class="shape"></div>

Adding a Border to a Complex Clip Path With SVG Dilation Filter

Copy-Shrink Method Only Works In Simple Cases -- used in currently accepted answer

The currently accepted answer works by making a copy and shrinking it. This works for the example, but if you have a more complex shape (like text), it will not work. A better approach is to use dilation with a filter.

Shape Dilation Works on ANY Shape

A better approach is to use dilation with the feMorphology filter!!

  • SVG feMorphology Filter

Key aspects:

  • Create matching <image> and <rect> shapes of equal height and width
  • Clip both with the desired shape path/polygon
  • Use filter to dilate/enlarge the clipped rect to make a border

The filter radius= becomes the stand in for border thickness.

The result:

enter image description here

.clipper{
  clip-path: url(#clip_shape);
}
.dilate{
  filter: url("#dilate_shape");
}
<svg xmlns="http://www.w3.org/2000/svg" height="400" width="400">
 <defs>
  <clipPath id="clip_shape" clipPathUnits="objectBoundingBox">
    <text x="0" y=".8" lengthAdjust="spacing" font-weight="700" font-style="italic" font-size="1"> M </text>
  </clipPath>
   <filter id="dilate_shape">
      <feMorphology operator="dilate" in="SourceGraphic" radius="5" />
   </filter>
   
 </defs> 
 
 <g transform="translate(5,5)">
 <g class="dilate">
   <rect class="clipper" x=0 y=0 height="400px" width="400px" fill="lightgreen"></rect>
 </g>
 <image class="clipper" xlink:href="http://placekitten.com/400/300" height="400px" width="400px">
 </g>
</svg>

Tags:

Css

Css Shapes