本想起一个哗众取宠的标题,但转念一想,还是求真务实一点,用内容说话。今天我们抛开JS,不用SVG,单纯使用CSS来一步一步地制作响应式的仿真眼球。
先睹为快
- 最终效果
|
|
---|
- 在线预览
请戳这里 - 代码仓库
我已将其封装成vue组件,托管在各仓库上,有兴趣可以看一看。
github
gitee
绘制眼球基础球体
- html
- css
body {
background-image: radial-gradient(ellipse at 50% 0%, #eef 0, #888 100%);
min-height: 100vh;
display: flex;
flex-wrap: nowrap;
flex-direction: row;
align-items: center;
justify-content: center;
}
.eye_container {
width: 200px;
height: 200px;
}
.eye {
position: relative;
width: 100%;
height: 100%;
border-radius: 50%;
background-image: radial-gradient(circle at 45% 45%, #fff 41%, #ccc 83%);
}
- 通过
.eye_container
来定义眼球的边界,通过它来控制眼球的大小。 - 通过
radial-gradient(径向渐变)
,由中心点辐射开进行颜色渐变,这里选取中心点偏左(45%)处开始渐变,通过灰色渐变构造出立体感。
描绘虹膜基础轮廓
- html
- css
.eye_iris {
position: absolute;
top: 25%;
left: 25%;
width: 50%;
height: 50%;
border-radius: 50%;
box-shadow: 0 0 5px 0 #000;
background: radial-gradient(circle at center, #b86e29 32%, #94c7d4 42%, #1c0a24 112%);
}
通过三种颜色构成的径向渐变构造出虹膜的基础轮廓,同时通过box-shadow制作虹膜边框的模糊特效。
制作四根睫状肌
- html
- css
.eye_ciliary {
display: block;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
transform: rotateZ(1deg);
}
.eye_ciliary_item {
display: block;
width: 100%;
height: 100%;
position: absolute;
top: 50%;
margin-top: -50%;
}
.eye_ciliary_item span {
display: block;
width: 100%;
height: 100%;
position: absolute;
}
.eye_ciliary_item:before,
.eye_ciliary_item:after,
.eye_ciliary_item span:before,
.eye_ciliary_item span:after {
content: "";
display: block;
width: 100%;
height: 100%;
position: absolute;
background-color: #000;
opacity: 0.1;
}
.eye_ciliary_item:before {
transform: scale(0.025, 0.7) rotate(45deg);
}
.eye_ciliary_item:after {
transform: scale(0.7, 0.025) rotate(45deg);
}
.eye_ciliary_item span:before {
transform: rotate(45deg) scale(0.025, 0.7) rotate(45deg);
}
.eye_ciliary_item span:after {
transform: rotate(-45deg) scale(0.025, 0.7) rotate(45deg);
}
-
li
的:before
、:after
伪元素及span
的:before
、:after
伪元素构成四个同虹膜一般大小的正方形。 - 将这4个正方形通过变换得到菱形,首先正方形向不同的方向旋转,然后往较长的一边拉长,另外一边收缩得到菱形。
- 根据勾股定理,我们假设虹膜的矩形边长为
1
,则可以得到虹膜的直径为0.7
(1/√2=0.707106...
),故此处将较长的边缩放为原来的0.7
倍,正好填充满虹膜直径。
增加更多的睫状肌
- html
- css
.eye_ciliary_item:nth-child(2) {
transform: rotateZ(5deg);
}
.eye_ciliary_item:nth-child(3) {
transform: rotateZ(10deg);
}
.eye_ciliary_item:nth-child(4) {
transform: rotateZ(15deg);
}
.eye_ciliary_item:nth-child(5) {
transform: rotateZ(20deg);
}
.eye_ciliary_item:nth-child(6) {
transform: rotateZ(25deg);
}
.eye_ciliary_item:nth-child(7) {
transform: rotateZ(30deg);
}
.eye_ciliary_item:nth-child(8) {
transform: rotateZ(35deg);
}
.eye_ciliary_item:nth-child(9) {
transform: rotateZ(40deg);
}
我们假设两条睫状肌之间的角度偏差为5度,则一共需要360/5 = 72
条睫状肌,而根据上个步骤,一个li
可在四个象限产生总数为8条的睫状肌,因此我们此处构造了72/8 = 9
个li
。
绘制瞳孔
- html
- css
.eye_ciliary_sub {
width: 60%;
height: 60%;
top: 20%;
left: 20%;
}
.eye_ciliary_sub .eye_ciliary_item:before,
.eye_ciliary_sub .eye_ciliary_item:after,
.eye_ciliary_sub .eye_ciliary_item span:before,
.eye_ciliary_sub .eye_ciliary_item span:after {
opacity: 1;
}
与虹膜的睫状肌制作一样来制作瞳孔,只是通过缩小体积和调整透明度是的中间部分的颜色更加深暗。
瞳孔增加高光
- html
- css
.eye_reflect {
position: absolute;
top: 30%;
left: 30%;
width: 20%;
height: 15%;
border-radius: 50%;
transform: rotate(-35deg);
background-image: radial-gradient(circle at center, #fff 0%, #fff 40%, rgba(255,255,255,0) 100%);
z-index: 2;
opacity: .9;
}
.eye_reflect_sec {
top: 58%;
left: 50%;
width: 12%;
height: 6%;
background-image: radial-gradient(ellipse at center, #fff 0%, #fff 10%, rgba(255,255,255,0) 100%);
transform: rotate(35deg);
}
.eye_reflect_sub {
width: 80%;
height: 80%;
top: 0;
left: 0;
margin-left: -10%;
margin-top: -10%;
background-image: none;
background-color: rgba(255,255,255, .1);
z-index: 3;
}
通过两个小的椭圆渐变及一个大的透明的圆形径向渐变来表现出高光,同时通过调整旋转角度将其放置在合适的位置。
添加阴影
角膜阴影
- css
.eye_iris {
top: 15%;
left: 15%;
box-shadow: 0 0 5px 2px rgba(0,0,0,0.4), 5px 5px 5px 0 rgba(0,0,0,0.5) inset;
}
这边增加了角膜内阴影,然后通过改变虹膜的位置调节眼球的转向使之更靠近光源,让角膜阴影显得更加自然。
眼球阴影
- html
- css
.eye_iris {
background-image: radial-gradient(circle at center, #b86e29 32%, #94c7d4 42%, #1c0a24 200%);
}
.eye:before, .eye:after {
content: "";
display: block;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border-radius: 50%;
}
.eye:before {
opacity: .75;
mix-blend-mode: color-burn;
background-image: radial-gradient(circle at 45% 45%, #ffe 30%, #222 67%, #558 80%);
z-index: 10;
}
.eye:after {
mix-blend-mode: overlay;
background-image: radial-gradient(circle at 65% 65%, #000 20%, rgba(0,0,0,0) 40%);
z-index: 4;
opacity: 0.5;
}
.shade {
position: relative;
width: 130%;
height: 10%;
margin: 0 2em;
border-radius: 80% 60%;
background-image: radial-gradient(ellipse at center, #000 0%, rgba(0,0,0, 0.6) 30%, rgba(0,0,0, 0) 70%);
z-index: 1;
}
- 利用
.eye
的:befoer
和:after
伪元素构造出球体上的背光阴影 - 通过
.shade
制作球体在下方的投影
增加浮动效果
- css
.eye_iris {
-webkit-animation: eye_iris_shade ease-in-out 1.5s infinite;
animation: eye_iris_shade ease-in-out 1.5s infinite;
}
.eye:after {
-webkit-animation: eye_shade ease-in-out 1.5s infinite;
animation: eye_shade ease-in-out 1.5s infinite;
}
.eye {
-webkit-animation: float ease-in-out 1.5s infinite;
animation: float ease-in-out 1.5s infinite;
}
.shade {
-webkit-animation: shade ease-in-out 1.5s infinite;
animation: shade ease-in-out 1.5s infinite;
}
@-webkit-keyframes float {
0% {
-webkit-transform: translateY(0);
transform: translateY(0);
}
50% {
-webkit-transform: translateY(1em);
transform: translateY(1em);
}
100% {
-webkit-transform: translateY(0);
transform: translateY(0);
}
}
@keyframes float {
0% {
-webkit-transform: translateY(0);
transform: translateY(0);
}
50% {
-webkit-transform: translateY(1em);
transform: translateY(1em);
}
100% {
-webkit-transform: translateY(0);
transform: translateY(0);
}
}
@-webkit-keyframes shade {
0% {
-webkit-transform: translateY(0) translateX(1em);
transform: translateY(0) translateX(1em);
opacity: .5;
}
50% {
-webkit-transform: translateY(1em) translateX(-1em) scale(.9);
transform: translateY(1em) translateX(-1em) scale(.9);
opacity: 1;
}
100% {
-webkit-transform: translateY(0) translateX(1em);
transform: translateY(0) translateX(1em);
opacity: .5;
}
}
@keyframes shade {
0% {
-webkit-transform: translateY(0) translateX(1em);
transform: translateY(0) translateX(1em);
opacity: .5;
}
50% {
-webkit-transform: translateY(1em) translateX(-1em) scale(.9);
transform: translateY(1em) translateX(-1em) scale(.9);
opacity: 1;
}
100% {
-webkit-transform: translateY(0) translateX(1em);
transform: translateY(0) translateX(1em);
opacity: .5;
}
}
@-webkit-keyframes eye_shade {
0% {
opacity: .2;
}
50% {
opacity: .5;
}
100% {
opacity: .2;
}
}
@keyframes eye_shade {
0% {
opacity: .2;
}
50% {
opacity: .5;
}
100% {
opacity: .2;
}
}
@-webkit-keyframes eye_iris_shade {
0% {
-webkit-box-shadow: 0 0 3px 1px rgba(0,0,0,0.4), 5px 5px 5px 0 rgba(0,0,0,0.2) inset;
box-shadow: 0 0 3px 1px rgba(0,0,0,0.4), 5px 5px 5px 0 rgba(0,0,0,0.2) inset;
}
50% {
-webkit-box-shadow: 0 0 3px 1px rgba(0,0,0,0.4), 5px 5px 5px 0 rgba(0,0,0,0.5) inset;
box-shadow: 0 0 3px 1px rgba(0,0,0,0.4), 5px 5px 5px 0 rgba(0,0,0,0.5) inset;
}
100% {
-webkit-box-shadow: 0 0 3px 1px rgba(0,0,0,0.4), 5px 5px 5px 0 rgba(0,0,0,0.2) inset;
box-shadow: 0 0 3px 1px rgba(0,0,0,0.4), 5px 5px 5px 0 rgba(0,0,0,0.2) inset;
}
}
@keyframes eye_iris_shade {
0% {
-webkit-box-shadow: 0 0 3px 1px rgba(0,0,0,0.4), 5px 5px 5px 0 rgba(0,0,0,0.2) inset;
box-shadow: 0 0 3px 1px rgba(0,0,0,0.4), 5px 5px 5px 0 rgba(0,0,0,0.2) inset;
}
50% {
-webkit-box-shadow: 0 0 3px 1px rgba(0,0,0,0.4), 5px 5px 5px 0 rgba(0,0,0,0.5) inset;
box-shadow: 0 0 3px 1px rgba(0,0,0,0.4), 5px 5px 5px 0 rgba(0,0,0,0.5) inset;
}
100% {
-webkit-box-shadow: 0 0 3px 1px rgba(0,0,0,0.4), 5px 5px 5px 0 rgba(0,0,0,0.2) inset;
box-shadow: 0 0 3px 1px rgba(0,0,0,0.4), 5px 5px 5px 0 rgba(0,0,0,0.2) inset;
}
}
- 在动画的不同阶段调节透明度,及阴影位置大小来调节阴影的效果,靠近光源时,透明度变大,沿X轴拉长,远离光源时,透明度变小,沿着X轴缩短。