随着 Web技术不断的革新,以往很多依赖于图片展示的布局能较轻易地通过代码来实现,而且现在的布局也不仅仅局限于平面的布局。实际上也有一些伪3D,甚至是3D的布局效果。这样的布局主要目的是为了增强一个立体的空间感。比如我们常见的层叠的效果,飘带等效果,如下图所示:
还有一些效果类似于下图的效果:
这样的交叉效果就是我们今天要深入聊的一个效果。
简单地分析一下
就上图这样的一个效果,看上去是一张图片穿叉在一个边框中,但一般穿叉的效果是图片在边框的下面或图片在边框的上面。但要实现上图的效果,还着实不是一件易事。那么问题了,如果你的业务中要实现上图这样的一个效果,你会怎么来做呢?
拿到这样的一个效果,一眼看上去就是两个层:
如果用两个层来处理的话,要实现我们想要的效果还是有一定的难度的。按照两层的思路来做,实现的效果是红框在图片的上面或者红框在图片的下面:
如果用代码来写的话,会很简单:
<div class="design">
<img src="http://i.pravatar.cc/500?img=2" alt="" />
<div class="design__border"></div>
</div>
.design {
position: relative;
height: 300px;
width: 300px;
}
.design > * {
position: absolute;
height: 100%;
width: 100%;
}
.design__border {
box-sizing: border-box;
border: 15px #eb311f solid;
transform: rotate(45deg);
box-shadow: 0 0 10px #eb311f, inset 0 0 20px #eb311f;
}
效果会如下所示:
Demo 地址:codepen.io/airen/full/…
这离我们想要的效果还是非常的遥远。但要实现最终的效果还是有一定的方案的。
将旋转的边框拆分成多分
就效果而言,两条边在图片上面,另外两条边在图片下面。按照这样的思路,我们可以将design__border
元素的border
拆分出来。可以借助::before
和::after
来做。比如:
<div class="design">
<img src="http://i.pravatar.cc/500?img=2" alt="">
</div>
.design {
position: relative;
height: 300px;
width: 300px;
}
.design > * {
position: absolute;
height: 100%;
width: 100%;
}
.design {
&::before,
&::after {
content: '';
transform: rotate(45deg);
width: 100%;
height: 100%;
box-sizing: border-box;
border: 15px solid #eb311f;
position: absolute;
left: 0;
top: 0;
filter: drop-shadow(0 0 5px #eb311f);
}
&::before {
border-color: transparent #eb311f;
z-index: 1;
}
img {
z-index: 2;
}
&::after {
border-color:#eb311f transparent ;
z-index: 3;
}
}
效果如下:
Demo 地址:codepen.io/airen/full/…
来简单地看一下其合成过程:
Demo 地址:codepen.io/airen/full/…
注意,这个效果中我们使用了filter的drop-shadow()来实现阴影效果,就该示例而言,如果继续使用box-shadow不易于控制红色边框的阴影效果。
使用 CSS Masking特性
就该示例上下层穿插效果而言,用另一种话来描述的话就是部分红色边框不可见(因为他被图片给遮盖住了)。纵观CSS 中要让一个元素中部分不可见可以借助于CSS 的Masking和Clipping相关的特性。其中Masking是指CSS的mask
属性,而Clipping是掉CSS的clip-path
属性。
接下来我们来看看怎么借助CSS Masking中的特性实现我们想要的效果。
如果你对mask
或clip-path
有所了解的话,就应该知道接下来要怎么做了。大概的步骤如下:
通过前三步得到我们想要的合层图的效果,然后和图片结合在一起,并做一定的旋转,就可以得到我们最终想要的一个效果。这里最为关键的是蒙层图(即mask-image
),对应上图中的2
,大致如下:
整个效果所用的代码并不多:
.design {
position: relative;
height: 300px;
width: 300px;
}
.design > * {
position: absolute;
height: 100%;
width: 100%;
}
.design__border {
height: 300px;
width: 300px;
box-sizing: border-box;
border: 15px #eb311f solid;
transform: rotate(-45deg);
mask: url('masking3.png') no-repeat 0 0;
}
最终的效果如下:
Demo 地址:codepen.io/airen/full/…
使用Masking较为麻烦的是mask-image
制作麻烦。另外,要是你足够仔细的话,你可以看到就算代码中加入了box-shadow
(或者filter:drop-shadow()
)也会被mask
裁剪掉,如果你想让阴影能够显示出来,需要对mask-image
做扩大处理。
如果你不想使用mask
来做处理的话,那么你可以尝试着使用clip-path
来做,要是你感兴趣的话,不仿一试。
CSS Grid和混合模式的结合
接下来这种方式是一个全新的思路。将CSS Grid布局和CSS混合模式结合在一起实现。咱们先不看CSS怎么写,先来看其结果。该方案所用结构要比前面的复杂一些。整个结构分成了四个部分:
<div id=design>
<!-- 原图 -->
<img src=photo-1511692277506-3be3a7ab1686>
<!-- 旋转的红色边框 -->
<div id=rotatedBorder></div>
<!-- 网格布局层 -->
<div class=grid>
<div data-white></div>
<div></div>
<div></div>
<div data-white></div>
</div>
<div id=blend>
<img src=photo-1511692277506-3be3a7ab1686>
<div class=grid>
<div></div>
<div data-white></div>
<div data-white></div>
<div></div>
</div>
</div>
</div>
是不是复杂多了,整不明白为什么要这么写,不要紧,随着往下阅读你就能整明白。咱们先拆分一下整个效果:
其合成的过程如下图所示:
浏览器渲染的过程:
-
最底层是
img
(即示例中那张鸟图),对应下图中最左侧的那个灰色部分 -
然后旋转一个红色边框,对应下图中最左侧的那个红色边框
-
在它们的上层盖着一个网格(即
div.grid
),其中左上角和右下角是单元格带有白色背景 -
最后整了类似前面的一个副本,带有原图和另一个网格,只不过该网格右上角和左上角单元格带有白色背景,该层设置混合模式(正片叠底)
整个过程如下图所示:
下面我们分别用代码来完成这三个部分:
<!-- Step01 -->
<div class="design">
<img src="bird-photo.jpg">
<div class="rotated-border"></div>
</div>
.design {
position: relative;
height: 300px;
width: 300px;
}
.design > * {
position: absolute;
height: 100%;
width: 100%;
}
.rotated-border {
box-sizing: border-box;
border: 15px #eb311f solid;
transform: rotate(45deg);
box-shadow: 0 0 10px #eb311f, inset 0 0 20px #eb311f;
}
在前面的基础上增加第二层:
<!-- Step02 -->
<div class="design">
<img src="bird-photo.jpg">
<div class="rotated-border"></div>
<!-- Grid Level -->
<div class=grid>
<div data-white></div>
<div></div>
<div></div>
<div data-white></div>
</div>
</div>
.grid {
display: grid;
grid: repeat(2, 1fr) / repeat(2, 1fr);
}
[data-white]{
background-color: white;
}
在这里用到了CSS的grid
相关的知识,为了节省篇幅就不做过多阐述,感兴趣的话可以点击这里了解CSS Grid相关的知识。
接着是第三层,在第三层中,我们有原图和一个网格,其中不同的是网格填充白色的格子不同。代码如下:
<!-- Step03 -->
<div class="design">
<img src="bird-photo.jpg">
<div class="rotated-border"></div>
<!-- Grid Level -->
<div class=grid>
<div data-white></div>
<div></div>
<div></div>
<div data-white></div>
</div>
<!-- CSS Blend -->
<div class=blend>
<img src="https://images.unsplash.com/photo-1511692277506-3be3a7ab1686" alt="鸟图" />
<div class=grid>
<div></div>
<div data-white></div>
<div data-white></div>
<div></div>
</div>
</div>
</div>
.blend > * {
position: absolute;
height: 100%;
width: 100%;
}
这个时候在混合层上添加CSS混合模式,采用正片叠底的效果:
.blend {
mix-blend-mode: multiply;
}
现在我们只需要把三个层合在一起,即可。先来将第一步和第二步两层合起来:
接下来是混合层要起的作用了,怎么让第二层网格左上角和右下角能显示图片。还记得在混合层也用了一张图?这也是关键所在,先将第三层合在一起,但暂时将混合样式禁用一下:
开启混合模式样式:
.blend {
mix-blend-mode: multiply;
}
效果就出来了:
Demo 地址:codepen.io/airen/full/…
该方法相比以前面几种方案而言,更为灵活,只是HTML结构更为复杂。对于CSS混合模式的特性之强大之处,有兴趣的话建议阅读一些这方面的文章。你甚至还可以将 CSS mask 和 CSS 自定义属性相结合,实现其他的交叉布局效果:
Demo 地址:codepen.io/airen/detai…
如果你对这个示例效果感兴趣的话,可以移步阅读《SVG 遮罩》!
另外,CSS Grid在布局方面特别的灵活,只要发挥你的创意,他都能非常灵活的帮助你实现。比如@Andy Barefoot的示例,实现一个3D的布局效果:
Demo 地址:codepen.io/andybarefoo…
小结
这篇文章主要使用不同的方式来实现穿叉布局效果。同样的一个效果虽然可以使用不同的方式实现,但不管是哪种方式都有相应的局限性。要实现一个效果并不难,难是创新。好比最后一种方案,采用最新的CSS Grid布局和CSS混合模式的结合,让我们实现了这种带边框的穿叉效果。
当然,你可能还有别的方案更具创意,如果有兴趣的话不妨发挥发挥,用自己的方式实现同样的一个效果。同时欢迎您能在下面的评论中与我们一起分享。
如果你觉得该教程对你有所帮助,请给我点个赞。要是你喜欢 CSS ,或者想进一步了解和掌握 CSS 相关的知识,请关注我的专栏,或者移步阅读下面这些系列教程: