CSS Tips:水波纹

通常情况之下,Web 开发者都习惯了规则的矩形布局的效果,对于 Web 设计师提供的不规则布局,难免会带有一种恐惧与排斥的心理。事实上,**现代 Web 布局**技术构建这些不规则的布局,例如类似杂志类创意布局不规则图形的布局等,不再是问题。而且现代 CSS 提供了很多新特性,使这件事情变得更容易。要是你将 SVG 相关的特性以及一些工具结合起来,构建这些不规则的布局你可以手到擒来。比如,接下来我们要构建的水波纹布局效果,就是这样完成的。

如何构建水波纹

我们的目标非常明确,在 Web 上构建带有水波纹的 UI 效果。

到目前为止,我们有两种主流技术可以创建带有水波纹的 UI 效果:CSS 和 SVG 。接下来,我们分别来看看 CSS 和 SVG 是如何构建水波纹的。

CSS 创建水波纹

先从气泡图形着手,这样能更好的帮助大家理解 CSS 创建水波纹的过程。

在 CSS 的世界中,我们会常常利用 CSS 的一些特性,例如圆角边框阴影渐变变换裁剪和遮罩 等可以绘制出各种不同的不规则形状。比如,使用 border-radius 就可以快速构建出气泡图形:

直接上代码:

HTML 复制代码
<section class="bubble"></section>
CSS 复制代码
.bubble::after {
    content: '';
    border-top-left-radius: 50% 100%;
    border-top-right-radius: 50% 100%;
    position: absolute;
    bottom: 0;
    z-index: -1;
    width: 100%;
    background-color: #0f0f10;
    height: 85%;
}

这里借助 CSS 的伪元素 ::afterborder-radius 绘制了一个具有响应式的气泡图形,它看上去就类似一个椭圆:

Demo 地址:codepen.io/airen/full/...

现在,我们在这个椭圆上再叠加一个相似的椭圆,使其外观看上去类似一个水波纹:

HTML 复制代码
<section>
    <div class="curve"></div>    
</section>
CSS 复制代码
section {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    min-height: 400px;
    padding-top: 100px;
    background: #3c31dd;
}

.curve {
    position: absolute;
    height: 250px;
    width: 100%;
    bottom: 0;
    text-align: center;

    &::before,
    &::after {
        content: "";
        display: block;
        position: absolute;
        width: 55%;
        height: 100%;
        background-color: #3c31dd;
        border-radius: 100% 50%;
    }

    &::before {
        transform: translate(85%, 60%);
        background: #fff;
    }

    &::after {
        transform: translate(-4%, 40%);
        z-index: -1;
    }
}

Demo 地址:codepen.io/airen/full/...

效果只能说是一般般,而且这种方案有两个致命的缺点。首先,两个伪元素要完美地定位,可能有些困难(如果追求不够高,那么大多数情况来说,它也可用);其次,背景调整之后,伪元素的颜色也要随着改变:

如果你碰到相似的场景,那么可以考虑使用 CSS 自定义属性来修复它:

CSS 复制代码
:root {
    --bg: #fff;
}

body {
    min-height: 100vh;
    background-color: var(--bg);
}

.curve::before {
    transform: translate(93%, 48%);
    background: var(--bg);
}

Demo 地址:codepen.io/airen/full/...

特别声明,小心伪元素定位造成溢出问题

SVG 创建水波纹

使用 SVG 创建水波纹要比使用 CSS 简单地多。因为 SVG 最大的特性就是可以无限缩放,而且还不会失真。另外就是,可以使用 <path> 绘制出任何你想要的水波纹效果。即使你不懂 SVG ,你也可以借且诸如 Figma 这样的图形设计软件或在线工具(例如 getwaves.ioShapeDriverHaikei app 等)获得绘制水波纹的 SVG 代码。

URL:getwaves.io/

XML 复制代码
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1440 320" class="wave">
    <path fill="#0099ff" fill-opacity="1" d="M0,288L60,288C120,288,240,288,360,261.3C480,235,600,181,720,181.3C840,181,960,235,1080,245.3C1200,256,1320,224,1380,208L1440,192L1440,0L1380,0C1320,0,1200,0,1080,0C960,0,840,0,720,0C600,0,480,0,360,0C240,0,120,0,60,0L0,0Z"></path>
</svg>

SVG 的另一个优势是,可以直接嵌套到 HTML 文档中:

HTML 复制代码
<div class="wave--container">
    <h1>Hello, world!</h1>
    <p>Check out my awesome waves!</p>
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1440 320" class="wave">
        <path fill="#0099ff" fill-opacity="1" d="M0,288L60,288C120,288,240,288,360,261.3C480,235,600,181,720,181.3C840,181,960,235,1080,245.3C1200,256,1320,224,1380,208L1440,192L1440,0L1380,0C1320,0,1200,0,1080,0C960,0,840,0,720,0C600,0,480,0,360,0C240,0,120,0,60,0L0,0Z"></path>
    </svg>
</div>

根据布局需要,添加少些 CSS ,就可以构建出页头带有水波纹的布局效果:

Demo 地址:codepen.io/airen/full/...

案例:水波纹卡片

Demo 地址:codepen.io/airen/full/...

不难发现,上面这个案例中,好多地方都有水波纹的身影。前面说了,水波纹的效果,不需要担心,即使你不懂任何 SVG 也无妨,使用 getwaves.io 工具,可以获得案例中所需的水波纹的效果以及对应的 SVG 代码。

只不过,在这里我将利用 SVG 的雪碧图技术,即使用 SVG 的 <symbol> 将每个水波纹实例化,然后在需要使用的地方使用 <use> 来调用。

XML 复制代码
<svg style="display:none;">
    <symbol id="one" viewBox="0 0 1440 320" preserveAspectRatio="none">
        <path fill="white" d="M0,96L1440,320L1440,320L0,320Z"></path>
    </symbol>
    <symbol id="two" viewBox="0 0 1440 320" preserveAspectRatio="none">
        <path fill="white" d="M0,32L48,37.3C96,43,192,53,288,90.7C384,128,480,192,576,197.3C672,203,768,149,864,138.7C960,128,1056,160,1152,160C1248,160,1344,128,1392,112L1440,96L1440,320L1392,320C1344,320,1248,320,1152,320C1056,320,960,320,864,320C768,320,672,320,576,320C480,320,384,320,288,320C192,320,96,320,48,320L0,320Z"></path>
    </symbol>
  
    <symbol id="three" viewBox="0 0 1440 320" preserveAspectRatio="none">
        <path fill="white" d="M0,128L30,144C60,160,120,192,180,197.3C240,203,300,181,360,192C420,203,480,245,540,245.3C600,245,660,203,720,192C780,181,840,203,900,181.3C960,160,1020,96,1080,80C1140,64,1200,96,1260,122.7C1320,149,1380,171,1410,181.3L1440,192L1440,320L1410,320C1380,320,1320,320,1260,320C1200,320,1140,320,1080,320C1020,320,960,320,900,320C840,320,780,320,720,320C660,320,600,320,540,320C480,320,420,320,360,320C300,320,240,320,180,320C120,320,60,320,30,320L0,320Z"></path>
    </symbol>
  
    <symbol id="four" viewBox="0 0 1440 320" preserveAspectRatio="none">
        <path fill="white" d="M0,192L120,192C240,192,480,192,720,165.3C960,139,1200,85,1320,58.7L1440,32L1440,320L1320,320C1200,320,960,320,720,320C480,320,240,320,120,320L0,320Z"></path>
    </symbol>
  
    <symbol id="five" viewBox="0 0 1440 320" preserveAspectRatio="none">
        <path fill="white" d="M0,32L120,69.3C240,107,480,181,720,192C960,203,1200,149,1320,122.7L1440,96L1440,320L1320,320C1200,320,960,320,720,320C480,320,240,320,120,320L0,320Z"></path>
    </symbol>
  
    <symbol id="six" viewBox="0 0 1440 320" preserveAspectRatio="none">
        <path fill="rgba(255, 255, 255, .8)" d="M0,32L120,64C240,96,480,160,720,160C960,160,1200,96,1320,64L1440,32L1440,320L1320,320C1200,320,960,320,720,320C480,320,240,320,120,320L0,320Z"></path>
    </symbol>
