Melanie P.
Melanie P.

Reputation: 53

Animated div with SVG clip-path not responsive?

I have a DIV utilizing a css background, animation, and clip-path. The svg won't scale responsively whether I'm using vh/vw or percent. It'll scale properly when you change the window's height, but not when you change the window's width. Can you help me figure out which SVG implementation to use to get it to scale 1:1 responsively? I'd like to accomplish this without js but I'm open to it.

HTML

.imageHero {
  max-width: 100%;
    max-height: 100%;
    width: 65vh;
  height: 65vh;
  margin: 40px;
  clip-path: url('#my-clip-path');
  animation: clipRotateAnim 6s linear infinite;
  position: relative;
  overflow: hidden;
}

.imageHero::before {
  content: "";
  position: absolute;
  top: -10%;
  bottom: -10%;
  left: -10%;
  right: -10%;
  background: var(--i) center;
    -webkit-background-size: cover;
  -moz-background-size: cover;
  -o-background-size: cover;
  background-size: cover;
  animation: inherit;
  animation-direction: reverse;
}

@keyframes clipRotateAnim {
  to {
    transform: rotate(360deg);
  }
}

.r0tate {
        display: inline-block;
    position: relative;
    width: 100%;
    padding-bottom: 100%; 
    vertical-align: middle; 
    overflow: hidden; 
}

.svg-content { 
    display: block;
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
}
<meta name="viewport" content="width=device-width, initial-scale=1.0">

<center>
    <div class="r0tate">
    <div class="imageHero" style="--i:url(https://source.unsplash.com/600x600?summer)" width="100%" height="100%">
</div>

<svg class="svg-content" viewBox="0 0 616.8 599" preserveAspectRatio="xMinYMin meet" height="0" width="0">
  <clipPath id="my-clip-path" clipPathUnits="objectBoundingBox"><path d="M0.5,0.768 L0.366,1 L0.366,0.732,0.134,0.866 L0.268,0.634 L0,0.634 L0.232,0.5,0,0.366 L0.268,0.366,0.134,0.134 L0.366,0.268 L0.366,0 L0.5,0.232,0.634,0 L0.634,0.268,0.866,0.134 L0.732,0.366 L1,0.366 L0.768,0.5 L1,0.634,0.732,0.634,0.866,0.866 L0.634,0.732 L0.634,1"></path></clipPath>
</svg>
</div>
</center>

fiddle here

Upvotes: 2

Views: 339

Answers (2)

herrstrietzel
herrstrietzel

Reputation: 17165

Part of the problem are your width and max-width definitions.

Essentially you have to ensure your clipped image keeps its aspect ratio.
You might actually use the css aspect-ratio property – but browser support is still not perfect. Thus we take the old-school aspect-ratio hack.

   .imageHero::before {
        content: "";
        padding-bottom: 100%;
        width: 100%;
        display: block;
    }

.imageHero {
  max-width: 65vh;
  margin: 0 auto;
  clip-path: url('#my-clip-path');
  animation: clipRotateAnim 6s linear infinite;
  position: relative;
  overflow: hidden;
}


/* force aspect ratio 1:1 */
.imageHero::before {
  content: "";
  padding-bottom: 100%;
  width: 100%;
  display: block;
}

/* image */
.imageHero::after {
  content: "";
  position: absolute;
  top: -10%;
  bottom: -10%;
  left: -10%;
  right: -10%;
  background: var(--i) center;
  background-size: cover;
  animation: inherit;
  animation-direction: reverse;
}

@keyframes clipRotateAnim {
  to {
    transform: rotate(360deg);
  }
}

.imageHero-wrp {
  position: relative;
  overflow: hidden;
  padding: 40px;
  background: #eee;
}

.svg-content {
  position: absolute;
  top: 0;
  left: 0;
  width: 0;
  height: 0;
}
<main>
  <div class="imageHero-wrp">
    <div class="imageHero" style="--i:url(https://source.unsplash.com/600x600?summer)" width="100%" height="100%">
    </div>

    <svg class="svg-content" viewBox="0 0 1 1">
                <clipPath id="my-clip-path" clipPathUnits="objectBoundingBox">
                    <path
                        d="M0.5,0.768 L0.366,1 L0.366,0.732,0.134,0.866 L0.268,0.634 L0,0.634 L0.232,0.5,0,0.366 L0.268,0.366,0.134,0.134 L0.366,0.268 L0.366,0 L0.5,0.232,0.634,0 L0.634,0.268,0.866,0.134 L0.732,0.366 L1,0.366 L0.768,0.5 L1,0.634,0.732,0.634,0.866,0.866 L0.634,0.732 L0.634,1z">
                    </path>
                </clipPath>
            </svg>
  </div>
