cssanimationsvgtransformscale

Is it possible to change svg path height with css transform? (not scale, not whole svg, only one path)


I'm trying to increase the height of an SVG path (the border) and I'm getting the problem that the border gets hidden, only grows to down direction (not up) and the rounded corners get stretched. If I do the scale with the whole SVG also the icon inside get stretched and I want a uniform grow for that icon. I think using a div for that box is not a solution either because I would like the whole composition get resized to fill the space responsively.

Any solution?

#box{
  position:absolute;
  left: 80px;
}
#t-shirt{
  position: absolute;
  left:0;
  top: 25%;
}
#t-shirt:hover {
  transform: scale(1,1.2);
}
#pants{
  position: absolute;
  left: 160px;
  top: 25%;
}
#pants:hover #pants-border{
  transform: scale(1,1.2);
}
<svg id="box" width="315" height="341" viewBox="0 0 315 341" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="10.5" y="9.5" width="304" height="331" rx="19.5" fill="#242420" stroke="#242420"/>
<rect x="0.5" y="0.5" width="304" height="331" rx="19.5" fill="#D9D9D9" stroke="#242420"/>
<circle cx="23" cy="20" r="6.5" fill="#C9C9C9" stroke="#242420"/>
<circle cx="47" cy="20" r="6.5" fill="#C9C9C9" stroke="#242420"/>
<circle cx="71" cy="20" r="6.5" fill="#C9C9C9" stroke="#242420"/>
</svg>

<svg id="t-shirt" width="147" height="147" viewBox="0 0 147 147" fill="none" xmlns="http://www.w3.org/2000/svg">
  <path height="200" d="M19.3522 0.706462H126.757C137.178 0.706462 145.626 9.15414 145.626 19.5749V126.98C145.626 137.4 137.178 145.848 126.757 145.848H19.3522C8.93148 145.848 0.483806 137.4 0.483806 126.98V19.5749C0.483806 9.15414 8.93149 0.706462 19.3522 0.706462Z" fill="#EBEBEB" stroke="#242420" stroke-width="0.967611"/>
  <path d="M112.243 116.336H34.834L35.0547 113.12L35.2341 110.749L35.441 107.977L35.6066 105.579L35.8135 102.806L35.9928 100.408L36.1998 97.6353L36.3653 95.2648L41.1525 29.251H53.8172C53.9529 34.4014 56.0844 39.295 59.7577 42.8896C63.431 46.4841 68.3559 48.4956 73.4833 48.4956C78.6106 48.4956 83.5354 46.4841 87.2087 42.8896C90.882 39.295 93.0136 34.4014 93.1493 29.251H105.869L110.643 95.2648L110.822 97.6353L111.029 100.408L111.194 102.806L111.401 105.579L111.581 107.977L111.788 110.749L111.953 113.12L112.243 116.336Z" fill="#D9D9D9"/>
  <path d="M37.7369 29.251L13.5466 58.7078L34.2872 75.6963L37.7369 29.251Z" fill="#d9d9d9"/>
  <path d="M109.34 29.251L133.53 58.7078L112.776 75.6963L109.34 29.251Z" fill="#D9D9D9"/>
</svg>

<svg id="pants" width="148" height="147" viewBox="0 0 148 147" fill="none" xmlns="http://www.w3.org/2000/svg">
<path id="pants-border" d="M19.8137 0.706462H128.186C138.607 0.706462 147.055 9.15414 147.055 19.5749V126.98C147.055 137.4 138.607 145.848 128.186 145.848H19.8136C9.39288 145.848 0.945231 137.4 0.945231 126.98V19.5749C0.945231 9.15414 9.39291 0.706462 19.8137 0.706462Z" fill="#EBEBEB" stroke="#242420" stroke-width="0.967611"/>
<path d="M103.028 12.8018V19.575L74 19.5611V19.575H44.9717V12.8018H103.028Z" fill="#DADADA"/>
<path d="M94.3198 24.4131H103.028V33.1216C94.465 32.713 94.3198 24.4131 94.3198 24.4131Z" fill="#DADADA"/>
<path d="M103.028 38.4122V132.786H80.6181L74.021 45.4874L67.382 132.786H44.9717V38.4122C48.7254 37.779 57.6755 35.1361 57.6755 24.4131H71.5839C71.5839 31.7636 71.3738 38.1781 73.993 38.2607C76.6262 38.2607 76.4161 31.7636 76.4161 24.4131H90.3385C90.3245 35.1361 99.2746 37.779 103.028 38.4122Z" fill="#DADADA"/>
<path d="M44.9717 33.1216V24.4131H53.6802C53.6802 24.4131 53.5205 32.713 44.9717 33.1216Z" fill="#DADADA"/>
</svg>


