CSS揭秘之形状

352 阅读3分钟

自适应的椭圆

难题

给任何正方形元素设置一个足够大的 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);