一、很久很久以前

遥远的 CSS 大草原上,生活着一群草泥马前端攻城狮,在这里攻城狮们捕捉着各种各样属性和创造新属性,施以魔法来构建他们的玩具。有一天,攻城狮们发现了一直被冷落在角落里的 clip 属性……

二、发动咒语

在 MDN 的魔法书上,clip 属性的语法是这样被规定的:

clip: <shape> | auto  

值得注意的是,clip 属性仅在设置了 position: absolute | fixed 的元素上生效

<shape> 仅接受 rect() 矩形裁切,看起来似乎很废柴,因此一直被大家忽视,但用好 clip 属性能创造出许多黑魔法般的效果。

三、rect 初体验

按照规定,rect() 接受四个值:

clip: rect(<top>, <right>, <bottom>, <left>)  

<top><bottom> 指定相对于盒子上边框边界的偏移,<right><left> 指定了相对于盒子左边框边界的偏移。

这样说有点抽象,我们可以把 <top><bottom> 想象成 Photoshop 中的水平参考线<right><left>垂直参考线,而裁切区域就是它们所围成的矩形区域:

具体的可以参照这个图片裁切的 demo

当 bottom <= top 或者 right <= left 时,裁切区域不显示。根据这个特性,我们便可以创建对屏幕阅读器友好的隐藏元素:

.hide {
  clip: rect(0,0,0,0);
}

四、CSS3 黑魔法混入

如果只是像上面那样用,就显得有点庸常了。但是混入 CSS3 属性以后,clip 属性中隐藏的黑魔法便被打开了:

1. 制作环形进度条

如在之前的文章里描述过的,利用 clip 属性和 border-radius 属性裁出两个半圆环和一个半圆环的遮罩,便可以实现环形进度条:

  1. 裁切特殊形状

虽然clip 属性只接受 rect() 矩形区域裁切,但是配合上 border-radius 属性,便可以创建出意想不到的效果。

比如,我们用如下样式创建一个圆环:

.arms {
  position: relative;
  width: 80px;
  height: 200px;
  border: 10px solid #92cbd9;
  border-top-width: 20px;
  border-radius: 50%;
  box-sizing: border-box;
}

然后进行裁切:

.arms {
  clip: rect(0, 80px, 40px, 45px);
}

再在末端补上一个半圆,同样利用 clip 裁出:

.arms:after {
  content: '';
  position: absolute;
  right: 8px;
  top: 33px;
  width: 12px;
  height: 12px;
  background: #92cbd9;
  border-radius: 50%;
  clip: rect(6px, 12px, 12px, 0);
}

一只手臂的形状便画好了。以此类推,我们便可以创建出复杂的图形:

See the Pen Mr Squishworth Junior by Dolphin Wood (@idiotWu) on CodePen.

3. 特定边阴影

最初见到这个效果是在一丝姐的微博上,她采用了两个伪元素分别用于创建阴影和遮盖特定边缘。实际上,我们可以使用 rect 属性更快地达到目的:

如图进行裁切,由于外阴影是在盒模型之外,所以只要在想要保留的边上将裁切位置拉伸到阴影半径之外即可

对应的样式:

.box:before {
  content: '';
  position: absolute;
  width: 100%;
  height: 100%;
  box-shadow: 0 0 10px rgba(0,0,0,.4);
  clip: rect(0px,110px,210px,-10px);
  z-index: -1;
}

由于每次都要进行裁切位置的计算太麻烦,我们可以用 sass 封装一个 mixin:

%shadowOnSides {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: -1;
}

// Calculate clip rectangle
// eg: @include calcShadowClip(100px, 200px, 10px, left bottom);

@mixin calcShadowClip($width, $height, $radius, $sides: top right bottom left) {
  clip: rect(if(index($sides, top), -$radius, 0), if(index($sides, right), $width + $radius, $width), if(index($sides, bottom), $height + $radius, $height), if(index($sides, left), -$radius, 0));
}

// Create box-shadow on certain sides
// eg: @include shadowOnSides(100px, 200px, 10px, rgba(0,0,0,.4), top bottom);

@mixin shadowOnSides($width, $height, $radius, $shadowColor, $sides: '') {
  position: relative;
  width: $width;
  height: $height;
  box-sizing: border-box; // fix padding
  &:before {
    @extend %shadowOnSides;
    box-shadow: 0 0 $radius $shadowColor;
    @if $sides != '' {
      @include calcShadowClip($width, $height, $radius, $sides);
    }
  }
}

这样便能够轻松创建出特定边阴影的效果。

See the Pen SCSS Mixin for creating box-shadow on certain sides by Dolphin Wood (@idiotWu) on CodePen.

五、结语

clip 属性是 CSS2.1 中的属性,在最新的规范中已经不被推荐使用。取而代之的是更加规范标准的clip-path属性,利用该属性可以创建出更加酷炫的不规则图形:

但是个人对这个新属性并没有深入研究过,这里先推荐两篇文章给大家解解馋:

  1. CSS和SVG中的剪切——clip-path属性和<clipPath>元素
  2. Clipping and Masking in CSS

(全文完)

参考资料

  1. Clip | css3教程-css3实例-css3动画 | W3CPlus
  2. CSS clip:rect矩形剪裁功能及一些应用介绍 « 张鑫旭-鑫空间-鑫生活
  3. 浅谈 CSS display:none 对 SEO 及屏幕阅读器(screen reader)的影响