Solution

  • As suggested by @n-- you need to scale your elements separately on hover:

    To avoid distortions, you could use a <rect> element with rx ry attributes (for rounded borders) and change the height and y values on hover.

    We can avoid clipping by applying a overflow:visible property to the svgs.

    svg {
      overflow: visible;
    }
    
    svg * {
      transform-origin: center;
      transition: 0.3s;
    }
    
    #box {
      position: absolute;
      left: 80px;
    }
    
    #t-shirt {
      position: absolute;
      left: 0;
      top: 25%;
    }
    
    #pants {
      position: absolute;
      left: 160px;
      top: 25%;
    }
    
    
    /* scale rect by changing height */
    
    #t-shirt:hover .rect-shirt {
      height: 180px;
      y: -14px;
    }
    
    
    /* scale icons */
    
    svg:hover .g-icon {
      transform: scale(1.2);
    }
    
    
    /* scale rect by changing d */
    
    #pants:hover .rect-pants {
      d: path("M0 4.8 a 19.5 19.5 0 0 1 19.5-19.5 h 107 a 19.5 19.5 0 0 1 19.5 19.5 v 140 a19.5 19.5 0 0 1-19.5 19.5 h -107 a19.5 19.5 0 0 1-19.5-19.5 z");
    }
    <svg id="box" width="315" height="341" viewBox="0 0 315 341" fill="none" xmlns="http://www.w3.org/2000/svg">
      <rect x="10.5" y="9.5" width="304" height="331" rx="19.5" fill="#242420" stroke="#242420" />
      <rect x="0.5" y="0.5" width="304" height="331" rx="19.5" fill="#D9D9D9" stroke="#242420" />
      <circle cx="23" cy="20" r="6.5" fill="#C9C9C9" stroke="#242420" />
      <circle cx="47" cy="20" r="6.5" fill="#C9C9C9" stroke="#242420" />
      <circle cx="71" cy="20" r="6.5" fill="#C9C9C9" stroke="#242420" />
    </svg>
    
    <svg id="t-shirt" width="147" height="147" viewBox="0 0 147 147" fill="none" xmlns="http://www.w3.org/2000/svg">
    <rect class="rect-shirt transition" x="0.5" y="0.5" width="146" height="146" rx="19.5" fill="#EBEBEB" stroke="#242420" stroke-width="1" ></rect>
      
      <g class="g-icon g-shirt">
      <path d="M112.243 116.336H34.834L35.0547 113.12L35.2341 110.749L35.441 107.977L35.6066 105.579L35.8135 102.806L35.9928 100.408L36.1998 97.6353L36.3653 95.2648L41.1525 29.251H53.8172C53.9529 34.4014 56.0844 39.295 59.7577 42.8896C63.431 46.4841 68.3559 48.4956 73.4833 48.4956C78.6106 48.4956 83.5354 46.4841 87.2087 42.8896C90.882 39.295 93.0136 34.4014 93.1493 29.251H105.869L110.643 95.2648L110.822 97.6353L111.029 100.408L111.194 102.806L111.401 105.579L111.581 107.977L111.788 110.749L111.953 113.12L112.243 116.336Z" fill="#D9D9D9" />
      <path d="M37.7369 29.251L13.5466 58.7078L34.2872 75.6963L37.7369 29.251Z" fill="#d9d9d9" />
      <path d="M109.34 29.251L133.53 58.7078L112.776 75.6963L109.34 29.251Z" fill="#D9D9D9" />
        </g>
    </svg>
    
    <svg id="pants" width="148" height="147" viewBox="0 0 148 147" fill="none" xmlns="http://www.w3.org/2000/svg">
      <path class="rect-pants transition" fill="#EBEBEB" stroke="#242420" stroke-width="1" d="
    M0 19.5
    a19.5 19.5 0 0 1 19.5-19.5
    h107
    a19.5 19.5 0 0 1 19.5 19.5
    v107a19.5 19.5 0 0 1-19.5 19.5
    h-107
    a19.5 19.5 0 0 1-19.5-19.5
    z"/>
      
      <g class="g-icon g-pants">
      <path d="M103.028 12.8018V19.575L74 19.5611V19.575H44.9717V12.8018H103.028Z" fill="#DADADA" />
      <path d="M94.3198 24.4131H103.028V33.1216C94.465 32.713 94.3198 24.4131 94.3198 24.4131Z" fill="#DADADA" />
      <path d="M103.028 38.4122V132.786H80.6181L74.021 45.4874L67.382 132.786H44.9717V38.4122C48.7254 37.779 57.6755 35.1361 57.6755 24.4131H71.5839C71.5839 31.7636 71.3738 38.1781 73.993 38.2607C76.6262 38.2607 76.4161 31.7636 76.4161 24.4131H90.3385C90.3245 35.1361 99.2746 37.779 103.028 38.4122Z" fill="#DADADA" />
      <path d="M44.9717 33.1216V24.4131H53.6802C53.6802 24.4131 53.5205 32.713 44.9717 33.1216Z" fill="#DADADA" />
        </g>
    </svg>

    Alternative: transition the d (path data) attribute

    The pants rectangle is drawn as a path using relative commands

    M 0 19.5
    a 19.5 19.5 0 0 1 19.5-19.5
    h 107
    a 19.5 19.5 0 0 1 19.5 19.5
    v 107
    a 19.5 19.5 0 0 1-19.5 19.5
    h -107
    a 19.5 19.5 0 0 1-19.5-19.5
    z
    

    The hovered d can be created by just changing the M y value and the v (vertical line to) like so

    M 0 4.8 // rectangle's x/y position 
    a 19.5 19.5 0 0 1 19.5-19.5 
    h 107 
    a 19.5 19.5 0 0 1 19.5 19.5 
    v 140 // rectangle's height
    a 19.5 19.5 0 0 1-19.5 19.5 
    h -107 
    a 19.5 19.5 0 0 1-19.5-19.5 
    z
    

    We can change the paths geometry using the css path() method:

    /* scale rect by changing d */
    #pants:hover .rect-pants{
      d:path("M0 4.8 a 19.5 19.5 0 0 1 19.5-19.5 h 107 a 19.5 19.5 0 0 1 19.5 19.5 v 140 a19.5 19.5 0 0 1-19.5 19.5 h -107 a19.5 19.5 0 0 1-19.5-19.5 z");
    }