Search code examples
javascripthtmlcsssvgfrontend

Creating responsive SVG shapes with consistent stroke width and rounded corners


I'm working on a project where I need to create SVG shapes with strokes that are responsive to their parent container size. I want these shapes to always fill the width and height of their parent container, and I also want to position them absolutely within the parent. Additionally, I need to add stroke colors to these shapes.

One issue I'm encountering is that the stroke width seems inconsistent. Sometimes, even when I set the stroke width to 1px, it appears much thicker, possibly 10px or more, making the shapes look distorted.

Here's an example of what I'm trying to achieve: I added here 1px stroke width, but I think it's getting much. Also top, bottom and left, right stroke width are getting different size though I added 1px for each side. Also how can I add 5px border radius to this path

body {
   padding: 100px 20px;
}


.parent-container {
    width: 100%;
    height: 400px;
    background: black;
    clip-path: polygon(
      0% 0%,
      95% 0%,
      100% 20%,
      100% 100%,
      5% 100%,
      0% 80%,
      0% 0%
    );
    position: relative;
}


.cta-stroke {
    position: absolute;
    inset: 0px;
    width: 100%;
    height: 100%;
    
}

path {
    stroke-width: 1px;
    stroke: red;
}
<!doctype html>
<html>
<head>
<title>svg shapes</title>
</head>

<body>
<div class="parent-container">
 <svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" fill="none" preserveAspectRatio="none" 
  class="cta-stroke">
  <path d="M0 0  L95 0  L100 20 L100 100 L5 100 L0 80 L0 0 Z" />
 </svg>
</div>

</body>
</html>

How can I achieve responsiveness and absolute positioning of SVG shapes with strokes that adapt to the size of their parent container while ensuring consistent stroke width? Also, how can I add rounded corners to the shapes? Any help or guidance would be greatly appreciated. Thank you!


Solution

  • Tip number 7 from this article on the topic of responsive SVGs may be helpful:

    By default, SVG scales everything with the viewport, including stroke thickness. Usually this works out fine, but in some cases – diagrams and strokes applied as effects on the outside of text in particular – you may want to keep strokes the same thickness, no matter what the size of the drawing. This is the domain of the little-known vector-effect property, which can be applied as a presentation attribute or in CSS.

    vector-effect: non-scaling-stroke;
    

    Here is the relevant text from the MDN documentation for this property value:

    This value modifies the way an object is stroked. Normally stroking involves calculating stroke outline of the shape's path in current user coordinate system and filling that outline with the stroke paint (color or gradient). The resulting visual effect of this value is that the stroke width is not dependent on the transformations of the element (including non-uniform scaling and shear transformations) and zoom level.

    Browser support is green across the board.

    The snippet below demonstrates the effect of this property. The SVG contains a square 20 pixels in size, styled with a 1 pixel red border. The copy on the left scales in the default manner, so the border scales in proportion with the shape. The copy on the right scales with vector-effect: non-scaling-stroke set.

    enter image description here

    body {
      background: #888;
      margin: 1em;
    }
    
    .d1 {
      display: grid;
      grid-template-columns: 1fr 1fr;
      gap: 1em;
    }
    
    svg {
      width: 100%;
      background: white;
    }
    
    svg rect {
      fill: pink;
      stroke: red;
      stroke-width: 1;
    }
    
    svg:last-child rect {
      vector-effect: non-scaling-stroke;
    }
    <div class="d1">
    
      <svg viewBox="0 0 22 22">
        <rect x="1" y="1" width="20" height="20"/>
      </svg>
    
      <svg viewBox="0 0 22 22">
        <rect x="1" y="1" width="20" height="20"/>
      </svg>
      
    </div>

    After running the snippet, use the full page link to test the responsive behaviour.

    Rounded corners

    As for this part of your question, you can round the corners of certain shapes, for example with a <rect> you can specify the roundness of the corners with the rx and ry properties. You cannot round a <path>, though, because a path by nature contains precise curvature information. You would think that <polygon> and <polyline> would provide some kind of corner-rounding property, but unfortunately they do not. Here is some further reading on rounded corners in SVG.