</svg>

如果你希望能更好的控制每个水波纹的颜色,那么建议你将 fill 设置为 currentColor 或 CSS 自定义属性的值。这样利用 CSS 穿透 <use> 元素,覆盖引用的 SVG 的样式。有关于这方面的详细介绍,请移步 《CSS Tips:CSS 如何穿透 SVG 的 use》。

我们以示例中的卡片为例,你可能需要像下面这样的一个 HTML:

HTML 复制代码
<div class="cards">
    <div class="card">
        <figure>
            <img src="https://picsum.photos/id/188/800/600" alt="">
            <svg>
                <use href="#two"></use>
            </svg>
        </figure>
        <figcaption>
            <p>现代 Web 布局</p>
        </figcaption>
    </div>
    <!-- 其他 Card -->
</div>

<figure> 中的 <use> 就是引用 <symbol> 已实例化的水波纹。接下来,你需要使用一点 CSS 来样式化卡片:

CSS 复制代码
.cards {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100% - 18px, 300px), 1fr));
    gap: 2rem;
  
    .card {
        display: grid;
        gap: 2rem;
        position: relative;
        box-shadow: 0 5px 20px 2px rgb(0 0 0 / 0.15);
        min-width: 0;
        background-color: #fff;
        border: 1px solid rgba(0, 0, 0, .125);
        border-radius: .25rem;
        overflow: hidden;
        
        figure {
            position: relative;
        }
        
        img {
            display: block;
            max-width: 100%;
            aspect-ratio: 4 / 3;
            border-radius: .25rem .25rem 0 0;
            object-fit: cover;
            object-position: center;
        }
        
        svg {
            position: absolute;
            bottom: 0;
            left: 0;
            height: 55px;
            width: 100%;
        }
        
        figcaption {
            padding: 0 20px 20px;
            font-weight: bold;
        }
    }
}

整个布局,使用了 CSS Grid 中的 RAM 布局技术,另外还应用了些新的 CSS 特性,例如 aspect-ratio 设置图片的宽高比object-fit 和 object-position 防止图片拉伸和挤压等。其他的 CSS 应该对于大家来说,很普通,就不在这里重复阐述!

写在最后

利用相似的技术,你不仅仅局限于水波纹的布局,你可以实任何不规则的效果。最后希望这篇文章所阐述的小技巧对你今后的工作有所帮助。

如果你对 CSS 方面的技巧感兴趣,请移步阅读:


如果你觉得该教程对你有所帮助,请给我点个赞。要是你喜欢 CSS ,或者想进一步了解和掌握 CSS 相关的知识,请关注我的专栏,或者移步阅读下面这些系列教程:

相关推荐
科技探秘人11 分钟前
Chrome与火狐哪个浏览器的隐私追踪功能更好
前端·chrome
科技探秘人11 分钟前
Chrome与傲游浏览器性能与功能的深度对比
前端·chrome
JerryXZR17 分钟前
前端开发中ES6的技术细节二
前端·javascript·es6
七星静香18 分钟前
laravel chunkById 分块查询 使用时的问题
java·前端·laravel
q24985969321 分钟前
前端预览word、excel、ppt
前端·word·excel
小华同学ai27 分钟前
wflow-web:开源啦 ,高仿钉钉、飞书、企业微信的审批流程设计器,轻松打造属于你的工作流设计器
前端·钉钉·飞书
Gavin_91535 分钟前
【JavaScript】模块化开发
前端·javascript·vue.js
懒大王爱吃狼2 小时前
Python教程:python枚举类定义和使用
开发语言·前端·javascript·python·python基础·python编程·python书籍
逐·風6 小时前
unity关于自定义渲染、内存管理、性能调优、复杂物理模拟、并行计算以及插件开发
前端·unity·c#
Devil枫6 小时前
Vue 3 单元测试与E2E测试
前端·vue.js·单元测试