太惊艳了,这些都是css的杰作

40 篇文章 1 订阅
25 篇文章 0 订阅

作者: 晴栀
珍惜拥有的每一天,拥抱生命里的每一个瞬间。莫到日历沙沙划去了岁月,莫到钟摆悠悠摇老了容颜。不要一眨眼,芳华岁月都已成过往之事。才发现,时光匆匆逝去光阴真如箭。

有趣的css动画

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
img

img

使用 border-image 实现渐变边框

border-image 是 CSS 规范 CSS Backgrounds and Borders Module Level 3 (最新一版的关于 background 和 border 的官方规范) 新增的一个属性值。
https://drafts.csswg.org/css-backgrounds-3/#border-images

顾名思义,我们可以给 border 元素添加 image,类似于 background-image,可以是图片也可以是渐变,不再局限于纯色。

使用 border-image 实现渐变边框

有了 border-image 之后,实现渐变边框变得很方便
不过多介绍 border-image 的语法,读者需要自行了解一下。
https://developer.mozilla.org/zh-CN/docs/Web/CSS/border-image

border-imageCSS属性允许在元素的边框上绘制图像。这使得绘制复杂的外观组件更加简单,也不用在某些情况下使用九宫格了。使用border-image时,其将会替换掉 border-style属性所设置的边框样式。虽然规范要求使用border-image 时边框样式必须存在,但一些浏览器可能没有实现这一点。

特别注意,若 border-image-source(此值可用border-image-source或border-image简写设置) 的值为 none或者图片不能显示,则将应用 border-style。
在这里插入图片描述

实现代码如下

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        html,
        body {
            height: 100%;
            width: 100%;
        }
        
        body {
            display: flex;
            justify-content: center;
            align-items: center;
        }
        
        .box {
            width: 200px;
            height: 100px;
            border-radius: 10px;
            border: 30px solid;
            border-image-source: linear-gradient(45deg, gold, deeppink);
            border-image-slice: 10;
            border-image-repeat: stretch;
        }
    </style>
</head>

<body>
    <div class="box"></div>
</body>

</html>

在这里插入图片描述

border-radius 失效

仔细看上面的 Demo,设置了 border-radius: 10px 但是实际表现没有圆角。使用 border-image 最大的问题在于,设置的 border-radius 会失效。

我们无法得到一个带圆角的渐变边框。原因,查看官方规范 W3C 解释如下:
A box’s backgrounds, but not its border-image, are clipped to the appropriate curve (as determined by ‘background-clip’). Other effects that clip to the border or padding edge (such as ‘overflow’ other than ‘visible’) also must clip to the curve. The content of replaced elements is always trimmed to the content edge curve. Also, the area outside the curve of the border edge does not accept mouse events on behalf of the element.

为此,我们得另辟蹊径或者稍加改进,得到带圆角的渐变边框。

代码如下

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        body,
        html {
            width: 100%;
            min-height: 100%;
            display: flex;
            background: #fee;
        }
        
        .pesudo {
            position: relative;
            width: 200px;
            height: 100px;
            margin: auto;
        }
        
        .pesudo::after {
            content: "";
            position: absolute;
            width: 180px;
            height: 80px;
            background: #fff;
            top: 50%;
            left: 50%;
            transform: translate(50px, -50%);
            z-index: 3;
            animation: move 4s infinite;
        }
        
        .pesudo::before {
            content: "";
            position: absolute;
            width: 200px;
            height: 100px;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            border-radius: 10px;
            background: linear-gradient(45deg, gold, deeppink);
            z-index: 2;
        }
        
        @keyframes move {
            0% {
                transform: translate(50px, -50%);
            }
            50%,
            100% {
                transform: translate(-50%, -50%);
            }
        }
    </style>
</head>

<body>

    <!--伪元素遮罩-->
    <div class="pesudo">

    </div>


</body>

</html>

