CSS艺术 视觉效果

单侧投影

先来回忆一下 box-shadow 的几个属性值

1
2
/*          水平偏移  垂直偏移  模糊半径  扩张半径  颜色   内侧阴影*/
box-shadow: h-shadow v-shadow blur spread color inset;

模糊半径和扩张半径共同控制一个阴影的大小.

如果元素原始的尺寸是 100*100, 设置它的模糊半径为 5px,最终的阴影尺寸是 (100+5)*(100+5),所以如果没有进行平移操作, 每个边上都会延伸出 5px 的阴影.

这时再设置它的扩张半径属性,会在已有的阴影尺寸上再继续计算, 而且这个值可以是一个负值,如果设置扩张半径为-5px,它会压缩原有的阴影尺寸,最终变为 (105-5)*(105-5),这个属性并不会切割掉设置了阴影的部分,实际上可以看作是它压缩了实心部分也就是元素所占据的那部分的大小.因此现在每个边上都看不见阴影了,但阴影还是存在的,它被缩小到和元素面积相同,被元素覆盖住

知道了这些实现单侧投影可能就有了一些思路,可以设置一个 4px 的模糊半径, 这样元素四边就都有了 4px 的阴影,再垂直或水平方向上偏移这个阴影 4px,现在一个边上就会有 8px 的阴影,它的对边会被遮盖住,两个临边还是 4px 的阴影,最后在使用扩张半径设置为-4px,把多余的阴影遮盖住,为了效果明显一点,偏移量可以比模糊半径多几个像素

1
box-shadow: 0px 6px 4px -4px #000;

不规则投影

也许你还是想用 box-shadow 来实现,但事实上 box-shadow 也无能为力,有些场景 box-shadow 并不会正确的显示阴影的效果.

  • 半透明的(图片,背景图片,border-image) 阴影不会穿过半透明区域,实际上还是围绕在元素周围
  • 元素设置了虚线或点或半透明的边框,但没有背景(或者 background-clip 不是 border-box 时)
  • 伪类元素拼接
  • 切角或折角的效果
  • clip-path 生成的图形

这里需要用到一个从 SVG 中借鉴来的属性 filter,因为模糊算法不一样肯能有细微的差别

1
filter: drop-shadow(4px 4px 2px red);

注意:这个属性会一视同仁的把所有透明区域都打上阴影,所以如果是元素中的文字,如果没有背景颜色也会打上阴影,而且不受 text-shadow 影响,因为他会给 text-shadow 的阴影打上阴影

色彩滤镜

有的时候想给张图片转换为灰度图,但又需要保留原有的对比度,最好是能与鼠标有交互效果.

虽然通过 canvas 可以通过脚本的方式进行修改,但是成本很高,也有性能问题. css 提供了滤镜系统可以使用,但不是所有的浏览器都兼容.

具体属性参考 MDNW3C

1
2
transition: 0.5 filter;
filter: sepia(1) saturate(4);

![0002.png]

这种方式基本满足效果,但是滤镜的叠加有时会显得过度不自然, 另外一种方式就是混合模式,将上下两层效果混合在一起,一个最重要的区别就是混合叫过不能使用动画,所以混合模式中,只能控制外层的样式过度进行混合

mix-blend-mode MDN W3C

1
2
3
4
5
6
<div class="wrap" > <div class="box" > </div > </div > .wrap {
background: hsla(1, 1, 100, 0.8);
}
.box {
mix-blend-mode: luminosity;
}

毛玻璃效果

首先能想到的就是文字模糊的问题, 如何能保证背景模糊但是不影响文字, 这里需要使用两个元素,但是为了简洁可以使用伪元素

另一个元素就是外层的背景图片元素,这里以 body 元素为例, 所以 html 结构如下

1
2
3
<body>
<div class="box">玻璃效果中的文字</div>
</body>

先把一些简单的样式实现,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
body {
height: 100%;
background: url(./cover1.jpg) 0 / cover;
}

.box {
position: relative;
/*
当把一个元素移动到父元素下面的时候,一定要注意父元素的上级元素有没有背景
如果父元素上级元素有背景,那个移动的这个元素的背景会出现在父元素上级元素背景的下面
提升box的层级,防止before移动到box下面的时候背景会在body背景的下面
*/
z-index: 1;
}
.box::before {
content: "";
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
background: url(./cover1.jpg) 0 / cover;
/* 移动到父元素的下面,防止背景挡住文字 */
z-index: -1;
}

下一个重要的问题就是如何让 before 元素中的背景和 body 的背景完全对其,一种可能的办法是获取父元素背景的大小,子元素使用相同的大小,再获取子元素相对于父元素偏移量,为 background-position 设置相同的偏移量

虽然这种办法可行,但是一旦父元素存在滚动条会变的很复杂, 一个比较好的方法就是使用 background-attachment 属性.

background-attachment 设置背景图像是否固定或者随着页面的其余部分滚动。当属性值为 fixed 的时候表示,布景图相关于视口固定,所以随页面翻滚布景不动,相当于布景被设置在了 body 上。也就是说给任何元素的布景图设置 background-attachment:fixed;效果都是一样的,都是相关于视口,因为一个网页只要一个视口,该布景和元素现已没关系

所以分别给这两个元素添加这个属性,但要注意的是填充方式需要相同,否则会有错位的现象, background 最后一个属性就是 background-attachment 的简写形式.

最后通过一个负数的 margin 来解决模糊效果在临近边界的时候会衰弱, 并用外层元素的 overflow:hidden 把多余的部分剪裁掉

1
2
3
4
5
6
7
8
9
10
11
body {
background: url(./cover1.jpg) 0 / cover fixed;
}
.box {
overflow: hidden;
}
.box:after {
margin: -20px;
background: url(./cover1.jpg) 0 / cover fixed;
filter: blur(20px);
}
打赏
  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
  • Copyrights © 2015-2025 SunZhiqi

此时无声胜有声!

支付宝
微信