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的范围开始 */

在这里插入图片描述

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

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

posted @ 2023-05-07 11:18  兔子先森Ace  阅读(69)  评论(0编辑  收藏  举报