自适应的椭圆
难题
给任何正方形元素设置一个足够大的 border-radius ,就可以把它变成一个圆形
height:200px;
width:200px;
height:200px;
border-radius:100px;/* >= 正方形边长的一半 */
background:yellowgreen;
你可能还注意到了,如果指定任何大于 100px 的半径,仍然可以得到一个圆形。规范特别指出了这其中的原因:
当任意两个相邻圆角的半径之和超过 border box 的尺寸时,用户代理必须按比例减小各个边框半径所使用的值,直到它们不会相互重叠
为止。
解决方案
实现效果:如果它的宽高相等,就显示为一个圆;如果宽高不等,就显示为一个椭圆。可是,我们前面的代码并不能满足这个期望。当宽度大于高度时,我们怎么用border-radius 来产生一个椭圆,甚至是一个自适应的椭圆呢?
border-radius:50% / 50%;
半椭圆
纵向半椭圆
border-radius:50% / 100% 100% 0 0;
横向半椭圆
border-radius:100% 0 0 100% / 50%;
四分之一椭圆
border-radius:100% 0 0 0;
平行四边形
transform:skewX(45deg);
但是,这导致它的内容也发生了斜向变形,这很不好看,而且难读。有没有办法只让容器的形状倾斜,而保持其内容不变呢?
嵌套元素方案
我们可以对内容再应用一次反向的 skew() 变形,从而抵消容器的变形效果,最终产生我们所期望的结果。不幸的是,这意味着我们将不得不使用一层额外的 HTML 元素来包裹内容,比如用一个 div :
<div id="container">
<span>这是一个平行四边形 </span>
</div>
#container{
margin:200px;
height:200px;
width:200px;
height:200px;
transform:skewX(-45deg);
background:yellowgreen;
}
#container span{
transform:skewX(45deg);
display:inline-block;
}
注意:如果你想把这个效果应用到一个默认显示为行内的元素,不要忘记把它的 display 属性设置为其他值,比如 inline-block或 block ,否则变形是不会生效的。这一点对它内层的元素也是适用的。
伪元素方案
另一种思路是把所有样式(背景、边框等)应用到伪元素上,然后再对伪元素进行变形。因为我们的内容并不是包含在伪元素里的,所以内容并不会受到变形的影响。
#container{
position:relative;
padding-left:100px;
}
#container::before{
transform:skewX(-45deg);
content:'';
position:absolute;
left:0;
right:0;
top:0;
bottom:0;
background:yellowgreen;
z-index:-1;
width:200px;
}
菱形图片
基于变形的方案
<div id="container">
<img src="./boy.png"/>
</div>
#container{
margin:200px;
width:200px;
height:200px;
transform:rotate(45deg);
background:yellowgreen;
}
#container>img{
transform:rotate(-45deg);
width:200px;
height:200px;
}
裁切路径方案
上面的方法确实可以奏效,但它基本上是一个 hack。这个方法需要一层额外的 HTML 标签,这不够简洁;代码本身也不够直观;它甚至还不够健壮——如果我们碰巧要处理一张非正方形的图片
#container img {
clip-path: polygon(50% 0, 100% 50%,
50% 100%, 0 50%);
transition: 1s clip-path;
background:yellowgreen;
width:200px;
height:200px;
}
#container img:hover {
clip-path: polygon(0 0, 100% 0,
100% 100%, 0 100%);
}
切角效果
background:linear-gradient(-45deg, transparent 15px, yellowgreen 0);