菱形图片
最后更新于:2022-04-01 03:43:51
> 原文出处:http://www.w3cplus.com/css3/css-secrets/diamond-images.html
## 问题
用菱形裁剪图片在视觉设计中非常常见,但是这种效果没办法直接用CSS完成。实际上,直到最近,这基本上还是不可能做到的。因为,当网页设计师想要使用这种样式,他们通常会先用图像编辑器预裁剪图像。当然,不用想都知道,这对于应用任何效果都不是一种可维护的方式,如果后面有人想要改变图像样式,最后的结果都会变得非常混乱。
当然,现在有一个更好的方法,对吧?实际上,有两个耶!
![菱形图片](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-10-05_5611e84c5ef0b.png "菱形图片")
*图注:这是2013年的设计,24ways.org现在用菱形裁剪展示作者的简介图片,使用了这里讨论的技术*
## 基于变换的解决方案
主要的思想和在[上一节“多边形”中的第一个解决方案](http://www.w3cplus.com/css3/css-secrets/parallelograms.html)一样,我们需要用一个`<div>`包裹我们的图像,然后给它们应用相反的`rotate()`变换:
~~~
<div class="picture">
<img src="adam-catlace.jpg" alt="…" />
</div>
.picture {
width: 400px;
transform: rotate(45deg);
overflow: hidden;
}
.picture > img {
max-width: 100%;
transform: rotate(-45deg);
}
~~~
![菱形图片](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-10-05_5611e84ca2f12.png "菱形图片")
*图注:我们的原始图像,我们将要把它裁剪成菱形*
但是,下图所示效果这并不是我们想要完成的效果。
![菱形图片](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-10-05_5611e84d1c726.png "菱形图片")
*图注:反方向的`rotate()`不足以完成这个效果(`.picture`div用一个虚线框标出)*
除非我们是要把图像裁剪成八边形的形状,这样我们现在就可以停下来,然后去做其它的事情。如果是把它裁剪成菱形,我们还有很多工作要做。
主要是`max-width: 100%`的声明。`100%`对应的是我们的`.picture`容器的边长。但是,我希望我们的图片和它的对角线一样长,而不是它的边。你可能已经猜到了,没错我们要再次使用勾股定理了(如果你需要复习,在[第二章第五节的“Diagonal stripes”一小节中](http://www.w3cplus.com/css3/css-secrets/striped-backgrounds.html)有提到)。定理告诉我们,方形的对角线等于它的边长乘以`根号(2)≈1.414213562`。因此,把它的`max-width`设置为`根号(2)×100%≈141.4213562%`,约等于`142%`。因为我们不希望它在任何哪种情况下会变小(但稍微大一点是可以接受的,因为我们的图像是被裁剪的)。
事实上,通过`scale()`变换来放大元素,有以下几个原因:
* 我们希望图片的大小保持`100%`,如果CSS变换没有被支持
* 通过`scale()`变换来放大图像可以将它从中心放大(除非另外指定了一个不同的`transform-origin`值)。如果是使用`width`属性来直接进行大小的调整,那么它会从左上角开始放大,这样我们最后还要使用负边距来移动它。
综上所述,我们最后的代码如下:
~~~
.picture {
width: 400px;
transform: rotate(45deg);
overflow: hidden;
}
.picture > img {
max-width: 100%;
transform: rotate(-45deg) scale(1.42);
}
~~~
下图所示效果,这就是我们想要的效果。
![菱形图片](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-10-05_5611e84d4ae14.png "菱形图片")
*图注:最后裁剪出的图像*
## 基于`clip-path`的解决方案
前面的解决方案是可行的,但是它基本上是hack。它需要额外的HTML元素,而且也很混乱、复杂,并且脆弱:如果碰巧我们要处理的不是正方形图像,最终的结果就会非常糟糕:
![菱形图片](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-10-05_5611e84e44f54.png "菱形图片")
*图注:如果处理的是非正方形的图像,基于变换的解决方案将变得非常糟糕*
实际上,还有一个更好的方法。主要的思想是使用[`clip-path`](http://www.w3cplus.com/blog/tags/431.html)属性,这是从SVG借来的另一个特性,现在它已经可以被应用于HTML元素了(至少在支持它的浏览器中),用好的、可读性强的语法,不像它的SVG副本,据说用起来容易让人抓狂。它的主要问题浏览器支持有限(我写这篇文章时)。但是,它的降级非常优雅(没有裁剪),所以这至少是可考虑的选择。
你可以在使用像Photoshop这样的图形编辑器,因为你对clipping path非常熟悉。Clipping path允许我们把元素裁剪成我们想要的形状。在这里,我们使用`polygon()`来指定一个菱形,这个形状允许我们使用一系列用逗号分隔的坐标点来指定任何多边形形状。
~~~
clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%);
~~~
就是它了!实现下图效果,相比之前需要两行HTML元素和八行隐蔽的CSS代码,现在只需要简单的一行。
![菱形图片](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-10-05_5611e84d4ae14.png "菱形图片")
`clip-path`的令人惊叹之处不仅于此。这个属性是可添加动画的,只要是在两个相同的形状函数(这里是`polygon()`)之间,然后另一个形状有相同数量的坐标点。因此,如果我们想要在鼠标悬停的时候显示一幅完整的图像,我们可以这样写:
~~~
img {
clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%);
transition: 1s clip-path;
}
img:hover {
clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%);
}
~~~
还有,这个方法可以很好地应用到非正方形的图像上,如下图所示。
![菱形图片](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-10-05_5611e853b6dfd.png "菱形图片")
*图注:`clip-path`方法可以很好地应用于非正方形图像中*
啊~~现代CSS的乐趣~~
## 总结
在这一节中通过使用CSS的`transfrom`属性配合一定的数学计算,实现钻石图片效果。但这具有一定的局限性,对于正方形图片效果较好,但对于非正方形的图形效果就不太理想。实际上除了`transform`属性之外,还有更理想的方案,那就是使用`clip-path`对图片直接进行钻石形状的裁剪,从而实现我们需要的效果。