Shapes布局-文字环绕动画

简介: Shapes布局-文字环绕动画

说明

Shapes也有形状、图形的意思,我们可以在页面中创建图形,并让内容环绕在定义的图形边上。

Shapes的官方文档:https://developer.mozilla.org/zh-CN/docs/Web/CSS/CSS_Shapes/From_box_values

我们经常在一些宣传手册上看到文字环绕图形的海报效果,这种海报效果通过css也可以实现,shapes布局可以实现不规则的图文环绕效果。

注意:它需要和float属性配合使用。


实现以及语法

我们先来实现一个文字环绕图形的效果:

<div class="container">
        <div class="shape"></div>
        <p>
        这是一行文字这是一行文字这是一行文字这是一行文字这是一行文字这是一行文字这是一行文字
        这是一行文字这是一行文字这是一行文字这是一行文字这是一行文字这是一行文字这是一行文字
        这是一行文字这是一行文字这是一行文字这是一行文字这是一行文字这是一行文字这是一行文字
        这是一行文字
        </p>
    </div>
.container{
   width: 400px;
   height: 200px;
   border: 1px solid red;
   .shape{
    width: 100px;
    height: 100px;
    border: 1px solid gold;
    background: #ccc;
    float: left;  /* shape必须配合float */
    shape-outside: border-box; /* 围绕box边框环绕 */
   }
}

上图就是一个基本的文字环绕效果,float是必需的,它定义了元素浮动的位置,shape-outside: border-box;表示内容以盒子的边框为基准环绕。

这里是左浮动,所以盒子定位在左边,文字围绕左边的盒子排列。如果float:right;那么文字会围绕右边的盒子环绕。

上面的shape-outside: border-box;是其中一个环绕模式,shape-outside有多种环绕模式,如下:

属性 说明
shape-box 根据浮动元素的边缘(通过 CSS box model 来定义)形状计算出浮动的区域。
margin-box 以浮动元素的外边距边界进行围绕
border-box 以浮动元素的边框为基准环绕
padding-box 从浮动元素的padding位置开始环绕
content-box 从浮动元素的content位置开始环绕

margin-box

margin: 10px;
shape-outside: margin-box; /* 以margin的范围开始 */
• 1
• 2

content-box

border: 10px solid red;
    padding: 10px;
    shape-outside: content-box; /* 以元素的实际大小为起点,去掉border、margin */

此外还可以定义不规则的图形,让文字环绕这些不规则的图形。这里我们用ellipse()定义一个椭圆,让文字环绕椭圆

.shape{
    width: 100px;
    height: 100px;
    background: #ccc;
  float: right;
  clip-path: ellipse(50px 20px at 50% 50%); /* 裁切图形 */
  shape-outside: ellipse(50px 20px at 50% 50%); /* 环绕的实际图形 */
}

这里需要明白一点,clip-path裁切不是必须的(这里只是为了显示形状而已),真正的shapes布局是根据shape-outside而来,shape-outsid才是实际环绕的图形,如下:

.shape{
    width: 100px;
    height: 100px;
    background: #ccc;
  float: right;
    /* clip-path: ellipse(50px 20px at 50% 50%);  */
    shape-outside: ellipse(50px 20px at 50% 50%); /* 环绕的实际图形 */
}

关于形状裁切的几个属性:

属性 说明
circle() 定义一个圆形, 语法:circle(x轴(大小) at x轴坐标 y轴坐标); at后为剪切的位置,第一个参数左右,第二个参数上下
ellipse() 定义一个椭圆(使用两个半径和一个圆心位置)。语法:ellipse(x轴偏移 y轴偏移 at x轴坐标 y轴坐标)
inset() 四个参数,上右下左, 定义一个 inset 矩形。
polygon() 定义一个多边形(使用一个 SVG 填充规则和一组顶点)。四个参数,上右下左,每个位置的第一个参数代表左右偏移,第二个参数代表上下偏移
path() 定义一个任意形状(使用一个可选的 SVG 填充规则和一个 SVG 路径定义)。

裁切的具体用法可以去mdn上查询


动画

Shapes布局可以配合动画使用,动态的更改裁切的形状实现文字的动态变换:

