Search code examples
javascripthtmlcss

adding a border to a transparent div with clip path


Lets consider the following:

.hexagon {
            position: absolute;
            width: 200px;
            height: 200px;
            background-color: rgba(32,78,64,0.25);
            z-index: 20;
            /* -webkit-clip-path:  polygon(50% 0, 100% 25%, 100% 75%, 50% 100%, 0 75%, 0 25%); */
            -webkit-clip-path: polygon(25% 0, 75% 0, 100% 50%, 75% 100%, 25% 100%, 0 50%);
            /*aspect-ratio: 1/cos(30deg);*/
            /*clip-path: polygon(0% 25%, 0% 75%, 50% 100%, 100% 75%, 100% 25%, 50% 0%);*/
            clip-path: polygon(25% 0, 75% 0, 100% 50%, 75% 100%, 25% 100%, 0 50%);

            /*             clip-path: polygon(50% 0, 100% 25%, 100% 75%, 50% 100%, 0 75%, 0 25%); */
            left:40px;
            top:40px;
            /*transform: rotate(90deg);*/

            display: flex;
            justify-content: center;
            align-items: center;
            
            /*filter: drop-shadow(1px 0px 0px rgba(32,78,64,1))
                    drop-shadow(-1px 0px 0px rgba(32,78,64,1))
                    drop-shadow(0px 1px 0px rgba(32,78,64,1))
                    drop-shadow(0px -1px 0px rgba(32,78,64,1))
                    drop-shadow(1px 1px 0px rgba(32,78,64,1))
                    drop-shadow(-1px -1px 0px rgba(32,78,64,1))
                    drop-shadow(-1px 1px 0px rgba(32,78,64,1))
                    drop-shadow(1px -1px 0px rgba(32,78,64,1));
                    */

            outline: 2px solid rgba(32,78,64,0.75);
            outline-offset: -2px;
        }

        .hexagon::after {
            content: "";
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            border: 2px solid black; /* Change color as needed */
            -webkit-clip-path: polygon(25% 0, 75% 0, 100% 50%, 75% 100%, 25% 100%, 0 50%);
            clip-path: polygon(25% 0, 75% 0, 100% 50%, 75% 100%, 25% 100%, 0 50%);
            pointer-events: none;
            box-sizing: border-box; /* Ensures the border is included in the element's dimensions */
        }

Challenge:

I need to add borders along the Hexagon-shaped clip-path.

Attempts to solution:

The drop shadow I used above (commented) does not work in Firefox.

Now, there are many solutions on SO (example) (this is where I got the drop shadow idea from) and on the internet, but they usually use a hidden, slightly larger hexagon with border colors underneath the one where you need to border. In my case, the target hexagon is transparent, hence it would not work.

The after pseudoelement here only adds a rectangular border aimed for the original unclipped div.

I thought about an SVG, but I could not figure out how to keep the SVG anchored to all the Hexagon divs, as they move and change size with resize event and based on media queries.

Question:

How to I add a dark border to a div, with transparent background background with clip-path applied to it? Thank you.

Edit: Here is full page : Pastebin link


Solution

  • Since borders (as well as shadows) get clipped by a <clip-path> (or a mask) you may need an unclipped wrapping element.

    You can replicate the CSS clip-path with a SVG <polygon> like so:

      <svg class="poly-brd full-width-height" viewBox="0 0 100 100" overflow="visible" preserveAspectRatio="none">
        <polygon points="25 0 75 0 100 50 75 100 25 100 0 50" stroke="blue" fill="none" vector-effect="non-scaling-stroke" />
      </svg>
    

    For a responsive polygon filling the parent element's bounding box, we need to set preserveAspectRatio to "none".

    vector-effect="non-scaling-stroke"
    

    ensures the strokes will keep a uniform stroke width. Besides we apply

    overflow="visible"
    

    to the SVG to ensure the border isn't cropped by the bounding box.

    body {
      background-image: url("data:image/svg+xml,<svg viewBox='0 0 10 9' xmlns='http://www.w3.org/2000/svg'><path d='M0 0 L10 0 L10 9' stroke-width='1' fill='none' stroke='%23eee'/></svg>");
      background-repeat: repeat;
      background-size: 10px;
    }
    
    .hexagon-brd {
      position: relative;
      overflow: visible;
      width: 100%;
      height: 75vh;
    }
    
    .hexagon {
      background-color: rgba(200, 0, 0, 0.2);
      -webkit-clip-path: polygon(25% 0, 75% 0, 100% 50%, 75% 100%, 25% 100%, 0 50%);
      clip-path: polygon(25% 0, 75% 0, 100% 50%, 75% 100%, 25% 100%, 0 50%);
      display: flex;
      justify-content: center;
      align-items: center;
    }
    
    .poly-brd {
      stroke-width: 5px
    }
    
    .full-width-height {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
    }
    <div class="hexagon-brd">
      <svg class="poly-brd full-width-height" viewBox="0 0 100 100" overflow="visible" preserveAspectRatio="none">
        <polygon points="25 0 75 0 100 50 75 100 25 100 0 50" stroke="blue" fill="none" vector-effect="non-scaling-stroke" />
      </svg>
    
      <div class="hexagon full-width-height">
        <p>content</p>
      </div>
    </div>