Michael

写写代码,说说人生

您好,我是Michael,欢迎来到我的个人家园。
代码搬运工,目前就职于XX证券,努力修行中。


H5 / Java / Objc / Swift / Vue / RN

CSS中的剪裁和遮罩

剪裁和遮罩都是用来隐藏元素的一些部分、显示其他部分的。当然了,这两者还是有区别的。区别主要在于这几方面:他们能做的东西,不同的语法,涉及到的不同技术,是新的还是旧的,以及浏览器支持的差异。

但不幸的是总是有相当多的过时信息在那儿,所以一起来看看能否解决这个问题。

剪裁和遮罩之间的区别

遮罩使用的是图像,剪裁使用的是路径。

想象一张从左到右、从黑到白渐变的正方形图像,它可以是一个遮罩。对于应用了这个渐变遮罩图像的元素,它在遮罩图像的黑色部分是透明(透视)的,而在遮罩图像的白色的部分是不透明(正常)的。所以作出的结论是:这个元素是从左到右淡入的。

而剪裁一直都是矢量路径的。路径之外的部分是透明的,路径里边的部分是不透明的。

个人觉得有点混乱。因为很多时候可能会碰到某个关于遮罩的教程用的是一个在黑色上有白色矢量形状的遮罩图像,这和剪裁基本是同一个原理。但这还好,它只是混淆了一点东西。

旧的(不推荐使用)clip

clip 属性是CSS中出现的第一种剪裁(除了 overflow: hidden;,它不是真正的剪裁)。(MDN)。

它的示例如下:

.element {
    clip: rect(10px, 20px, 30px, 40px);
}

这四个值和margin/padding属性的值是同样的顺序(上右下左):

  • 10px 为到元素顶部的距离
  • 20px 为到元素右边的距离
  • 30px 为到元素底部的距离
  • 40px 为到元素下边的距离

<font color=#0099ff> 在CSS中, clip 属性是已过时的</font>,也就是说它已经不再建议被使用,因为有一个更新的、规范的版本,各个浏览器也将集中努力使用它。

clip 也是有一些优势的:因为 clip 是运行在浏览器中的,它可能会一直有效。而浏览器对它的支持是非常强大的:几乎是有史以来的每一个浏览器。另外,我也听说过了,它作出的动画效果胜过其它的新方法。

但是比起它的优势,clip 有两个更为重要的弱点,这也使得它难以被广泛地使用:

  • clip 只对绝对定位的元素有效;
  • clip 只能用于矩形,即rect()函数。

这真的是非常大的限制!所以来让我们接着说。

新的 clip-path

在CSS中新的、推荐使用的应用于剪裁元素的版本是 clip-path ,你可能认为它的代码应该是这样简单的:

.element {
    /* NOPE */
    clip-path: rect(10px, 20px, 30px, 40px);
}

但这行不通(即使作为前缀,或任何地方),最终我们还是会得到 rectangle()所以还不是时候

Postponed rectangle() to level 2

新的解决方法是使用inset():

.element {
    /* Also can take single values to make all sides the same, or 2 values (vert/horz), or 3 values (top/horz/bottom). */
    clip-path: inset(10px 20px 30px 40px);
}

你会注意到各个值的中间没有用逗号隔开,语法也不一样,但是最终做的东西还是一样的。

那么 clip-path 还可以用来做什么东西呢(在一些浏览器中)?圆、椭圆以及多边形。下面是一些示例:

.clip-circle {
    /* OLD VALUE example: circle(245px, 140px, 50px); */
    /* Yep, even the new clip-path has deprecated stuff. */
    clip-path: circle(60px at center);
}

.clip-ellipse {
    /* OLD VALUE example: ellipse(245px, 80px, 75px, 30px); */
    clip-path: ellipse(60px 40px at 75px 30px);
}

.clip-polygon {
    /* Note that percentages work as well as px */
    clip-path: polygon(5% 5%, 100% 0%, 100% 75%, 75% 75%, 75% 100%, 50% 75%, 0% 75%);
}

多边形是非常强大的。Ryan Scherf 在CSS-Tricks上发布了一个以编程方式使用多边形生成简略效果的教程

我强烈建议大家去Bennet Feely的 Clippy 网站上玩一下这个东西: CSS中裁剪和遮罩-Clippy

从理论上讲,这是 clip-path 将会支持的(作为它的”基本形状“):

.clip-examples {
    clip-path: rectangle(x, y, width, height, rounded-x, rounded-y);
    /* Looks like this is what rect() used to be like with clip */ /* Will replace inset(), I suppose */
    clip-path: inset-rectangle(from top, from right, from bottom, from left, rounded-x, rounded-y); 
    
    clip-path: polygon(a, bunch, of, points);
    clip-path: circle(radius at x, y);
    clip-path: ellipse(radius-x, radius-y at x, y);
}

我似乎难以找到关于 path() 是否会永远有效的信息

通过SVG定义的标签来使用``clip-path

你不需要在CSS中定义 clip-path 的值,因为它能够引用SVG中定义的 <clipPath> 标签元素。下面是它的使用示例:

html代码:

<img class="clip-svg" src="harry.jpg" alt="Harry Potter">
<svg width="0" height="0">
    <defs>
        <clipPath id="myClip">
            <circle cx="100" cy="100" r="40" />
            <circle cx="60" cy="60" r="40" />
        </clipPath>
    </defs>
