Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating a CSS blinking eyelid effect

I am trying to create a wait/countdown screen that shows an eye along with the eyelid, and eyeball with an iris effect. Given that so many of us spend time pointlessly staring at such spinners the effect I am trying to achieve is of the "eye" spinner looking back at the viewer and blinking.

document.getElementById('waitDia').showModal();

var ticks = 300,
    ticker = setInterval(changeTick,1000);

function changeTick()
{
 document.getElementById('spnTick').innerText = --ticks;
 if (0 === ticks) clearInterval(ticker);
}
#waitDia
{
 position:absolute;
 left:0 !important;
 top:0 !important;
 width:100vw !important;
 height:100vh !important; 
 padding:0; 
 min-width:100vw;
 min-height:100vh; 
 background-color:transparent !important;
}

#waitDia::backdrop{background-color:rgba(127,127,127,0.2);}

#spnTick
{
 position:absolute;
 display:inline-block;
 width:100%;
 left:0;
 top:0;
} 
#waitbox
{
 left:0 !important;
 top:0 !important;
 width:100vw !important;
 height:100vh !important;
 position:absolute;
 overflow:hidden;
}


#eyeball
{
 position:relative;
 top:-10vh;
 left:-6px;
 width:calc(24vh + 12px);
 height:calc(24vh + 12px);
 box-sizing:border-box;
 background:rgba(0,128,128,0.5);
 border-radius:100%;
 border:1px solid transparent;
 box-shadow:inset 0 0 18px 2px blue;
 z-index:99999998;
}


#waitsecs
{
 position:absolute;
 left:calc(50vw - 12vh);
 top:46vh;
 width:24vh;
 height:24vh;
 font-size:8vh;
 text-align:center;
 display:block;
 
}

#waitEye
{
 position:absolute;
 top:27vh;
 left:calc(50vw - 23vh);
 width: 46vh;
 height: 46vh;
 background-color: rgba(255,255,255,.9);
 border-radius: 100% 0px;
 transform: rotate(45deg); 
 mix-blend-mode:overlay;
 z-index:199999999;
 box-shadow:0 -0.5vh 0 2px #f1c27d,inset 0 6px 4px 4px black;
}
body,html
{
 background:black;
 font-family:arial;
}
<dialog id='waitDia' class='waitdia'>
   <div id='waitbox'>
    <div id='waitsecs'><span id='spnTick'>300</span><div id='eyeball'></div></div>
   <div id='waitEye'></div> 
   </div>  
  </dialog>

What I have been able to achieve thus far is shown below - I have set the ticker at 300 seconds here merely by way of illustration so it keeps working for a looong time - in the real application the wait time is likely to be considerably lesser.

While this effect is heading in the right direction it still lacks the eyelid blink effect. I suspect that this is easily doable with the help of correct 'box-shadow' manipulation and a simple animation. However, here I hit the limits of my part time CSS skills. I'd be most grateful to anyone here who might be able to suggest improvements to complete this implementation.

like image 498
DroidOS Avatar asked Dec 22 '22 22:12

DroidOS


1 Answers

I would do this differently and consider rotation for the blink effect. The trick is to create the eye with two elements (the eyelid) to be able to blink it.

Here is the code with only the blink animation:

.eye {
  width: 250px;
  height: 80px;
  margin: 50px;
  display:inline-block;
  perspective: 200px;
  background:
    radial-gradient(circle 100px at 50% 250%,#f1c27d 99% ,transparent 100%) top/100% 50%,
    radial-gradient(circle 100px at 50% -150%,#f1c27d 99% ,transparent 100%) bottom/100% 50%;
  background-repeat:no-repeat
}

.eye>div {
  height: 50%;
  position:relative;
  overflow:hidden;
  transform-origin:bottom;
  animation:b1 0.8s  infinite ease-out alternate;
}
.eye>div:last-child {
  transform-origin:top;
  animation-name:b2;
}
.eye>div:before {
  content: "";
  position: absolute;
  top:0;
  left:10%;
  right:10%;
  padding-top:80%;
  border-radius:50%;
  background:#fff;
  box-shadow:
    -2px 0 0 3px inset #f1c27d,
    inset -5px 5px 2px 4px black;
}
.eye>div:last-child:before {
  bottom:0;
  top:auto;
  box-shadow:
    -2px 0 0 3px inset #f1c27d,
    inset -6px -4px 2px 4px black;
}


body {
 background:#000;
}

@keyframes b1{
  to { transform:rotateX(-88deg);}
}
@keyframes b2{
  to {transform:rotateX(88deg);}
}
<div class="eye">
  <div></div>
  <div></div>
</div>

Here is a more realistic blinking with a full eye:

var ticks = 300,ticker;
setTimeout(function() { ticker = setInterval(changeTick,1600);},500);

function changeTick()
{
 document.querySelector('.eye span').setAttribute('data-text', --ticks);
 if (0 === ticks) clearInterval(ticker);
}
.eye {
  width: 250px;
  height: 80px;
  margin: 50px;
  display:inline-block;
  perspective: 200px;
  background:
    radial-gradient(circle 100px at 50% 250%,#f1c27d 99% ,transparent 100%) top/100% 50%,
    radial-gradient(circle 100px at 50% -150%,#f1c27d 99% ,transparent 100%) bottom/100% 50%;
  background-repeat:no-repeat;
  transform-style:preserve-3d;
  position:relative;
}

.eye>div {
  height: 50%;
  position:relative;
  overflow:hidden;
  transform-origin:bottom;
  z-index:1;
  animation:b1 0.8s  infinite ease-out alternate;
}
.eye>div:last-child {
  transform-origin:top;
  animation:none;
}
.eye>div:before {
  content: "";
  position: absolute;
  top:0;
  left:10%;
  right:10%;
  padding-top:80%;
  border-radius:50%;
  background:#fff;
  box-shadow:
    -2px 0 0 3px inset #f1c27d,
    inset -5px 5px 2px 4px black;
  animation:inherit;
  animation-name:color;
}
.eye>div:last-child:before {
  bottom:0;
  top:auto;
  box-shadow:
    -2px 0 0 3px inset #f1c27d,
    inset -6px -4px 2px 4px black;
}
.eye > span {
  position:absolute;
  width:45px;
  height:45px;
  bottom:18px;
  left:50%;
  transform:translateX(-50%) translateZ(55px);
  overflow:hidden;
  border-radius:20% 20% 0 0;
  z-index:2;
  animation:b2 0.8s  infinite ease-out alternate;
}
.eye > span:before {
  position:absolute;
  left:0;
  bottom:0;
  height:45px;
  width:100%;
  content:attr(data-text);
  border-radius:50%;
  background:#000;
  color:#fff;
  text-align:center;
  line-height:45px;
}


body {
 background:#000;
}

@keyframes b1{
  to { 
    transform:rotateX(-170deg);
  }
}
@keyframes b2{
  50% {
    height:20px;
  }
  60%,100% {
    height:0px;
  }
}
@keyframes color{
  0%,40% {
    background:#fff;
    box-shadow:
      -2px 0 0 3px inset #f1c27d,
      inset -5px 5px 2px 4px black;
  }
  40.1%,100% { 
    background:#f1c27d;
    box-shadow:none;
  }
}
<div class="eye">
  <div></div>
    <span data-text="300"></span>
  <div></div>
</div>
like image 186
Temani Afif Avatar answered Jan 04 '23 00:01

Temani Afif