缺点

  • 这个方案有两个问题,第一个是多使用了两个元素(当然在这里是( ::before 和 ::after),其次最致命的是,如果要求边框內的背景是透明的,此方案便行不通了。
  • 并且框内不能添加元素

在这里插入图片描述

background-image + 伪元素

第一种方法,我们不再使用 border-image ,而是使用 background-image + 伪元素 的方案,这也是在 border-image 规范没有出现最常用的方法。

使用 background-clip 实现

使用 background-clip: content-box 以及 background-clip: border-box 配合使用。

background-clip:background-clip 设置元素的背景(背景图片或颜色)是否延伸到边框下面。它的部分取值和 box-sizing 类似。其中,

  • background-clip: border-box 表示设置的背景 background-image 将延伸至边框
  • background-clip: content-box 表示设置的背景 background-image 被裁剪至内容区(content box)外沿

这里,我们使用设置两个 background-image,设置两个 background-clip ,并且将border设置为透明即可:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        div {
            width: 200px;
            height: 100px;
            border: solid 10px transparent;
            border-radius: 10px;
            background-image: linear-gradient(#fee, #fee), linear-gradient(to right, green, gold);
            background-origin: border-box;
            background-clip: content-box, border-box;
        }
    </style>
</head>

<body>
    <div></div>
</body>

</html>

 background-clip实现渐变边框

因为用到了 background-clip: border-box,所以还需要 background-origin: border-box 使图案完整显示,可以尝试下关掉这个属性,即可明白为什么需要这样做。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        div {
            width: 200px;
            height: 100px;
            border: solid 10px transparent;
            border-radius: 10px;
            background-image: linear-gradient(#fee, #fee), linear-gradient(to right, green, gold);
            /* background-origin: border-box; */
            background-clip: content-box, border-box;
        }
    </style>
</head>

<body>
    <div></div>
</body>

</html>

在这里插入图片描述

background-origin

border-box
背景图片的摆放以border区域为参考
padding-box
背景图片的摆放以padding区域为参考
content-box
背景图片的摆放以content区域为参考

  • fixed
    此关键属性值表示背景相对于视口固定。即使一个元素拥有滚动机制,背景也不会随着元素的内容滚动。
  • local
    此关键属性值表示背景相对于元素的内容固定。如果一个元素拥有滚动机制,背景将会随着元素的内容滚动, 并且背景的绘制区域和定位区域是相对于可滚动的区域而不是包含他们的边框。
  • scroll
    此关键属性值表示背景相对于元素本身固定, 而不是随着它的内容滚动(对元素边框是有效的)。
  • 相关我文章
    https://www.cnblogs.com/shytong/p/5077129.html
  • 假如background简写中没有设置该值,那么在 background简写值后指定background-origin,那么后面的值就会覆盖简写值,其实说白了,就是后出现的值会覆盖前面的值。

缺点

与第一种方法类似,如果要求边框內的背景是透明的,此方案便行不通了。

border-image + overflow: hidden

这个方法也很好理解,既然设置了 background-image 的元素的 border-radius 失效。那么,我们只需要给它加一个父容器,父容器设置 overflow: hidden + border-radius 即可:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        body,
        html {
            width: 100%;
            min-height: 100%;
            display: flex;
            background: #fee;
            justify-content: center;
            align-items: center;
        }
        
        .border-image-overflow {
            position: relative;
            width: 220px;
            height: 120px;
            border-radius: 10px;
            overflow: hidden;
        }
        
        .content {
            position: absolute;
            width: 200px;
            height: 100px;
            border: 10px solid;
            border-radius: 10px;
            border-image: linear-gradient(45deg, gold, deeppink) 1;
        }
    </style>
</head>

<body>
    <div class="border-image-overflow">
        <div class="content">
          
        </div>
    </div>
</body>

</html>

在这里插入图片描述

border-image + clip-path

设置了 background-image 的元素的 border-radius 失效。但是在 CSS 中,还有其它方法可以产生带圆角的容器,那就是借助 clip-path

clip-path,一个非常有意思的 CSS 属性。
https://developer.mozilla.org/zh-CN/docs/Web/CSS/clip-path

clip-path CSS 属性可以创建一个只有元素的部分区域可以显示的剪切区域。区域内的部分显示,区域外的隐藏。剪切区域是被引用内嵌的URL定义的路径或者外部 SVG 的路径。

<clip-source>

  • <url> 表示剪切元素的路径
    <basic-shape>
  • 一种形状,其大小和位置由<几何盒>值定义。如果没有指定几何框,则边框将用作参考框
    <geometry-box>
  • 如果同 <basic-shape> 一起声明,它将为基本形状提供相应的参考框盒。通过自定义,它将利用确定的盒子边缘包括任何形状边角(比如说,被 border-radius 定义的剪切路径)。几何框盒可以有以下的值中的一个:
  • margin-box
    使用 margin box 作为引用框。
  • border-box
    使用 border box 作为引用框。
  • padding-box
    使用 padding box 作为引用框。
  • content-box
    使用 content box 作为引用框。
  • fill-box
    利用对象边界框作为引用框。
  • stroke-box
    使用笔触边界框(stroke bounding box)作为引用框
  • view-box
    使用最近的 SVG 视口(viewport)作为引用框。如果viewBox 属性被指定来为元素创建 SVG 视口,引用框将会被定位在坐标系的原点,引用框位于由 viewBox 属性建立的坐标系的原点,引用框的尺寸用来设置 viewBox 属性的宽高值。
  • none
    不创建的剪切路径。
<clip-source> | [ <basic-shape> || <geometry-box> ] | none
where 
<clip-source> = <url>
<basic-shape> = <inset()> | <circle()> | <ellipse()> | <polygon()> | <path()>
<geometry-box> = <shape-box> | fill-box | stroke-box | view-box

where 
<inset()> = inset( <length-percentage>{1,4} [ round <'border-radius'> ]? )
<circle()> = circle( [ <shape-radius> ]? [ at <position> ]? )
<ellipse()> = ellipse( [ <shape-radius>{2} ]? [ at <position> ]? )
<polygon()> = polygon( <fill-rule>? , [ <length-percentage> <length-percentage> ]# )
<path()> = path( [ <fill-rule>, ]? <string> )
<shape-box> = <box> | margin-box

where 
<length-percentage> = <length> | <percentage>
<shape-radius> = <length-percentage> | closest-side | farthest-side
<position> = [ [ left | center | right ] || [ top | center | bottom ] | [ left | center | right | <length-percentage> ] [ top | center | bottom | <length-percentage> ]? | [ [ left | right ] <length-percentage> ] && [ [ top | bottom ] <length-percentage> ] ]
<fill-rule> = nonzero | evenodd
<box> = border-box | padding-box | content-box

语法

/* Keyword values */
clip-path: none;

/* <clip-source> values */
clip-path: url(resources.svg#c1);

/* <geometry-box> values */
clip-path: margin-box;
clip-path: border-box;
clip-path: padding-box;
clip-path: content-box;
clip-path: fill-box;
clip-path: stroke-box;
clip-path: view-box;

/* <basic-shape> values */
clip-path: inset(100px 50px);
clip-path: circle(50px at 0 100px);
clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%);
clip-path: path('M0.5,1 C0.5,1,0,0.7,0,0.3 A0.25,0.25,1,1,1,0.5,0.3 A0.25,0.25,1,1,1,1,0.3 C1,0.7,0.5,1,0.5,1 Z');

/* Box and shape values combined */
clip-path: padding-box circle(50px at 0 100px);

/* Global values */
clip-path: inherit;
clip-path: initial;
clip-path: unset;

案例

 .border-image-clip-path {
       position: relative;
        width: 200px;
        background-color: aqua;
        height: 200px;
        border: 50px solid;
  }
<body>
    <div class="border-image-clip-path"></div>
</body>

在这里插入图片描述

clip-path: circle(40%);
在这里插入图片描述
clip-path: ellipse(130px 140px at 10% 20%);
在这里插入图片描述
clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%);
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

实现代码

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        body,
        html {
            width: 100%;
            min-height: 100%;
            display: flex;
            background: #fee;
            justify-content: center;
            align-items: center;
        }
        
        .border-image-clip-path {
            position: relative;
            width: 200px;
            background-color: aqua;
            height: 100px;
            border: 10px solid;
            border-image: linear-gradient(45deg, gold, deeppink) 1;
            clip-path: inset(0 round 10px);
        }
    </style>
</head>

<body>
    <div class="border-image-clip-path"></div>
</body>

</html>

clip-path实现渐变边框

border-image 使用渐变

我们可以利用 border-image + filter + clip-path实现渐变变换的圆角边框:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        body,
        html {
            width: 100%;
            min-height: 100%;
            display: flex;
        }
        
        .border-image-clip-path {
            width: 200px;
            height: 100px;
            margin: auto;
            border: 10px solid;
            border-image: linear-gradient(45deg, gold, deeppink) 1;
            clip-path: inset(0px round 10px);
            animation: huerotate 6s infinite linear;
            filter: hue-rotate(360deg);
        }
        
        @keyframes huerotate {
            0% {
                filter: hue-rotate(0deg);
            }
            100% {
                filter: hue-rorate(360deg);
            }
        }
    </style>
</head>

<body>
    <div class="border-image-clip-path"></div>
</body>

</html>

实现边框渐变动画

https://codepen.io/Chokcoco/pen/povBORP

边框hover动画

长度变化动画

先来个比较简单的,实现一个类似这样的边框效果:
在这里插入图片描述

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
         :root {
            --borderColor: #03A9F3;
        }
        
        html,
        body {
            height: 100%;
            width: 100%;
        }
        
        body {
            display: flex;
            justify-content: center;
            align-items: center;
            background-image: linear-gradient(to top, #fdcbf1 0%, #fdcbf1 1%, #e6dee9 100%);
        }
        
        .box {
            position: relative;
            width: 140px;
            height: 64px;
            margin: auto;
            border: 1px solid #03A9F3;
            cursor: pointer;
            /*文字样式 */
            text-align: center;
            line-height: 64px;
            color: #ffffff;
            font-size: 26px;
            font-weight: bold;
        }
        
        .box::before,
        .box::after {
            content: "";
            position: absolute;
            width: 20px;
            height: 20px;
            transition: .3s ease-in-out;
        }
        
        .box::before {
            top: -5px;
            left: -5px;
            border-top: 1px solid var(--borderColor);
            border-left: 1px solid var(--borderColor);
        }
        
        .box::after {
            right: -5px;
            bottom: -5px;
            border-bottom: 1px solid var(--borderColor);
            border-right: 1px solid var(--borderColor);
        }
        
        .box:hover::before,
        .box:hover::after {
            width: calc(100% + 9px);
            height: calc(100% + 9px);
        }
    </style>
</head>

<body>
    <div class="box">
        hover
    </div>
</body>

</html>

接下来,会开始加深一些难度。

虚线边框动画

首先使用 dashed 关键字,可以方便的创建虚线边框

div {
    border: 1px dashed #333;
}

当然,我们的目的是让边框能够动起来。使用 dashed 关键字是没有办法的。但是实现虚线的方式在 CSS 中有很多种,譬如渐变就是一种很好的方式:

div {
    background: linear-gradient(90deg, #333 50%, transparent 0) repeat-x;
    background-size: 4px 1px;
    background-position: 0 0;
}

在这里插入图片描述

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        html,
        body {
            height: 100%;
            width: 100%;
        }
        
        body {
            display: flex;
            justify-content: center;
            align-items: center;
            background-image: linear-gradient(to top, #fdcbf1 0%, #fdcbf1 1%, #e6dee9 100%);
        }
        
        div {
            width: 100px;
            height: 100px;
            background: linear-gradient(90deg, #333 50%, transparent 0) repeat-x;
            background-size: 4px 1px;
            background-position: 0 0;
        }
    </style>
</head>

<body>
    <div></div>
</body>

</html>

好了,渐变支持多重渐变,我们把容器的·4 个边都用渐变表示即可:

 div {
            width: 100px;
            height: 100px;
            background: linear-gradient(90deg, #333 50%, transparent 0) repeat-x, linear-gradient(90deg, #333 50%, transparent 0) repeat-x, linear-gradient(0deg, #333 50%, transparent 0) repeat-y, linear-gradient(0deg, #333 50%, transparent 0) repeat-y;
            background-size: 4px 1px, 4px 1px, 1px 4px, 1px 4px;
            background-position: 0 0, 0 100%, 0 0, 100% 0;
        }

效果图
四边用渐变实现虚线
OK,至此,我们的虚线边框动画其实算是完成了一大半了。虽然 border-style: dashed 不支持动画,但是渐变支持呀。我们给上述 div 再加上一个 hover 效果,hover 的时候新增一个 animation 动画,改变元素的 background-position 即可。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        html,
        body {
            height: 100%;
            width: 100%;
        }
        
        body {
            display: flex;
            justify-content: center;
            align-items: center;
            background-image: linear-gradient(to top, #fdcbf1 0%, #fdcbf1 1%, #e6dee9 100%);
        }
        
        div {
            width: 100px;
            height: 100px;
            background: linear-gradient(90deg, #333 50%, transparent 0) repeat-x, linear-gradient(90deg, #333 50%, transparent 0) repeat-x, linear-gradient(0deg, #333 50%, transparent 0) repeat-y, linear-gradient(0deg, #333 50%, transparent 0) repeat-y;
            background-size: 4px 1px, 4px 1px, 1px 4px, 1px 4px;
            background-position: 0 0, 0 100%, 0 0, 100% 0;
        }
        
        div:hover {
            animation: linearGradientMove .3s infinite linear;
        }
        
        @keyframes linearGradientMove {
            100% {
                background-position: 4px 0, -4px 100%, 0 -4px, 100% 4px;
            }
        }
    </style>
</head>

<body>
    <div></div>
</body>

</html>

效果图
img

这里还有另外一个小技巧,如果我们希望虚线边框动画是从其他边框,过渡到虚线边框,再行进动画。完全由渐变来模拟也是可以的,如果想节省一些代码,使用 border 会更快一些,譬如这样:

实现边虚线动画

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        html,
        body {
            height: 100%;
            width: 100%;
        }
        
        body {
            display: flex;
            justify-content: center;
            align-items: center;
            background-image: linear-gradient(to top, #fdcbf1 0%, #fdcbf1 1%, #e6dee9 100%);
        }
        
        div {
            border: 1px solid #333;
            width: 100px;
            height: 100px;
        }
        
        div:hover {
            border: none;
            background: linear-gradient(90deg, #333 50%, transparent 0) repeat-x, linear-gradient(90deg, #333 50%, transparent 0) repeat-x, linear-gradient(0deg, #333 50%, transparent 0) repeat-y, linear-gradient(0deg, #333 50%, transparent 0) repeat-y;
            background-size: 4px 1px, 4px 1px, 1px 4px, 1px 4px;
            background-position: 0 0, 0 100%, 0 0, 100% 0;
            animation: linearGradientMove .3s infinite linear;
        }
        
        @keyframes linearGradientMove {
            100% {
                background-position: 4px 0, -4px 100%, 0 -4px, 100% 4px;
            }
        }
    </style>
</head>

<body>
    <div></div>
</body>

</html>

由于borderbackground在盒子模型上位置的差异,视觉上会有一个很明显的错位的感觉:
img
要想解决这个问题,我们可以把 border替换成outline,因为 outline可以设置 outline-offset。便能完美解决这个问题:

div {
    outline: 1px solid #333;
    outline-offset: -1px;
}
div:hover {
    outline: none;
}


outline

CSS 的 outline 属性是在一条声明中设置多个轮廓属性的简写属性 , 例如 outline-style, outline-widthoutline-color。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        body,
        html {
            width: 100%;
            min-height: 100%;
            display: flex;
        }
        
        .outline {
            width: 200px;
            height: 100px;
            margin: auto;
            /* 字体 */
            display: flex;
            text-align: center;
            align-items: center;
            background: linear-gradient(45deg, gold, deeppink);
            outline: solid;
        }
    </style>
</head>

<body>
    <div class="outline">
        This is a box with an outline around it.
    </div>
</body>

</html>

在这里插入图片描述

outline: dashed red;
outline: dashed red;
outline: 1rem solid;
outline: 1rem solid;
outline: thick double #32a1ce;
outline: thick double #32a1ce;
outline: 8px ridge rgba(170, 50, 220, .6);
border-radius: 2rem;
outline: 8px ridge rgba(170, 50, 220, .6);border-radius: 2rem;

border 和 outline

border 和 outline很类似,但有如下区别:

outline不占据空间,绘制于元素内容周围。
根据规范,outline通常是矩形,但也可以是非矩形的。

语法
 /* 样式 */
outline: solid;

/* 颜色 | 样式 */
outline: #f66 dashed;

/* 样式 | 宽度 */
outline: inset thick;

/* 颜色 | 样式 | 宽度 */
outline: green solid 3px;

/* 全局值 */
outline: inherit;
outline: initial;
outline: unset;
最终效果
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        html,
        body {
            height: 100%;
            width: 100%;
        }
        
        body {
            display: flex;
            justify-content: center;
            align-items: center;
            background-image: linear-gradient(120deg, #89f7fe 0%, #66a6ff 100%);
        }
        
        div {
            width: 200px;
            height: 50px;
            outline: 1px solid rgb(255, 255, 255);
            outline-offset: -1px;
            text-align: center;
            line-height: 50px;
            color: white;
        }
        
        div:hover {
            outline: none;
            box-shadow: inset #ffffff44 0px 0px 6px 5px;
            background: linear-gradient(90deg, rgb(255, 255, 255) 50%, transparent 0) repeat-x, linear-gradient(90deg, rgb(255, 254, 254) 50%, transparent 0) repeat-x, linear-gradient(0deg, rgb(248, 248, 248) 50%, transparent 0) repeat-y, linear-gradient(0deg, rgb(247, 244, 244) 50%, transparent 0) repeat-y;
            background-size: 4px 1px, 4px 1px, 1px 4px, 1px 4px;
            background-position: 0 0, 0 100%, 0 0, 100% 0;
            animation: linearGradientMove .3s infinite linear;
        }
        
        @keyframes linearGradientMove {
            100% {
                background-position: 4px 0, -4px 100%, 0 -4px, 100% 4px;
            }
        }
    </style>
</head>

<body>
    <div>
        Hover Me
    </div>
</body>

</html>

img

其实由于背景和边框的特殊关系,使用 border 的时候,通过修改 background-position 也是可以解决的。

巧妙使用渐变

用渐变,不仅仅只是能完成上述的效果。 条纹背景

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        div {
            position: relative;
        }
        
        div::after {
            content: '';
            position: absolute;
            left: -50%;
            top: -50%;
            width: 200%;
            height: 200%;
            background-repeat: no-repeat;
            background-size: 50% 50%, 50% 50%;
            background-position: 0 0, 100% 0, 100% 100%, 0 100%;
            background-image: linear-gradient(#399953, #399953), linear-gradient(#fbb300, #fbb300), linear-gradient(#d53e33, #d53e33), linear-gradient(#377af5, #377af5);
        }
    </style>
</head>

<body>
    <div>

    </div>
</body>

</html>

在这里插入图片描述

旋转

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        html,
        body {
            height: 100%;
            width: 100%;
        }
        
        body {
            display: flex;
            justify-content: center;
            align-items: center;
            background-image: linear-gradient(to top, #fdcbf1 0%, #fdcbf1 1%, #e6dee9 100%);
        }
        
        .box {
            width: 100px;
            height: 100px;
            position: relative;
            border-radius: 20px;
            overflow: hidden;
        }
        
        .box::after {
            content: '';
            position: absolute;
            left: -50%;
            top: -50%;
            width: 200%;
            height: 200%;
            background-repeat: no-repeat;
            background-size: 50% 50%, 50% 50%;
            background-position: 0 0, 100% 0, 100% 100%, 0 100%;
            background-image: linear-gradient(#399953, #399953), linear-gradient(#fbb300, #fbb300), linear-gradient(#d53e33, #d53e33), linear-gradient(#377af5, #377af5);
            animation: rotate 4s linear infinite;
        }
        
        @keyframes rotate {
            100% {
                transform: rotate(1turn);
            }
        }
    </style>
</head>

<body>
    <div class="box">

    </div>
</body>

</html>

img

最后,再利用一个伪元素,将中间遮罩起来,一个 Nice 的边框动画就出来了 (动画会出现半透明元素,方便示意看懂原理):

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        body {
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
        }
        
        *,
        *::before,
        *::after {
            box-sizing: border-box;
        }
        
        @keyframes rotate {
            100% {
                transform: rotate(1turn);
            }
        }
        
        .rainbow {
            position: relative;
            z-index: 0;
            width: 400px;
            height: 300px;
            border-radius: 10px;
            overflow: hidden;
            padding: 2rem;
        }
        
        .rainbow::before {
            content: '';
            position: absolute;
            z-index: -2;
            left: -50%;
            top: -50%;
            width: 200%;
            height: 200%;
            background-color: #399953;
            background-repeat: no-repeat;
            background-size: 50% 50%, 50% 50%;
            background-position: 0 0, 100% 0, 100% 100%, 0 100%;
            background-image: linear-gradient(#399953, #399953), linear-gradient(#fbb300, #fbb300), linear-gradient(#d53e33, #d53e33), linear-gradient(#377af5, #377af5);
            animation: rotate 4s linear infinite;
        }
        
        .rainbow::after {
            content: '';
            position: absolute;
            z-index: -1;
            left: 6px;
            top: 6px;
            width: calc(100% - 12px);
            height: calc(100% - 12px);
            background: white;
            border-radius: 5px;
            animation: opacityChange 3s infinite alternate;
        }
        
        @keyframes opacityChange {
            50% {
                opacity: 1;
            }
            100% {
                opacity: .5;
            }
        }
    </style>
</head>

<body>
    <div class="rainbow"></div>
</body>

</html>

在这里插入图片描述
在这里插入图片描述

改变渐变的颜色

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        body {
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
        }
        
        *,
        *::before,
        *::after {
            box-sizing: border-box;
        }
        
        @keyframes rotate {
            100% {
                transform: rotate(1turn);
            }
        }
        
        .rainbow {
            position: relative;
            z-index: 0;
            width: 400px;
            height: 300px;
            border-radius: 10px;
            overflow: hidden;
            padding: 2rem;
        }
        
        .rainbow::before {
            content: '';
            position: absolute;
            left: -50%;
            top: -50%;
            width: 200%;
            height: 200%;
            z-index: -2;
            background-color: #fff;
            background-repeat: no-repeat;
            background-size: 50% 50%;
            background-position: 0 0;
            background-image: linear-gradient(#399953, #399953);
            animation: rotate 4s linear infinite;
        }
        
        .rainbow::after {
            content: '';
            position: absolute;
            z-index: -1;
            left: 6px;
            top: 6px;
            width: calc(100% - 12px);
            height: calc(100% - 12px);
            background: white;
            border-radius: 5px;
            animation: opacityChange 3s infinite alternate;
        }
        
        @keyframes opacityChange {
            50% {
                opacity: 1;
            }
            100% {
                opacity: .5;
            }
        }
    </style>
</head>

<body>
    <div class="rainbow"></div>
</body>

</html>

img

Wow,很不错的样子。不过如果是单线条,有个很明显的缺陷,就是边框的末尾是一个小三角而不是垂直的,可能有些场景不适用或者 PM 接受不了。
img
那有没有什么办法能够消除掉这些小三角呢?有的,在下文中我们再介绍一种方法,利用 clip-path ,消除掉这些小三角。

conic-gradient`的妙用

再介绍 clip-path 之前,先讲讲角向渐变。
上述主要用到了的是线性渐变 linear-gradient 。我们使用角向渐变 conic-gradient 其实完全也可以实现一模一样的效果。

conic-gradient:圆锥形渐变,它的两个兄弟line-gradient(线性渐变)、radial-gradient(径向渐变),算是最早认识的渐变属性。

圆锥渐变的起始点是图形中心,渐变方向以顺时针方向绕中心旋转实现渐变效果。

  • 兼容性

根据 can i use,目前只在chrome 69及以上支持。
可以使用polyfill垫片库,解决兼容性问题。垫片库会根据css语法,生成对应的圆锥渐变图案,并且转化为 base64 代码。

颜色表盘

在这里插入图片描述

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        body {
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
        }
        /* 起始处与结尾处衔接不够自然 */
        
        .color1 {
            width: 200px;
            height: 200px;
            border-radius: 50%;
            background: conic-gradient(red, orange, yellow, green, teal, blue, purple)
        }
        /* 起始处与结尾处衔接不够自然,解决:在结尾加入开始的颜色 */
        
        .color2 {
            width: 200px;
            height: 200px;
            border-radius: 50%;
            background: conic-gradient(red, orange, yellow, green, teal, blue, purple, red);
        }
    </style>
</head>

<body>
    <section class="color1"></section>
    <section class="color2"></section>
</body>

</html>
饼图

在这里插入图片描述

<section class="pie"></section>

    .pie {
      width: 200px;
      height: 200px;
      border-radius: 50%;
      /* 百分比 写法一 */
       background: conic-gradient(pink 0, pink 30%, yellow 30%, yellow 70%, lime 70%, lime 100%); 
      /* 写法二 不支持 chrome69 */
      /* background: conic-gradient(pink 0 30%, yellow 0 70%, lime 0 100%); */
    }
菱形背景

在这里插入图片描述

 <section class="rhombus"></section>

    .rhombus {
      width: 200px;
      height: 200px;
      background: conic-gradient(#000 0, #000 12.5%, #fff 12.5%, #fff 37.5%, #000 37.5%, #000 62.5%, #fff 62.5%, #fff 87.5%, #000 87.5%,#000 0);
      border: 1px solid #000;
      background-size: 50px 50px;
    }
仪表盘

在这里插入图片描述

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .bg {
            position: relative;
            margin: 50px auto;
            width: 400px;
            height: 400px;
            border-radius: 50%;
            background: conic-gradient(#f1462c 0%, #fc5d2c 12.4%, #fff 12.5%, #fff 12.5%, #fc5d2c 12.5%, #fba73e 24.9%, #fff 24.9%, #fff 25%, #fba73e 25%, #e0fa4e 37.4%, #fff 37.4%, #fff 37.5%, #e0fa4e 37.5%, #12dd7e 49.9%, #fff 49.9%, #fff 50%, #12dd7e 50%, #0a6e3f 62.4%, #fff 62.4%, #fff 62.5%);
            transform: rotate(-112.5deg);
            transform-origin: 50% 50%;
        }
        
        .bg::before {
            content: "";
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            width: 370px;
            height: 370px;
            border-radius: 50%;
            background: #fff;
        }
        
        .bg::after {
            content: "";
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            width: 320px;
            height: 320px;
            border-radius: 50%;
            background: radial-gradient(#fff 0%, #fff 25%, transparent 25%, transparent 100%), conic-gradient(#f1462c 0, #f1462c 12.5%, #fba73e 12.5%, #fba73e 25%, #e0fa4e 25%, #e0fa4e 37.5%, #12dd7e 37.5%, #12dd7e 50%, #0a6e3f 50%, #0a6e3f 62.5%, #fff 62.5%, #fff 100%);
        }
        
        .point {
            position: absolute;
            width: 30px;
            height: 30px;
            transform: translate(-50%, -50%);
            left: 50%;
            top: 50%;
            background: radial-gradient(#467dc6 0%, #a4c6f3 100%);
            border-radius: 50%;
            z-index: 999;
        }
        
        .point::before {
            content: "";
            position: absolute;
            width: 5px;
            height: 350px;
            left: 50%;
            top: 50%;
            transform: translate(-50%, -50%) rotate(0);
            border-radius: 100% 100% 5% 5%;
            background: linear-gradient( 180deg, #9bc7f6 0, #467dc6 50%, transparent 50%, transparent 100%);
            animation: pointerRotate 3s cubic-bezier(.93, 1.32, .89, 1.15) infinite;
        }
        
        @keyframes pointerRotate {
            50% {
                transform: translate(-50%, -50%) rotate(150deg);
            }
            100% {
                transform: translate(-50%, -50%) rotate(150deg);
            }
        }
    </style>
</head>

<body>
    <div class="bg">
        <div class="point"></div>
    </div>
</body>

</html>

我们试着使用 conic-gradient 也实现一次,这次换一种暗黑风格。核心代码如下:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        body {
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            background-color: rgb(8, 8, 8);
        }
        
        *,
        *::before,
        *::after {
            box-sizing: border-box;
        }
        
        @keyframes rotate {
            100% {
                transform: rotate(1turn);
            }
        }
        
        .rainbow {
            position: relative;
            z-index: 0;
            width: 400px;
            height: 300px;
            border-radius: 10px;
            overflow: hidden;
            padding: 2rem;
        }
        
        .rainbow::before {
            content: '';
            position: absolute;
            left: -50%;
            top: -50%;
            width: 200%;
            height: 200%;
            z-index: -2;
            background-repeat: no-repeat;
            background-size: 50% 50%;
            background-position: 0 0;
            background: conic-gradient(transparent, rgba(168, 239, 255, 1), transparent 30%);
            animation: rotate 4s linear infinite;
        }
        
        .rainbow::after {
            content: '';
            position: absolute;
            z-index: -1;
            left: 6px;
            top: 6px;
            width: calc(100% - 12px);
            height: calc(100% - 12px);
            background-color: rgb(8, 8, 8);
            border-radius: 5px;
            /* animation: opacityChange 3s infinite alternate; */
        }
        
        @keyframes opacityChange {
            50% {
                opacity: 1;
            }
            100% {
                opacity: .5;
            }
        }
    </style>
</head>

<body>
    <div class="rainbow"></div>
</body>

</html>

在这里插入图片描述

clip-path 的妙用

  • 又是老朋友 clip-path,有意思的事情它总不会缺席。
  • clip-path 本身是可以进行坐标点的动画的,从一个裁剪形状变换到另外一个裁剪形状。
  • 利用这个特点,我们可以巧妙的实现这样一种 border 跟随效果。伪代码如下:
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        body,
        html {
            width: 100%;
            height: 100%;
            display: flex;
            background-color: red;
        }
        
        div {
            position: relative;
            margin: auto;
            width: 160px;
            line-height: 160px;
            text-align: center;
            font-size: 24px;
        }
        
        div::before {
            content: "";
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            border: 2px solid gold;
            transition: all .5s;
            animation: clippath 3s infinite linear;
        }
        
        @keyframes clippath {
            0%,
            100% {
                clip-path: inset(0 0 95% 0);
            }
            25% {
                clip-path: inset(0 95% 0 0);
            }
            50% {
                clip-path: inset(95% 0 0 0);
            }
            75% {
                clip-path: inset(0 0 0 95%);
            }
        }
        
        .bg::before {
            background: rgba(255, 215, 0, .5);
        }
    </style>
</head>

<body>
    <div>Hello</div>
    <div class="bg">示意图</div>
</body>

</html>

在这里插入图片描述

这里,因为会裁剪元素,借用伪元素作为背景进行裁剪并动画即可,使用 clip-path 的优点了,切割出来的边框不会产生小三角。同时,这种方法,也是支持圆角 border-radius 的。

如果我们把另外一个伪元素也用上,实际实现一个按钮样式,可以得到这样的效果:
img

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        body,
        html {
            width: 100%;
            height: 100%;
            display: flex;
        }
        
        .btn {
            position: relative;
            margin: auto;
            width: 120px;
            line-height: 64px;
            text-align: center;
            color: #fff;
            font-size: 20px;
            border: 2px solid gold;
            border-radius: 10px;
            background: gold;
            transition: all .3s;
            cursor: pointer;
        }
        
        .btn:hover {
            filter: contrast(1.1);
        }
        
        .btn:active {
            filter: contrast(0.9);
        }
        
        .btn::before,
        .btn::after {
            content: "";
            position: absolute;
            top: -10px;
            left: -10px;
            right: -10px;
            bottom: -10px;
            border: 2px solid gold;
            transition: all .5s;
            animation: clippath 3s infinite linear;
            border-radius: 10px;
        }
        
        .btn::after {
            animation: clippath 3s infinite -1.5s linear;
        }
        
        @keyframes clippath {
            0%,
            100% {
                clip-path: inset(0 0 98% 0);
            }
            25% {
                clip-path: inset(0 98% 0 0);
            }
            50% {
                clip-path: inset(98% 0 0 0);
            }
            75% {
                clip-path: inset(0 0 0 98%);
            }
        }
    </style>
</head>

<body>
    <div class="btn">Hover</div>
</body>

</html>

overflow的妙用

下面这个技巧利用 overflow 实现。实现这样一个边框动画:
img
为何说是利用 overflow 实现?

  • 示意图
    img
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        body,
        html {
            width: 100%;
            height: 100%;
            display: flex;
            background: yellowgreen;
        }
        
        div {
            position: relative;
            margin: auto;
            width: 200px;
            height: 100px;
            line-height: 100px;
            text-align: center;
            overflow: hidden;
        }
        
        div::after {
            content: "Hover Me";
            position: absolute;
            top: 4px;
            bottom: 4px;
            right: 4px;
            left: 4px;
            line-height: 92px;
            font-size: 24px;
            background: #fff;
            border: 2px solid yellowgreen;
            cursor: pointer;
            color: yellowgreen;
        }
        
        div::before {
            content: "";
            position: absolute;
            top: 0px;
            bottom: 0px;
            right: -20px;
            left: 0px;
            background: #fff;
            transform: rotateZ(-90deg) translate(-100%, -100%);
            transform-origin: top left;
            transition: transform .3s;
            transition-timing-function: linear;
        }
        
        div:hover {
            filter: contrast(1.2);
        }
        
        div:hover::before {
            transform: rotateZ(0deg) translate(0%, -0%);
        }
        
        div:nth-child(2) {
            overflow: unset;
        }
        
        div::after {
            content: "";
        }
        
        div:nth-child(1):hover~div:nth-child(2)::before {
            transform: rotateZ(0deg) translate(0%, -0%);
        }
    </style>
</head>

<body>
    <div>Hover Me</div>
    <div>Hover Me</div>
</body>

</html>

两个核心点:

  1. 我们利用 overflow: hidden,把原本在容器外的一整个元素隐藏了起来
  2. 利用了 transform-origin,控制了元素的旋转中心

发现没,其实几乎大部分的有意思的 CSS 效果,都是运用了类似技巧

总结

简单的说就是,我们看到的动画只是原本现象的一小部分,通过特定的裁剪、透明度的变化、遮罩等,让我们最后只看到了原本现象的一部分。

在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值