我正在使用 SVG 将图像剪切到三角形。我的目标是让路径扩展并在悬停时变成一个圆圈(平滑过渡)。
我发现的最接近的是这个 codepen,作为对站点挑战的回应: http://codepen.io/enjikaka/pen/hCGjE 它确实会过渡,但它似乎与我正在做的剪辑有很大不同。我对 svg 很陌生(才刚刚开始使用它来创建这些三角形)。
这是我的代码(引导程序 col-sm-4 div 中的向上三角形剪辑和向下三角形剪辑):
<div class="col-sm-4">
<div class='tri-up'>
<svg width="100%" height="100%" viewBox="0 0 100 87">
<clipPath id="clipTriangleUp">
<polygon points="0 87,100 87,50 0"/>
</clipPath>
<image clip-path="url(#clipTriangleUp)" preserveAspectRatio="none" width="100%" height="100%" xlink:href="http://placehold.it/560x484"/>
</svg>
</div>
</a>
</div>
<div class="col-sm-4">
<div class='tri-down'>
<svg width="100%" height="100%" viewBox="0 0 100 87">
<clipPath id="clipTriangleDown">
<polygon points="0 0,100 0,50 87"/>
</clipPath>
<image clip-path="url(#clipTriangleDown)" preserveAspectRatio="none" width="100%" height="100%" xlink:href="http://placehold.it/560x484"/>
</svg>
</div>
</a>
</div>
我这里还有其他一些类,它可以制作 6 个三角形(上下),分成两行,每行三个。负边距将三角形推得比引导列靠得更近。
如果有人知道如何实现这一点,我已经在互联网上搜索无果,非常感谢您的帮助。
没有库和 JS 就没有简单的解决方案。然而,我们可以通过一些妥协来做到这一点。 我们将讨论的解决方案/部分:
让我们首先了解一下我们在做什么。为此,我们将使用 SVG。 我们使用带有 arc 命令的路径来制作一个完美的圆。然后我们增加这三个圆弧的半径。这将导致接近平坦的曲线。最后,我们添加一个真正的三角形并缩小假三角形。最后一步可以省略。我用点标记了角,并将真正的三角形涂成灰度,以便更容易看到正在发生的事情。
// tested with symmetrical triangle
// height width
h=w= 200
// center of circle, radius
cx=cy=r= w/2
// width of the right/left half triangle
w_tri=w_tri_ri=w_tri_le=75
// length of the triangle from the center to bottom
h_tri_bo=h_tri_bo_ri=h_tri_bo_le=Math.sqrt(r**2-w_tri**2)//=Math.sqrt(r**2-w_tri_ri**2)=Math.sqrt(r**2-w_tri_le**2)
// untranslated coordinates
// console.log(cx,0) //100 0
// console.log(cx+w_tri_ri,cy+h_tri_bo_ri) //175 166.14378277661478
// console.log(cx-w_tri_ri,cy+h_tri_bo_le) //25 166.14378277661478
// translated to be at the centre (centre of the circle translated to the origin)
console.log(0,cy) //0 100
console.log(w_tri_ri,h_tri_bo_ri) //75 66.14378277661477
console.log(-w_tri_ri,h_tri_bo_le) //-75 66.14378277661477
<svg width="200" height="200">
<circle cx="0" cy="-100" r="2" fill="blue" transform="translate(100 100)"/>
<circle cx="75" cy="66.14378277661477" r="2" fill="blue" transform="translate(100 100)"/>
<circle cx="-75" cy="66.14378277661477" r="2" fill="blue" transform="translate(100 100)"/>
<path transform="translate(100 100)"
d="M0,-100
L 75 66.14378277661477
-75 66.14378277661477
0 -100" fill="grey"
/>
<path transform="translate(100 100)">
<animate
id="morph-ani"
attributeName="d" dur="2s" fill="freeze"
calcMode="spline"
keyTimes="0;1"
keySplines ="1 0 .85 1"
from="M0,-100
A100,100 0 0,1 75 66.14378277661477
A100,100 0 0,1 -75 66.14378277661477
A100,100 0 0,1 0 -100"
to="M0 -100
A1000,1000 0 0,1 75 66.14378277661477
A1000,1000 0 0,1 -75 66.14378277661477
A1000,1000 0 0,1 0 -100"
/>
<animateTransform
additive="sum"
attributeName="transform"
type="scale"
dur="2s"
fill="freeze"
from="1"
to=".9"
begin="1.6s"
/>
/>
</svg>
现在我们只需要将其转换为 CSS 过渡,例如通过悬停来驱动它。我们将末端半径增加 10。这将使曲线更加线性,并且我们不必处理第二个三角形。 我们还在圆形/三角形周围添加一个 div。这确保了即使形状在光标下滑走,它仍然算作悬停状态。
#hoverhandler, #shape{
height: 200px;
width: 200px;
}
#hoverhandler #shape{
transition: background-color 0s, clip-path 2s;
transition-timing-function: cubic-bezier(.3,1,0.2,1);
background-color: black;
clip-path: path("M100,0 \
A100,100 0 0,1 175 166.14378277661478 \
A100,100 0 0,1 25 166.14378277661478 \
A100,100 0 0,1 100 0Z")
}
#hoverhandler:hover #shape{
clip-path: path( "M100,0 \
A10000,10000 0 0,1 175 166.14378277661478 \
A10000,10000 0 0,1 25 166.14378277661478 \
A10000,10000 0 0,1 100 0Z");
transition: background-color 0s, clip-path 2s;
transition-timing-function: cubic-bezier( 0.8, 0, 0.7, 0);
}
<div id="hoverhandler">
<div id="shape"></div>
</div>
// tested with symmetrical triangle
// height width
h=w= 200
// center of circle, radius
cx=cy=r= w/2
// width of the right/left half triangle
w_tri=w_tri_ri=w_tri_le=75
// length of the triangle from the center to bottom
h_tri_bo=h_tri_bo_ri=h_tri_bo_le=Math.sqrt(r**2-w_tri**2)//=Math.sqrt(r**2-w_tri_ri**2)=Math.sqrt(r**2-w_tri_le**2)
// untranslated coordinates
// console.log(cx,0)
// console.log(cx+w_tri_ri,cy+h_tri_bo_ri)
// console.log(cx-w_tri_le,cy+h_tri_bo_le)
// translated to be at the centre (centre of the circle translated to the origin)
console.log(0,-cy)
console.log(w_tri_ri,h_tri_bo)
console.log(-w_tri_le,h_tri_bo)
如果不调整缓动函数,之前示例的动画会变得非常快。为了缓解这个问题,我们可以创建一条完美三角形的路径,并尝试将其变形为尽可能接近圆形。
#hoverhandler, #shape{
height: 200px;
width: 200px;
}
#hoverhandler #shape{
transition: background-color 0s, clip-path 2s .5s;
background-color: black;
clip-path: path("M100,0 \
C 203,0 219.97777228809804,126.4771161099481 175,166.14378277661478 \
C 130.02222771190196,205.81044944328144 69.97777228809804,205.81044944328144 25,166.14378277661478 \
C -19.977772288098038,126.4771161099481 -3,0 100,0Z")
}
#hoverhandler:hover #shape{
transition: background-color 0s, clip-path 2s .4s;
clip-path: path( "M100,0 \
C 100,0 175,166.14378277661478 175,166.14378277661478 \
C 175,166.14378277661478 25,166.14378277661478 25,166.14378277661478 \
C 25,166.14378277661478 100,0 100,0Z");
}
<div id="hoverhandler">
<div id="shape"></div>
</div>
(见下一节)
这个“圆”看起来不像一个圆。所以我们可以使用 Paul LeBau 的解决方案来修复明显的缺陷。
#hoverhandler, #shape, #round{
height: 200px;
width: 200px;
}
#hoverhandler #round{
position: absolute;
background-color:black;
border-radius: 100%;
transition: transform 2s .5s;
}
#hoverhandler #shape{
transition: background-color 0s, clip-path 2s .5s;
background-color: black;
clip-path: path("M100,0 \
C 203,0 219.97777228809804,126.4771161099481 175,166.14378277661478 \
C 130.02222771190196,205.81044944328144 69.97777228809804,205.81044944328144 25,166.14378277661478 \
C -19.977772288098038,126.4771161099481 -3,0 100,0Z")
}
#hoverhandler:hover #shape{
transition: background-color 0s, clip-path 2s .4s;
clip-path: path( "M100,0 \
C 100,0 175,166.14378277661478 175,166.14378277661478 \
C 175,166.14378277661478 25,166.14378277661478 25,166.14378277661478 \
C 25,166.14378277661478 100,0 100,0Z");
}
#hoverhandler:hover #round{
transform: scale(0);
transition: transform 2s ease-in;
}
<div id="hoverhandler">
<div id="round"></div>
<div id="shape"></div>
</div>
// tested with symmetrical triangle
// height width
h=w= 200
// center of circle, radius
cx=cy=r= w/2
// width of the right/left half triangle
w_tri=w_tri_ri=w_tri_le=75
// length of the triangle from the center to bottom
h_tri_bo=h_tri_bo_ri=h_tri_bo_le=Math.sqrt(r**2-w_tri**2)//=Math.sqrt(r**2-w_tri_ri**2)=Math.sqrt(r**2-w_tri_le**2)
// untranslated coordinates
// console.log(cx,0)
// console.log(cx+w_tri_ri,cy+h_tri_bo_ri)
// console.log(cx-w_tri_le,cy+h_tri_bo_le)
// translated to be at the centre (centre of the circle translated to the origin)
console.log(0,-cy)
console.log(w_tri_ri,h_tri_bo)
console.log(-w_tri_le,h_tri_bo)
l = 68
add_top = 35
ratio = w_tri/h_tri_bo
x_bo= l/(Math.sqrt(ratio**2+1))
y_bo= x_bo/ratio
console.log("Top handles")
console.log(-l, -cy)
console.log(l, -cy)
console.log("Right handles")
console.log(w_tri+x_bo, h_tri_bo - y_bo)
console.log(w_tri-x_bo, h_tri_bo + y_bo)
console.log("Left handles", x_bo)
console.log(-w_tri+x_bo, h_tri_bo + y_bo)
console.log(-w_tri-x_bo, h_tri_bo - y_bo)
res = `M${0},${-cy}
C ${l+add_top},${-cy} ${w_tri+x_bo},${h_tri_bo - y_bo} ${w_tri_ri},${h_tri_bo}
C ${w_tri-x_bo},${h_tri_bo + y_bo} ${-w_tri+x_bo},${h_tri_bo + y_bo} ${-w_tri_le},${h_tri_bo}
C ${-w_tri-x_bo},${h_tri_bo - y_bo} ${-l-add_top},${-cy} ${0},${-cy}Z`
res_transf = `M${cx},${0}
C ${l+add_top+cx},${0} ${w_tri+x_bo+cx},${h_tri_bo - y_bo+cy} ${w_tri_ri+cx},${h_tri_bo+cy}
C ${w_tri-x_bo+cx},${h_tri_bo + y_bo+cy} ${-w_tri+x_bo+cx},${h_tri_bo + y_bo+cy} ${-w_tri_le+cx},${h_tri_bo+cy}
C ${-w_tri-x_bo+cx},${h_tri_bo - y_bo+cy} ${-l-add_top+cx},${0} ${cx},${0}Z`
res_transf_hov = `M${cx},${0}
C ${cx},${0} ${w_tri_ri+cx},${h_tri_bo+cy} ${w_tri_ri+cx},${h_tri_bo+cy}
C ${w_tri+cx},${h_tri_bo+cy} ${-w_tri+cx},${h_tri_bo+cy} ${-w_tri_le+cx},${h_tri_bo+cy}
C ${-w_tri+cx},${h_tri_bo+cy} ${cx},${0} ${cx},${0}Z`
console.log(res_transf_hov)
//document.getElementById("shape").setAttribute("d",res_transf)
这可能是实现此效果的最简单方法。我们实际上使用的是遮罩而不是clipPath。我们从一个三角形作为遮罩开始,然后放大一个圆(也是遮罩的一部分),使其变得与三角形大小相同。
只要动画速度很快,这种方法就很有效。如果您想要较慢的动画,您可能需要采用使三角形变形的方法。
.tri-up
{
background-color: red;
width: 400px;
height: 400px;
}
.tri-up:hover svg .circmask
{
-webkit-transform: scale(2);
transform: scale(2);
-webkit-transition: -webkit-transform 0.1s;
transition: transform 0.1s;
}
.tri-up svg .circmask
{
-webkit-transform: scale(1);
transform: scale(1);
-webkit-transition: -webkit-transform 0.1s;
transition: transform 0.1s;
}
<div class='tri-up'>
<svg width="100%" height="100%" viewBox="-100 -100 200 200">
<mask id="clipTriangleUp">
<polygon points="0,-100, 87,50, -87,50" fill="white"/>
<circle r="50" fill="white" class="circmask"/>
</mask>
<image mask="url(#clipTriangleUp)"
x="-100" y="-100" width="100%" height="100%"
xlink:href="http://placehold.it/400x400"/>
</svg>
</div>