</main>

Smil animated clip-path

As an alternative you might also animate the clip-path itself via <animateTransform>

.imageHero {
  max-width: 65vh;
  margin: 40px auto;
  clip-path: url('#my-clip-path');
  position: relative;
  overflow: hidden;
}


/* force aspect ratio 1:1 */
.imageHero::before {
  content: "";
  padding-bottom: 100%;
  width: 100%;
  display: block;
}


/* image element */
.imageHero::after {
  content: "";
  position: absolute;
  top: 0%;
  bottom: 0%;
  left: 0%;
  right: 0%;
  background: var(--i) center;
  background-size: cover;
}

.r0tate {
  position: relative;
  width: 100%;
  padding-bottom: 100%;
  overflow: hidden;
}

.svg-content {
  position: absolute;
  top: 0;
  left: 0;
  width: 0;
  height: 0;
}
<main>
  <div class="r0tate">
    <div class="imageHero" style="--i:url(https://source.unsplash.com/600x600?summer)" width="100%" height="100%">
    </div>

    <svg class="svg-content" viewBox="0 0 1 1" aria-hidden="true">
                <clipPath id="my-clip-path" clipPathUnits="objectBoundingBox">
                    <path
                        d="M0.5 0.755l-0.127 0.22l0-0.254l-0.221 0.127l0.128-0.22l-0.255 0l0.22-0.128l-0.22-0.127l0.255 0l-0.128-0.22l0.221 0.127l0-0.255l0.127 0.221l0.127-0.221l0 0.255l0.221-0.127l-0.128 0.22l0.255 0l-0.22 0.127l0.22 0.128l-0.255 0l0.128 0.22l-0.221-0.127l0 0.254z">
                        <animateTransform attributeName="transform"
                        type="rotate"
                        from="0 0.5 0.5"
                        to="360 0.5 0.5"
                        dur="6s"
                        repeatCount="indefinite"/>
                    </path>
                </clipPath>
            </svg>
  </div>
</main>

This might actually be more performant since you're just rotating the the clip-path and not both image and parent element.

Upvotes: 3

Attila F&#225;nczi
Attila F&#225;nczi

Reputation: 159

I've prepared a solution, if that's what you mean. .imageHero{position: absolute;} That's all I've set it to, plus r0tate{display: flex; justify-content: center;} if you want to center it.

.imageHero {
  max-width: 60%;
  max-height: 60%;
  width: 65vh;
  height: 65vh;
  margin: 40px;
  clip-path: url("#my-clip-path");
  animation: clipRotateAnim 6s linear infinite;
  position: absolute;
  overflow: hidden;
}

.imageHero::before {
  content: "";
  position: absolute;
  top: -10%;
  bottom: -10%;
  left: -10%;
  right: -10%;
  background: var(--i) center;
  -webkit-background-size: cover;
  -moz-background-size: cover;
  -o-background-size: cover;
  background-size: cover;
  animation: inherit;
  animation-direction: reverse;
}

@keyframes clipRotateAnim {
  to {
    transform: rotate(360deg);
  }
}

.r0tate {
  display: flex;
  justify-content: center;
  position: relative;
  width: 100%;
  padding-bottom: 100%;
  vertical-align: middle;
  overflow: hidden;
}

.svg-content {
  display: block;
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="style.css" />
    <title>Document</title>
  </head>
  <body>
    <center>
      <div class="r0tate">
        <div
          class="imageHero"
          style="--i: url(https://source.unsplash.com/600x600?summer)"
          width="100%"
          height="100%"
        ></div>

        <svg
          class="svg-content"
          viewBox="0 0 616.8 599"
          preserveAspectRatio="xMinYMin meet"
          height="0"
          width="0"
        >
          <clipPath id="my-clip-path" clipPathUnits="objectBoundingBox">
            <path
              d="M0.5,0.768 L0.366,1 L0.366,0.732,0.134,0.866 L0.268,0.634 L0,0.634 L0.232,0.5,0,0.366 L0.268,0.366,0.134,0.134 L0.366,0.268 L0.366,0 L0.5,0.232,0.634,0 L0.634,0.268,0.866,0.134 L0.732,0.366 L1,0.366 L0.768,0.5 L1,0.634,0.732,0.634,0.866,0.866 L0.634,0.732 L0.634,1"
            ></path>
          </clipPath>
        </svg>
      </div>
    </center>
  </body>
</html>

jsfiddle: https://jsfiddle.net/rmcnt9a1/

Upvotes: 1

Related Questions