<div class="container2">
     <div class="variant"></div>   <!-- 左侧的形状 -->
      <div class="variant2"></div>  <!-- 右侧的形状 -->
      <p>
        这是一行文字这是一行文字这是一行文字这是一行文字
        这是一行文字这是一行文字这是一行文字这是一行文字
        这是一行文字这是一行文字这是一行文字这是一行文字
        这是一行文字这是一行文字这是一行文字这是一行文字
        这是一行文字这是一行文字这是一行文字这是一行文字
        这是一行文字这是一行文字
      </p>
</div>
.container2{
    width: 400px;
    height: 200px;
    border: 1px solid green;
    .variant{
        width: 200px;
        height: 200px;
        background: #ccc;
        clip-path: polygon(0 0, 0% 100%, 40% 50%); /*形状裁切*/
        float: left;  /*左浮动*/
        shape-outside: polygon(0 0, 0% 100%, 40% 50%);  /*实际环绕的形状*/
        animation: square 5s infinite linear;
    }
    .variant2{
        width: 200px;
        height: 200px;
        background: #ccc;
        clip-path: polygon(100% 0, 100% 100%, 60% 50%); /*形状裁切*/
        float: right; /*右浮动*/
        shape-outside: polygon(100% 0, 100% 100%, 60% 50%); /*实际环绕的形状*/
        animation: square2 5s infinite linear;
    }
    >p{
        text-align: center;
    }
     /* 利用动画,动态更改裁切的形状 */
    @keyframes square {
        0%,100%{
            clip-path: polygon(0 0, 0% 100%, 40% 50%);
            shape-outside: polygon(0 0, 0% 100%, 40% 50%);
        }
       25%{
            clip-path: polygon(0 0, 0% 100%, 40% 25%);
            shape-outside: polygon(0 0, 0% 100%, 40% 25%);
       }
       75%{
            clip-path: polygon(0 0, 0% 100%, 40% 75%);
            shape-outside: polygon(0 0, 0% 100%, 40% 75%);
       }
    }
    @keyframes square2 {
        0%,100%{
            clip-path: polygon(100% 0, 100% 100%, 60% 50%);
            shape-outside: polygon(100% 0, 100% 100%, 60% 50%);
        }
       25%{
            clip-path: polygon(100% 0, 100% 100%, 60% 25%);
            shape-outside: polygon(100% 0, 100% 100%, 60% 25%);
       }
       75%{
            clip-path: polygon(100% 0, 100% 100%, 60% 75%);
            shape-outside: polygon(100% 0, 100% 100%, 60% 75%);
       }
    }
}

渐变裁切

Shapes布局是可以使用渐变的,如果渐变的颜色完全透明就相当于不占位,那么shape就会占据并围绕透明的位置:

<div class="container3">
     <div class="pngs"></div>
     <p>
     这是一行文字这是一行文字这是一行文字这是一行文字
     这是一行文字这是一行文字这是一行文字这是一行文字
     这是一行文字这是一行文字这是一行文字这是一行文字
     这是一行文字这是一行文字这是一行文字这是一行文字
     这是一行文字这是一行文字
     </p>