</svg>

css代码

.clip-svg {
    clip-path: url(#myClip);
}

Sara Soueidan也有个这样的示例

但是使用SVG定义的 clip paths 有个相当严重的问题:它们都被固定在文档的左上角。下面是这个问题的一个示例:

我可能只是忘了什么东西,但是我没有找到一个明确的方法能让路径随着应用了它的元素一起移动,就像当你直接使用CSS中的一个基本元素时,clip-path 运行的方式。

clip-path 的动画/过渡

当你声明了一个基本形状作为一个 clip-path 路径时,你可以将它变成动画!Dirk Schulze 有一篇涉及这一方面的精彩文章,下面是它的简单示例效果:

这有一个简单的代码样例:

div {
    transition: 0.4s cubic-bezier(1, -1, 0, 2);
    clip-path: polygon(50% 5%, 0% 100%, 100% 100%);
}

div:hover {
    clip-path: polygon(50% 19%, 0 76%, 100% 76%);
}

来尝试一下:

Masking

Masking是只有webkit才有的版本,你可以通过衔接一个栅格图像或者定义一个渐变作为遮罩。它的代码是这样写的:

img {
    width: 150px;
    -webkit-mask-image: -webkit-gradient(
        linear, left top, right bottom,
        color-stop(0.00,  rgba(0,0,0,1)),
        color-stop(0.35,  rgba(0,0,0,1)),
        color-stop(0.50,  rgba(0,0,0,0)),
        color-stop(0.65,  rgba(0,0,0,0)),
        color-stop(1.00,  rgba(0,0,0,0))
    []());
}

据我所知,这是不推荐使用的。因为渐变语法绝对不推荐使用,但当我把它改成新的语法时,它就无效了。所以呀,它可能被弃用,但是目前仍然可用:

另外,遮罩催生了像WebKit图像擦除这样的现在仍然有效的旧版教程(你懂的,在 Blink / Webkit 领域还在使用)。

在我查到的更现代的参考文献里,只提及了遮罩在SVG中被定义以及在CSS中被ID或URL引用。下面是一个例子,两种方式。mask定义在SVG中,在左边,image图片是作为SVG中的一个标签;在右边,遮罩是被应用于HTML中的img标签元素(右边的图目前只能Firefox浏览器中看到)。

在Firefox中也可以看一下这个示例,这是从Dirk Shulze的文章中取出来的示例代码。这种东西目前还有有点危险的,因为它不能运行于 Blink / Webkit ,它会完全删除它应用的元素。

你也可以将整个SVG文件链接起来作为遮罩,就像下面这样:

.mask {
    mask: url(mask.svg);
}

遮罩类型

.mask {
    mask-type: luminance; /* white = transparent, grays = semi-transparent, black = opaque */
    mask-type: alpha;     /* transparent areas of the image let image through, otherwise not */
}

边界遮罩

这和CSS中 border-image 的运行方式非常相像。你定义一个SVG图像,然后应用 nice-slice scaling 样式。像一个井字游戏板上的图像。在拐角处使用拐角,边缘(可)沿边缘重复,中间(可)在中间延展。下面是基础的使用示例:

.border-mask {
    /* Note that the properties aren't quite the same */
    -webkit-mask-box-image: url(stampTiles.svg) 30 repeat;
    mask-border: url(stampTiles.svg) 30 repeat;
    /* Image, again, from http://www.html5rocks.com/en/tutorials/masking/adobe/ */
}

下面是普通遮罩vs边缘遮罩的示例:

浏览器支持

这很难去简明扼要地总结,因为他们不同的属性,甚至在所有的地方,value 有不同的支持级别。且不说你如何使用、在哪些方面使用它们。这还是一片荒野,所以我建议把它们作为积累提升,努力做到你目前能做到的最好的地步。这可能有点困难,因为甚至连 Modernizr 的检测功能也还没有包括这一方面。

正如加前缀说的:在几乎所有东西上都记得非前缀以及 -webkit- 前缀一起使用。

最近的文章

Bootstrap栅格系统使用方法

如果你以前使用过 Bootstrap2 或者了解过响应式技术,那么肯定对 Bootstrap栅格系统 并不陌生,由于栅格系统的引入,使得 Bootstrap 的跨设备布局显示变得可能。什么是栅格系统栅格系统是指,将页面布局划分为等宽的列,然后通过列数的定义来模块化页面布局。Bootstrap 的栅格系统采用了 1-12 列的模式,并且通过比例计算来设置你定义的列宽。例如你这一行想要采用两列的布局模式,那么每列的宽度都为外容器的50%,不管你用什么设备浏览,它都会采用这样的比例进行展示。不过...…

Web前端-BootStrap继续阅读
更早的文章

为什么BootStrap要默认12列

今天被问了一个问题:有没有想过为什么Bootstrap要默认是12列?呃,好吧,用了Bootstrap一段时间,的确没想过为什么要默认是12列,隐隐约约觉得是因为布局比较方便,常见的分2块,3块,4块,都可以方便分完。既然有假设,那还是要求证一下。谷歌上一阵搜索。 Contrary to the question’s parenthetical, Bootstrap was always at 940px wide, and not 960px, even with the origin...…

Web前端-BootStrap继续阅读