HTML、JS、CSS实现果冻按钮效果
效果图:
参考代码仍然是yuanchuan前辈的codePen项目果冻按钮
下面开始解读
HTML:
<div id="boxes"><div style="--color: #f44336"></div><div style="--color: #e91e63"></div><div style="--color: #9c27b0"></div><div style="--color: #2196f3"></div><div style="--color: #4caf50"></div><div style="--color: #ff9800"></div></div>
作为示例按钮,在#boxes的Div下加入六个div,并且在样式中加入一个color变量,分别为六个按钮增加一个十六进制颜色值。
在变量名前加--
,即声明一个变量,在取变量时,用var()
读取,
var()
函数还可以使用第二个参数,表示变量的默认值,当该变量不存在时,使用默认值。
css变量详细教程参照
CSS:
html, body {height: 100%; margin: 0;}body, #boxes div {display: flex;align-items: center; justify-content: center;}body:after {z-index: -1;content: '';position: absolute;top: 0;left: 0;width: 100%;height: 100%;transition: all .5s ease;background: var(--bg-color, #f44336);opacity: .1;}#boxes {counter-reset: number;display: grid;grid-template-columns: repeat(3, 1fr);}@media (max-width: 320px) {#boxes {grid-template-columns: repeat(2, 1fr);}}#boxes div {counter-increment: number;width: 10vw;height: 10vw;min-width: 5em;min-height: 5em;transition: .5s all ease;background: var(--color, #aaa);border: 0 solid transparent;box-sizing: border-box;border-radius: 50%;margin: .5em;opacity: .7;--dx: calc(var(--size) - var(--x));--dy: calc(var(--size) - var(--y));}body:not([style]) #boxes div:first-child {--x: 84;--y: 75;--size: 128;}body:not([style]) #boxes div:first-child,#boxes div:hover {opacity: 1;cursor: pointer;border: calc(2px + .85vw) solid rgba(255, 255, 255, .5);transition:.5s background-color ease,.2s border ease;border-radius:calc(var(--x) / var(--size) * 100%) calc(var(--dx) / var(--size) * 100%)calc(var(--dx) / var(--size) * 100%) calc(var(--x) / var(--size) * 100%) / calc(var(--y) / var(--size) * 100%) calc(var(--y) / var(--size) * 100%) calc(var(--dy) / var(--size) * 100%) calc(var(--dy) / var(--size) * 100%) }body:not([style]) #boxes div:first-child:after,#boxes div:after {content: counter(number);color: rgba(255, 255, 255, 0);font-size: calc(1vw + 1.2em);font-weight: 200;transition: all .2s ease;transition-delay: .1s;transform: translate3d(0, -.5em, 0);}body:not([style]) #boxes div:first-child:after,#boxes div:hover:after {color: rgba(255, 255, 255, .7);transform: translate3d(0, 0, 0);}
块1 body:after
body:after {z-index: -1;content: '';position: absolute;top: 0;left: 0;width: 100%;height: 100%;transition: all .5s ease;background: var(--bg-color, #f44336);opacity: .1;}
在body后追加一块背景墙。
transition: 动画过渡效果,transition-property
,transition-duration
,transition-timing-function
和transition-delay
的一个简写属性。background: 背景颜色,如同之前说的,在没有给bg-color这个变量赋值之前,默认的颜色为#f44336有关十六进制颜色,格式为#+六位十六进制,从左到右每两位分别代表RGB,无法设置A
块2 #boxes
#boxes {counter-reset: number;display: grid;grid-template-columns: repeat(3, 1fr);}
设置一个counter变量:number,counter变量需要经历reset (设置) —— increment(自增) —— counter()(读取)boxes的布局为grid布局,grid-template-columns
用repeat()
函数快速设置,fr用于在长度中分配剩余空间,重复3个1fr即三个等宽列
块3 @media
@media (max-width: 320px) {#boxes {grid-template-columns: repeat(2, 1fr);}}
响应式布局,若screen尺寸小于320px,则一行只显示2列
块4 #boxes div
#boxes div {cscounter-increment: number;width: 10vw;height: 10vw;min-width: 5em;min-height: 5em;transition: .5s all ease;background: var(--color, #aaa);border: 0 solid transparent;box-sizing: border-box;border-radius: 50%;margin: .5em;opacity: .7;--dx: calc(var(--size) - var(--x));--dy: calc(var(--size) - var(--y));}
规定boxes容器中的div,即我们模拟的按钮。
counter-increment即之前提到的计数自增vw:相对于视口宽度被100等分的长度单位em:字体大小作为长度单位中的box-sizing
属性定义了 user agent (代指浏览器)应该如何计算一个元素的总宽度和总高度。content-box
是默认值。如果你设置一个元素的宽为100px,那么这个元素的内容区会有100px 宽,并且任何边框和内边距的宽度都会被增加到最后绘制出来的元素宽度中。border-box
告诉浏览器:你想要设置的边框和内边距的值是包含在width内的。也就是说,如果你将一个元素的width设为100px,那么这100px会包含它的border和padding,内容区的实际宽度是width减去(border + padding)的值。大多数情况下,这使得我们更容易地设定一个元素的宽高。border-radius:边框半径,设置为50%之后,div就变成一个圆这边又声明了两个变量dx,dy,为了之后制造果冻效果,calc()
是一个计算方法
块5 body:not([style]) #boxes div:first-child
body:not([style]) #boxes div:first-child {--x: 84;--y: 75;--size: 128;}
not([style])表示选择body中style之外的元素在body中设置三个变量并赋值
块6 body:not([style]) #boxes div:first-child,
#boxes div:hover
body:not([style]) #boxes div:first-child,#boxes div:hover {opacity: 1;cursor: pointer;border: calc(2px + .85vw) solid rgba(255, 255, 255, .5);transition:.5s background-color ease,.2s border ease;border-radius:calc(var(--x) / var(--size) * 100%) calc(var(--dx) / var(--size) * 100%)calc(var(--dx) / var(--size) * 100%) calc(var(--x) / var(--size) * 100%) / calc(var(--y) / var(--size) * 100%) calc(var(--y) / var(--size) * 100%) calc(var(--dy) / var(--size) * 100%) calc(var(--dy) / var(--size) * 100%) }
在鼠标悬浮在按钮之上后,设置cursor、border等样式,并且在border-radius设置中用变量控制值,这样设置之后在js中控制变量的值,从而将按钮的样式随时改变实现果冻效果。
块7\8 body:not([style]) #boxes div:first-child:after,
#boxes div:after
body:not([style]) #boxes div:first-child:after,#boxes div:after {content: counter(number);color: rgba(255, 255, 255, 0);font-size: calc(1vw + 1.2em);font-weight: 200;transition: all .2s ease;transition-delay: .1s;transform: translate3d(0, -.5em, 0);}body:not([style]) #boxes div:first-child:after,#boxes div:hover:after {color: rgba(255, 255, 255, .7);transform: translate3d(0, 0, 0);}
这两个式样设置了当鼠标hover到按钮上时,出现一个数字。content中的counter
方法取到这个按钮是#boxes中的第几个注意div:after中的color的A值为0不可见,设置div:hover:after,当鼠标hover之后,颜色可见
JS
var boxes = document.querySelectorAll('#boxes > div');[].forEach.call(boxes, box => {box.addEventListener('mousemove', e => {document.body.style.setProperty('--bg-color',box.style.getPropertyValue('--color'));var size = parseInt(getComputedStyle(box).width);// scalingvar x = size * .3 * .7 + .7 * e.offsetX;var y = size * .3 * .7 + .7 * e.offsetY;box.style.setProperty('--x', x);box.style.setProperty('--y', y);box.style.setProperty('--size', size);});});
js中有一个骚操作[].forEach.call
这边是快速取到数组中的prototypeforEach
方法,然后把每一个boxes中的div(按钮)都添加一个事件监听,当鼠标在div中移动时, 设置背景颜色和div中提前设置的颜色相同先取到按钮的宽度,然后实时计算出x、y的值,并且将这些值返回到css样式中的x、y、size在css样式中接收到值之后,实时重新渲染按钮的颜色,达到想要的效果这个按钮的果冻效果,主要是用border-radius
这个属性控制的。当然掌握这种样式变更的方法之后,想实现其他效果也是十分方便了
参考代码仍然是yuanchuan前辈的codePen项目果冻按钮