Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

css

css-shapes

People also ask

How do you make a polygon in CSS?

CSS | polygon() Function The polygon() function is an inbuilt function in CSS which is used with the filter property to create a polygon of images or text. Syntax: polygon( percentage | length); Parameter: This function accepts two parameter percentage or length which is used to hold the value of polygon size.

How do I box shadow a clip path in CSS?

clipped Object using Clip-Path() function of CSS. Approach: We are going to create two divs, one for the main and the other for our clipped shape. Then we are going to use the drop-shadow() function to apply shadow effects.

How do you clip a path?

The path() value allows us to use an SVG path to clip a specific area. For now, the browser support is inconsistent. To make it work across different browsers, we need to use an inline SVG, and then use the url() as a value for clip-path . In CSS, we need to append the path using url() value.


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="http://lorempixel.com/g/600/400/">
</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>

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>

Solution with pseudo element

I am write some simple code, use pseudo element - ::before, that I want to share.

I create the same shape-poligon, just bigger.

And so it seems that it has a border as you wanted (5px)

link to some nice clip-path: https://bennettfeely.com/clippy/

.poligon {
  height: 160px;
  width: 160px;
  background-color: black;
  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::before {
  content: "";
  display: block;
  position: relative;
  top: 5px;
  left: 5px;
  height: 150px;
  width: 150px;
  background-color: red;
  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"></div>

It is possible to use Drop-Shadow

  • The shape is entered only once
  • Size can be automatically set according to the content
  • The edge is outside the shape
  • One "Border Container" may contain more shapes

.arrowBg {
  filter: drop-shadow(1px 0px 0px black)
          drop-shadow(-1px 0px 0px black)
          drop-shadow(0px 1px 0px black)
          drop-shadow(0px -1px 0px black)
          drop-shadow(1px 1px 0px black)
          drop-shadow(-1px -1px 0px black)
          drop-shadow(-1px 1px 0px black)
          drop-shadow(1px -1px 0px black);
}
.arrow {
  background: #FFFF00;
  margin:20px;
  font-family: sans-serif;
  font-size:20px;
}
.arrowLeft {
  padding: 20px 20px 20px 40px;
  clip-path: polygon(40px 0%, 100% 0%, 100% 100%, 40px 100%, 0 50%);
}
.arrowRight{
  padding: 20px 40px 20px 20px;
  clip-path: polygon(calc(100% - 40px) 0%, 0 0, 0 100%, calc(100% - 40px) 100%, 100% 50%);
}
<br><br><br>
<span class="arrowBg">
  <span class="arrow arrowLeft">Go left</span>
  <span class="arrow arrowRight">Go go go right</span>
</span>

Sorry for my English


Here's how to do it.

<div class="screenshot"><img src="assets/img/tutorial/1.jpg"></div>

Just add duplicate the mask and add a padding to the parent.

.screenshot {
    mask: url(../assets/img/bubble.svg) center center no-repeat;
    background: white;
    padding: 10px;

    img {
        mask: url(../assets/img/bubble.svg) center center no-repeat;
    }
}

it's my first post here. I don't know if it answers to your question, but here's my solution :

<style>
#wrapper {
    width: fit-content;
    margin: auto;
    clip-path: polygon(0 0, 100% 0, 100% 100%, 60% 90%, 50% 100%, 40% 90%, 0 100%);
    background: white;
    border: 2px solid white;
}
#test {
    width: 500px;
    height: 300px;
    margin: auto;
    clip-path: polygon(0 0, 100% 0, 100% 100%, 60% 90%, 50% 100%, 40% 90%, 0 100%);
    background: red;
    
}
</style>

<div id="wrapper">
    <div id=test>
    </div>
</div>

fit-content will size the wrapper equal to the test div. But as the total width and height of a block element is content + padding + border, adding a border of 2 px will make the wrapper widther and higher than the test div to 2px + 2px. So by keeping the same percentage values, you create a constant difference of the border width.

The border and background of the wrapper must be the same color, the border is for uncutted zones and the background for cutted ones.