使用CSS构建Glassmorphism UI效果

发布于 大漠

最近看了一些设计相关的教程,看到几个有关于设计效果相关的专业术语,比如微软的 Fluent设计系统 中的亚克力效果(Acrylic Material),Mac OS的磨砂玻璃效果(Frosted Glass)。另外,记得去年 @Michal Malewicz的《Neumorphism in user interfaces》一文掀起了围绕“Neumorphism”设计风格的讨论,当时一度认为该设计风格将会是2020年的设计趋势,事实上去年并没有以这种设计风格为主流,而且很多人认为“Neumorphism”的UI风格是一种可怕的设计风格。不过,最近在Codepen上看到另一种设计风格,这种风格同样是@Michal Malewicz 提出来,并称之为“ 玻璃变形(Glassmorphism) ” 的UI风格,这种风格已在一些产品中出现,比如三星的一些广告和MKBHD的介绍视频。在设计圈很多设计师提出“玻璃变形(Glassmorphism)”设计风格运用得当,可以起到引人注目的效果。

既然她(Glassmorphism)有可能会成为一种设计趋,或者说有可能在你的项目中会运用这种设计风格,那么做为Web开发者就很有必要的了解或掌握如何使用CSS实现这种UI设计风格。那么今天我们就一起来看看怎么用代码实现今天所说的UI效果。

发展历程

这里有几个关键词,即“亚克力(Acrylic Material)”、“磨砂玻璃(Frosted Glass)”、“Neumorphism”和“Glassmorphism”。但它们的出现在我们的世界中是“磨砂玻璃(Frosted Glass)”,“亚克力(Acrylic Material)”,“Neumorphism”,然后才是“Glassmorphism”。

早在2013年的时候,iOS系统首次引入了“背景模糊(Background Blure)”效果,这是一个相当激进的变化。除了iOS系统之外,Windows Vista操作系统也有这种“背景模糊”的UI效果:

比如上图中左侧的图,在iOS系统的屏幕上从上慢慢往下拉出系统消息时,你会发现新的面板(消息面板)下面的图标慢慢的淡出和变得模糊。这是一个非常有意思的效果,而且也很受大家的喜爱。

或许你已经发现了,Mac OS Big Sur把这种效果(透明到模糊的效果)再一次增强了。比如下图中Sketch设计软件的窗口背景模糊是最清晰可见的(下图中白圈圈中的部分):

这种背景模糊的效果后来被称之为“磨砂玻璃(Frosted Glass)效果。Mac OS就是以这种磨砂玻璃效果而闻名。同样这种效果在Windows 10中引入,不过在Windows 10中用其他一些亮度(Light)和深度(Depth)、运动(Motion),材质(Material)、比例的东西来实现磨砂玻璃效果。这种效果用于创建“半透明纹理”,帮助构建视觉层次结构。

这种效果在微软的Fluent设计系统中也很受重视,并且将这种效果称之为“亚克力(Acrylic Material)”效果,并将该效果做为Fluent设计系统中的一个组件。

其实在过去的几年时间中,在UI界面设计中Flat设计Google的Material设计一直是主流,甚至在iOS7出现之前,最为流行的用户界面设计是“Skeuomorphism”(模拟现实世界对象的界面对象),因为它使人们能够很容易地过渡到使用数字设备:

就在去年(2020年),@Michal Malewicz的《Neumorphism in user interfaces》一文发表之后,掀起了“Neumorphism”的讨论。事实上,“Neumorphism” UI风格结合了Flat设计和Skeuomorphism两者的优点:

“干净的界面,通过巧妙地使用高光和阴影,让界面变得更加坚固”!

也正因为如此,@Jason Kelley才会称之为“New Skeuomorphism”,之后@Michal Malewicz将这种界面效果称为“Neumorphism”。

Neumorphism UI主要好处是“新”,至少会持续很长的时间,它为界面带来了“新感觉”,并使其脱颖而出。它也可以和其他样式混合使用,这样就避免了界面呆板,而让界面变得柔软凸起(凹陷),更具质感。但Neumorphism UI也有着致命的缺陷。那就是可访问性

访问互联网的人群(或者使用你产品的用户群体)可能会是下图中的某一(或同时是几个)类型之一:

而Neumorphism UI对于认识、身体和视觉有障碍的用户是致命的:

或许正因为如此,很多设计师对该UI风格并不怎么认可。即使如此,也有人说Neumorphism UI应用在卡片或滑块上是一个最佳的场景。但这也是有前提条件的,那就是卡片的结构是正确的。图像、图标和字体之间的层次结构应必须清晰,而且间距必须明确。

针对这一点而言,如果层次设计的不够清晰的话,那么Neumorphism风格的卡片也会令用户感到糟糕,因为用户在卡片上得不到想的焦点信息。