</div>
.container3{
    width: 400px;
    height: 200px;
    border: 1px solid gold;
    margin: 30px;
    .pngs{
        width: 200px;
        height: 200px;
        float: left;
        /* 如果渐变的透明度为完全透明,那么shape就会占据并围绕透明的位置 */
        /* 建立一个变量 */
        --gradient : linear-gradient(to right bottom , #80c342 40% , transparent 50% , transparent 70%  , #4d90fe 80%);
        shape-outside: var(--gradient);
        background: var(--gradient);
        animation: gradients 5s infinite linear;
    }
    /* 动态更改渐变的颜色占比 */
    @keyframes gradients {
        0%,100%{
            --gradient : linear-gradient(to right bottom , #80c342 40% , transparent 50% , transparent 70%  , #4d90fe 80%);
        }
        25%{
            --gradient : linear-gradient(to right bottom , #80c342 20% , transparent 30% , transparent 60%  , #4d90fe 70%);
        }
        75%{
            --gradient : linear-gradient(to right bottom , #80c342 60% , transparent 70% , transparent 80%  , #4d90fe 90%);
        }
    }
}

图形变换的动画效果

效果如下:

利用动画动态更改裁切元素的图形,文字根据裁切形状动态的进行排版变化

<div class="container">
     <div class="left"></div>
     <div class="right"></div>
     <p>
     这是一段文字。这是一段文字。这是一段文字。这是一段文字。这是一段文字。这是一段文字。
     这是一段文字。这是一段文字。这是一段文字。这是一段文字。这是一段文字。这是一段文字。
     这是一段文字。这是一段文字。这是一段文字。这是一段文字。这是一段文字。这是一段文字。
     这是一段文字。这是一段文字。这是一段文字。这是一段文字。这是一段文字。这是一段文字。
     这是一段文字。这是一段文字。这是一段文字。这是一段文字。这是一段文字。这是一段文字。
     这是一段文字。这是一段文字。这是一段文字。这是一段文字。这是一段文字。这是一段文字。
     这是一段文字。这是一段文字。这是一段文字。这是一段文字。这是一段文字。这是一段文字。
     这是一段文字。这是一段文字。这是一段文字。这是一段文字。
     </p>
</div>
.container{
    width: 500px;
    height: 254px;
    border: 1px solid red;
    background: black;
    overflow: hidden;
    margin: 20px;
    padding-top: 40px; /* 设置头部内距,留出文字间隙 */
    >p{
        color: #fff;
        margin-top: -40px; /* 与父级padding数值相等,抵消padding */
    }
    .left{
        width: 200px;
        height: 200px;
        /* margin-top: 60px; */ /* 如果使用裁切动画则不能设置margin,这个margin是给元素展示的本体用的,并不是给shape-outside裁切的形图形用的 */
        float: left;
        background: #ccc;
        animation: variants 4s infinite linear;
        background: linear-gradient(to right , #4ac6ff , #bd34fe);
    }
    .right{
        width: 200px;
        height: 200px;
        // margin-top: 60px;  
        float: right;
        background: #ccc;
        animation: variants 4s infinite linear;
        background: linear-gradient(to left , #4ac6ff , #bd34fe);
    }
    @keyframes variants {
        0%,5%,95%,100%{
            /* polygon的参数数量必须一致,否则动画会失效 */
            clip-path: polygon(50% 0%, 62% 38%, 100% 50%, 62% 56%, 50% 100%, 37% 56%, 0 50%, 38% 38%);
            shape-outside: polygon(50% 0%, 62% 38%, 100% 50%, 62% 56%, 50% 100%, 37% 56%, 0 50%, 38% 38%);
        }
        45%{
            clip-path: polygon(50% 30%, 100% 0, 70% 50%, 100% 100%, 50% 70%, 0 100%, 30% 50%, 0 0);
            shape-outside: polygon(50% 30%, 100% 0, 70% 50%, 100% 100%, 50% 70%, 0 100%, 30% 50%, 0 0);
        }
        55%{
            clip-path: polygon(50% 30%, 100% 0, 70% 50%, 100% 100%, 50% 70%, 0 100%, 30% 50%, 0 0);
            shape-outside: polygon(50% 30%, 100% 0, 70% 50%, 100% 100%, 50% 70%, 0 100%, 30% 50%, 0 0);
        }
    }
}

这里有几个需要注意的地方:

1、给元素添加shape-outside后不能使用margin,因为margin是给元素展示的本体使用的,并不是给shape-outside裁切的形图形用的,否者会出现下图的效果:

2、动画中shape-outsidepolygon的参数和clip-path的参数需要一致,否则动画无法对应页面效果

3、由于shape-outside不能使用margin,如果我们想要移动裁切的位置,为上面留两行文字的空间,给父级添加padding即可,父级的内容使用 -margin 抵消padding即可。


案例源码:https://gitee.com/wang_fan_w/css-diary

如果觉得这篇文章对你有帮助,欢迎点赞👍、收藏💖、转发✨哦~

目录
相关文章
|
JavaScript 前端开发 BI
最好用的 7 款 Vue admin 后台管理系统测评
Vue admin 后台管理系统作为每个项目必备的管理后台,对大家来说十分重要。选不好,配不好,不仅现在用着抓狂,未来迭代升级也困难重重,步步是坑。所以在技术选型阶段,就要对市面上主流的 Vue admin 做到全面了解,知道他们的优缺点,再根据自己项目的需求,有针对性的选择。我试用了市面上所有主流 Vue admin 都 npm 到本地测了一遍,筛掉长期不更新,bug 明显,社区活跃度低,功能单一的 admin 后台,把最好、最有特点的 7 款 Vue admin 挑出来,分享给大家。这些后台各有各的特点,有些功能多样,但整体很重;有些虽然稳定,但上线年头久远,含有大量陈旧功能;有些功能
3901 0
|
JSON 前端开发 小程序
uniapp:request 请求出现400错误
uniapp:request 请求出现400错误
1216 0
uniapp:request 请求出现400错误
|
分布式计算 并行计算 Java
浅析Python自带的线程池和进程池
浅析Python自带的线程池和进程池
1303 0
|
4月前
|
移动开发 JavaScript 前端开发
前端组件库——Vant 4知识点大全(一)
教程来源 http://yvyus.cn/ Vant 4 是面向 Vue 3 的轻量级移动端组件库,2022年12月发布,支持深色模式、5个新组件(如TimePicker、DatePicker)、体积更小(组件平均<1KB),零依赖、TypeScript 全面支持,GitHub 星标超2.2万,国内H5开发事实标准。
|
7月前
|
人工智能 安全 API
阿里云企业邮箱支持功能解读及收费价格详细介绍,2026年最新整理云邮箱功能大全
阿里云企业邮箱提供协同办公、管理及集成三大功能:支持多端同步、日程共享、邮件撤回;具备分级管理、归档、多域管理;集成钉钉收发信、开放API、免密登录,助力企业高效安全沟通。
|
5月前
|
人工智能 监控 API
【小龙虾Ai🦞保姆级】OpenClaw零基础阿里云/本地部署+多Agent开发集群搭建+免费API配置及避坑指南
2026年,AI开发工具的竞争已从“单点能力”转向“群体协同”。独立开发者Elvis的实战案例震撼行业:通过OpenClaw作为编排层,打造由Claude Code、Codex等模型组成的Agent Swarm(智能体集群),实现日均50次代码提交、单日峰值94次提交的惊人效率,30分钟内完成7个PR合并,无需打开编辑器即可交付完整功能。这一架构与Stripe内部的Minions系统异曲同工——以集中式编排层管理并行编码Agent,让个人开发者拥有媲美团队的生产力。
961 3
|
5月前
|
Ubuntu API 数据安全/隐私保护
OpenClaw“小龙虾”进阶保姆级图文教程!阿里云/本地部署+多Agent选型+百炼Coding Plan配置及避坑指南
2026年,OpenClaw的用户讨论焦点已从“如何安装”转向“如何用好”,其中多Agent玩法成为核心热点。但多数用户容易陷入“为了复杂而复杂”的误区——还未找到稳定使用场景,就盲目搭建十几个Agent,最终因维护成本过高而放弃。
2365 1
|
5月前
|
自然语言处理 安全 Linux
OpenClaw(Clawdbot)阿里云轻量服务器及本地部署与Skills集成保姆级指南
OpenClaw(原Clawdbot)作为2026年最热门的开源AI自动化代理框架,凭借系统级权限调用、多场景适配、可扩展性强的核心优势,成为个人办公自动化、开发辅助、轻量团队协作的首选工具。其核心价值在于支持通过集成各类Skills(技能插件)扩展功能边界,实现从自然语言指令到实际操作的全链路自动化,无需复杂的代码开发,零基础用户也能快速上手。
1812 2
|
Linux 数据库
在Linux中,如何在Linux中使用find命令搜索文件?
在Linux中,如何在Linux中使用find命令搜索文件?
|
存储 JavaScript
这一定是最有用的vite插件入门教程了!
【8月更文挑战第3天】 vite插件核心在于几个钩子函数的理解与使用,想开发vite插件,掌握这几个插件即可。本文中探讨了**config钩子**和**transformIndexHtml钩子**,相信大家看完对插件开发一定有了最基本的认识与方向!
1153 3