简而言之,Neumorphism UI风格存在一些缺陷,但这些缺陷并不是不能克服的。如果我们的设计师能够很好的去权衡其中的利弊以及较好的去把控整个设计风格,还是能设计出适合于实际生产中的Neumorphism UI界面。

而在2021年的新年伊始,在DribbbleBehance设计平台上出现了另一种UI设计风格,那就是“Glassmorphism” UI风格。

“Glassmorphism” UI风格引人注目,色彩斑斓,倾向于透明和多层次的方法。这种UI风格类似于乳白色的玻璃表面。

设计细节

我们花一些篇幅介绍了这几种设计风格。不过我想,更多的同学可能最为关注的是如何用代码实现这些设计风格效果。那么在和大家开始撸码之前,我还是想再花一点时间来和大家聊一下这几种设计风格在设计上的一些必备要素和相应的风格。

磨砂玻璃(Frosted Glass)

就磨砂玻璃效果而言,他很简单,在设计上分将分为三个层:

  • 背景层
  • 模糊层
  • 内容层

亚克力(Acrylic Material)

亚克力(Acrylic Material)以凸显其独特外观和属性。 从半透明度、模糊和噪点设置开始,为平滑图面增添视觉深度和维度。 我们添加了排除混合模式层,以确保放置在 Acrylic 背景上的 UI 的对比度和可读性。 最后,我们添加了各种颜色色调,以供用户进行个性化设置。 这些图层协同作用,形成了全新的实用材料。

Neumorphism UI

Neumorphism UI有一个非常明显的特征,该UI风格具有两个阴影,一个阴影为负值,另一个阴影为正值,但要使其正常显式,那么背景不能全是黑或白,至少需要一点色调,以便可见深色和浅色阴影。你可以使用任何色调作为背景,以便根据你的选择将其变暖或变冷。但是必须能看到深色或者浅色投影。

比如下面这个示例:

Glassmorphism UI

Glassmorphism UI效果本身很简单,但有些地方需要考虑。其一,对象离我们越近,它吸引的光线就越多。在这种情况下,这意味着它将更加透明一些。

整个效果的基础来自于阴影、透明和背景模糊的组合。这种风格只能使用一个透明层,也可以使用多个透明层,但当到少两个层次的透明层出现在一个相当繁忙、色彩丰富的背景上时,这种风格最为突出和明显。

然后,实现Glassmorphism UI风格并没有使整个形状(元素)透明,只有它的填充才是透明:

还有一点,背景对该UI效果也有着决定性的影响。运用于Glassmorphism UI中的背景不能太简单或太暗淡,否则效果不明显。同时也不能太细致。

这或许就是苹果选择彩色背景作为Mac OS Big Sur默认壁纸的原因。在挑选背景时要确保它有足够的色调差异,让玻璃效果实际可见。最后,你可以尝试在你的形状上添加一个1px的内边框,并具有一定的透明度。它可以模拟玻璃边缘,使形状从背景中更加突出。

开始编码吧

实现上述提到的这几种UI风格,我们会用到CSS的filteropacitybackdrop-filterbox-shadow等属性。先来看“磨砂玻璃”的效果。我们将构建一个Card组件,卡片效果带有磨砂玻璃效果,而且这张卡片将会放置大下面这张背景图上:

将该图片设置为卡片容器的背景,示例中就将其放置在<body>元素中:

body {
    background: url("/glassmorphism-css-11.jpeg") no-repeat center fixed;
    background-size: cover;
}

Card添加一些基本样式让它看起来好顺眼一点:

磨砂玻璃的效果关键处是背景和内容层之间有一个模糊层,就我们的示例而言,就是.card自己具有一个模糊背景效果。在CSS中我们可以使用filter来构建模糊效果:

.card {
    background: rgba(255,255,255,0.3);
    filter: blur(10px);
}

如果直接在容器.card使用filterblur()特性,那么其子元素都会受影响:

如果不希望filter影响其子元素,我们需要单独构建一个层,用来处理这个模糊背景效果。我们可以借助 CSS伪元素::before 来构建这个模糊背景:

.card {
    position: relative;
    background: inherit;
    overflow: hidden;
}

.card::before {
    content: "";
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    border-radius: 8px;

    z-index: 1;
    background: inherit;
    box-shadow: inset 0 0 0 200px rgba(255, 255, 255, 0.2);
    filter: blur(10px);
}

.card > * {
    position: relative;
    z-index: 2;
}

注意,在上面示例代码中,在.card.card::before中都运用了background: inherit,让元素继承其父元素的背景。这个时候看到的效果如下:

按这样的方式在头像的边框和底部的内容区域添加磨砂玻璃效果:

.card,
.card__media,
.card__content {
    position: relative;
    background: inherit;
    overflow: hidden;
}

.card::before,
.card__media::before,
.card__content::before {
    content: "";
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    border-radius: 8px;

    z-index: 1;
    background: inherit;
    box-shadow: inset 0 0 0 200px rgba(255, 255, 255, 0.2);
    filter: blur(10px);
}

.card > * {
    position: relative;
    z-index: 2;
}

.card__media img {
    top: 5%;
    right: 5%;
    bottom: 5%;
    left: 5%;
    position: absolute;
    z-index: 2;
    width: 90%;
    height: 90%;
    z-index: 2;
}

.card__media::before {
    box-shadow: inset 0 0 0 200px rgba(255, 255, 255, 0.06);
}

.card__content::before {
    border-radius: 0 0 8px 8px;
    box-shadow: inset 0 0 0 200px rgba(255, 255, 255, 0.06);
}

这个时候你看到的效果如下:

CSS的backdrop-filter属性出现之后,使用该属性替代filter制作磨砂玻璃效果会更逼真。基于上面的示例稍作调整,可以得到一个更逼真的磨砂玻璃效果:

.card,
.card__media,
.card__content {
    background-color: rgba(255, 255, 255, 0.06);
    backdrop-filter: blur(20px);
}

使用backdrop-filterfilter最的大的区别就是,backdrop-filter不会影响其子元素,这样就不需要借助伪元素来单独构建磨砂玻璃的模糊层。

接着使用CSS来写亚克力的效果。实现亚克力效果和磨砂玻璃的效果相似,同样可以使用filterbackdrop-filter。使用filter实现亚克力效果,需要新增一个::after伪元素添加纯色背景层。同样在上面的示例基础上,我们先来看filter实现亚克力的效果:

.card,
.card__media,
.card__content {
    position: relative;
    overflow: hidden;
    background: inherit;
    z-index: 1;
}

.card::before,
.card::after,
.card__media::before,
.card__media::after,
.card__content::before,
.card__content::after {
    content: "";
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    border-radius: 8px;
}

.card::before,
.card__media::before,
.card__content::before {
    filter: blur(10px);
    background: inherit;
    z-index: -1;
}

.card::after,
.card__media::after,
.card__content::after {
    opacity: 0.3;
    background: #fff;
    z-index: -1;
}

.card__media::after {
    opacity: 0.5;
    background-color: #000;
}

.card__content::after {
    border-radius: 0 0 8px 8px;
    background-color: #000;
}

.card > * {
    position: relative;
    z-index: 1;
}

同样的,可以使用backdrop-filter来构建亚克力效果:

.card,
.card__media,
.card__content{
    backdrop-filter: blur(30px) saturate(125%);
    background-color: rgb(217 200 200 / 16%);
}

值得注意的是,不管使用filter还是backdrop-filter实现的亚克力效果都没有包括UWP文档中提到的澡音或排除层,但这样做的确调高了饱和度以获得更多的颜色。

Neumorphism UI的效果和磨砂玻璃以及亚克力效果都有所不同,正如《聊聊Neumorphism UI效果》文中提到的,Neumorphism UI最大的特点是运用CSS的box-shadowbackground-color颜色的结合。

.card {
    background-color: #f1f8fd;
    position: relative;
    box-shadow: 20px 20px 30px 0 rgba(0, 0, 0, 0.1);
}

.card__media {
    border: 3px solid #f1f8fd;
    box-shadow: 
        20px 20px 20px rgba(0, 0, 0, 0.07),
        -20px -20px 20px rgba(255, 255, 255, 0.7), 
        6px 6px 6px rgba(0, 0, 0, 0.09),
        -6px -6px 6px rgba(255, 255, 255, 0.9);
}

.card__button {
    color: #222e51;
    box-shadow: 
        9px 9px 9px rgba(0, 0, 0, 0.06),
        -9px -9px 9px rgba(255, 255, 255, 0.6),
        inset 5px 5px 5px rgba(0, 0, 0, 0.07),
        inset -5px -5px 5px rgba(255, 255, 255, 0.7);
    background-color: transparent;
    z-index: 1;
}

.card__button::before {
    content: "";
    position: absolute;
    top: 3px;
    right: 3px;
    bottom: 3px;
    left: 3px;
    border-radius: 5px;
    background-color: #fed0b3;
    box-shadow: 
        inset 3px 3px 3px rgba(255, 255, 255, 0.5),
        inset -3px -3px 3px rgba(0, 0, 0, 0.05);
    z-index: -1;
}

在社区中有一款在线工具 Neumorphism.io 可以自动生成Neumorphism UI效果所需要的CSS代码。

另外在Codepen上也能找到很多有关于 Neumorphism UI的Demo效果

最后来看Glassmorphism UI制作。我们把上面的示例背景图换成下图:

基于上面的示例来调整CSS。首选调整.card的圆角,并且使用渐变色来填充,渐变颜色是带有不同透明度的#fff颜色,第一个是40%透明度,第二个是10%的透明度:

.card {
    border-radius: 40px;
    background-image: linear-gradient(
        to right bottom, 
        rgba(255, 255, 255, .4),
        rgba(255, 255, 255, .1)
    );
}

接着使用backdrop-filter来模拟玻璃模糊的效果。将blur()的值设置为20px:

.card {
    border-radius: 40px;
    background-image: linear-gradient(
        to right bottom,
        rgba(255, 255, 255, 0.4),
        rgba(255, 255, 255, 0.1)
    );
    backdrop-filter: blur(20px);
}

现使用渐变添加一个渐变边框效果,不卡片增加额外的抛光效果。当玻璃表面重叠时,有助于建立视觉层次感。

.card {
    border-radius: 40px;
    backdrop-filter: blur(20px);
    border: 3px solid transparent;
    background-image: linear-gradient(
        to right bottom,
        rgba(255, 255, 255, 0.4),
        rgba(255, 255, 255, 0.1)
        ),
        linear-gradient(
        to right bottom,
        rgba(255, 255, 255, 0.5) 0%,
        rgba(255, 255, 255, 0) 40%,
        rgba(255, 72, 219, 0) 55%,
        rgba(255, 72, 219, 0.5) 100%
        );
    background-origin: border-box;
    background-clip: padding-box, border-box;
}

最后再给其添加一点阴影加强视觉层次感。

.card {
    border-radius: 40px;
    backdrop-filter: blur(20px);
    border: 3px solid transparent;
    background-image: linear-gradient(
        to right bottom,
        rgba(255, 255, 255, 0.4),
        rgba(255, 255, 255, 0.1)
        ),
        linear-gradient(
        to right bottom,
        rgba(255, 255, 255, 0.5) 0%,
        rgba(255, 255, 255, 0) 40%,
        rgba(255, 72, 219, 0) 55%,
        rgba(255, 72, 219, 0.5) 100%
        );
    background-origin: border-box;
    background-clip: padding-box, border-box;
    box-shadow: 20px 20px 22px rgba(0,0,0,0.2);
}

我们按这个方式给用户头像和底部内容区域添加相似的玻璃模糊的效果:

.card__media {
    position: relative;
    background-color: rgba(255, 255, 255, 0.06);
    backdrop-filter: blur(20px);
}

.card {
    border-radius: 40px;
    backdrop-filter: blur(20px);
    border: 3px solid transparent;
    background-image: linear-gradient(
        to right bottom,
        rgba(255, 255, 255, 0.4),
        rgba(255, 255, 255, 0.1)
        ),
        linear-gradient(
        to right bottom,
        rgba(255, 255, 255, 0.5) 0%,
        rgba(255, 255, 255, 0) 40%,
        rgba(255, 72, 219, 0) 55%,
        rgba(255, 72, 219, 0.5) 100%
        );
    background-origin: border-box;
    background-clip: padding-box, border-box;
    box-shadow: 20px 20px 22px rgba(0, 0, 0, 0.2);
}

.card__content {
    background-color: rgba(255, 255, 255, 0.06);
    backdrop-filter: blur(20px);
    border-radius: 0 0 40px 40px;
}

如果使用的背景不同时,在卡片使用的背景颜色等也应该做一定的调整:

@Aysenur Turk在Codepen构建了一个Glassmorphism Creative Cloud App Redesign效果,如果你对Glassmorphism UI效果感兴趣的话,可以查看下面Demo中的代码:

如果觉得自己手撸撸不出好的Glassmorphism UI效果,也可以使用 @hype4 提供的在线生成CSS代码的工具

另外,你想找相关的参考案例的话,可以在GithubCodepen上查看

小结

磨砂玻璃(Frosted Glass)、亚克力(Acrylic Material)、Neumorphism UI 和 Glassmorphism UI 是不同时间的设计产物,对于Web开发者而言,虽然对这方面的关注与理解不如设计师,但我们需要第一时间掌握如何将UI效果还原出来。虽然这几种效果有所不同,但他们都有着自己的规律,特别是磨砂玻璃、亚克力和Glassmorphism 非常的相似,我们可以使用CSS的filterbackdrop-filter来实现。文章中介绍的案例,实现手段都是相似的,但要做出好的效果,我们还是在细节上稍做处理,这也是实现优秀UI的难度之处。如果你在这方面更好的建议,欢迎在下面的评论中与我们共享。