Создание CSS3 эффекта мигающего века

100
09 марта 2021, 13:00

Я пытаюсь создать экран ожидания c цифрами обратного отсчета, который показывает глаз вместе с веком, и глазное яблоко с эффектом радужной оболочки.

Учитывая, что многие из нас бессмысленно проводят время, глядя на такие лоадеры, я хочу создать такой эффект лоадера, при котором вращающийся "глаз" смотрит на зрителя и мигает.

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>

То, чего я смог достичь к настоящему времени, показано ниже - я установил здесь тикер на 300 секунд, просто в качестве иллюстрации, чтобы он продолжал работать в течение долгого времени - в реальном приложении время ожидания, вероятно, будет значительно меньше.

Пока этот эффект движется в правильном направлении, но ему все еще не хватает эффекта моргания века. Я подозреваю, что это легко выполнимо с помощью правильной манипуляцией box-shadow и простой анимацией.

Я был бы очень признателен всем, кто мог бы предложить улучшения для завершения этой реализации.

Свободный перевод вопроса Creating a CSS blinking eyelid effect от участника @DroidOS.

Answer 1

Двигаем 2 опорные точки в кривой Безье в зависимости от времени :

requestAnimationFrame(draw); 
 
function draw(t) { 
 
  // двигаем зрачок 
  circle.setAttribute('cx', Math.sin(t/1000)*2); 
 
  // анимируем градиент 
  grad.setAttribute('offset', 40 + Math.sin(t/3000)*20 + '%'); 
 
  // сглаживаем время по формуле easeInOutQuint 
  t = Math.max(0, Math.sin(t/300)); 
  t = (t<.5 ? 16*t*t*t*t*t : 1+16*(--t)*t*t*t*t)*6-3; 
   
  // кривая Безье в зависимости от сглаженного значения времени 
  let d = `-7 0C-2 ${t} 2 ${t} 7 0`; 
  mask.setAttribute('d', `M-7 -7${d}L7 -7z`); 
  eyelid.setAttribute('d', `M${d}`); 
 
  requestAnimationFrame(draw); 
}
<svg viewbox="-10 -10 20 20" height="90vh"> 
  <defs><radialGradient id="g1" cx="50%" cy="50%" r="50%"> 
      <stop stop-color="black" offset="0%"/> 
      <stop id="grad" stop-color="teal" offset="30%"/> 
      <stop stop-color="white" offset="100%"/> 
  </radialGradient></defs> 
  <circle id="circle" r="2.4" stroke="black" fill="url(#g1)" stroke-width="0.2"></circle> 
  <path id="mask" stroke="none" fill="white"></path> 
  <path id="eyelid" stroke="black" fill="none"></path> 
</svg>

let rnd = (a, b) => (a||0) + ((b-a)||1) * Math.random(); 
let eyes = Array(22).fill(0).map((e, i) => ({ 
  i,  
  t: rnd(1, 10),  
  x: rnd(-96, 96),  
  y: rnd(-46, 46),  
  k: rnd(0.05,0.2),  
  r: rnd(-33,33) 
})) 
 
defs.innerHTML = eyes.map(e => ` 
  <radialGradient id="gradient_${e.i}" cx="50%" cy="50%" r="50%"> 
    <stop stop-color="black" offset="0%"/> 
    <stop id="color_${e.i}" stop-color="hsl(${rnd(0, 360)},55%,35%)" offset="30%"/> 
    <stop stop-color="white" offset="100%"/> 
  </radialGradient> 
  <clipPath id="clip_${e.i}"> 
    <path></path> 
  </clipPath> 
`).join(''); 
 
g.innerHTML = eyes.map(e => ` 
  <g id="eye_${e.i}" transform="rotate(${e.r})scale(${e.k})translate(${e.x},${e.y})"> 
    <circle r="2.4" stroke="black" fill="url(#gradient_${e.i})" stroke-width="0.2" clip-path="url(#clip_${e.i})"></circle> 
    <path stroke="black" fill="none"></path> 
  </g>   
`).join(''); 
 
eyes.forEach(e => e.elements = { 
  circle: document.querySelector(`#eye_${e.i} circle`), 
  clipPath: document.querySelector(`#clip_${e.i} path`), 
  eyelid: document.querySelector(`#eye_${e.i} path`), 
  gradient: document.querySelector(`#color_${e.i}`) 
}) 
 
requestAnimationFrame(draw); 
 
function draw(t) { 
 
  eyes.forEach(e => { 
    e.elements.circle.setAttribute('cx', Math.sin(t/100/(e.t+e.i))*2); 
    e.elements.gradient.setAttribute('offset', 40 + Math.sin(t/300/(e.t+e.i))*20 + '%'); 
    let T = Math.max(0, Math.sin(t/50/(e.t+e.i))); 
    T = (T<.5 ? 16*T*T*T*T*T : 1+16*(--T)*T*T*T*T)*6-3; 
    let d = `-7 0C-2 ${T} 2 ${T} 7 0`; 
    e.elements.clipPath.setAttribute('d', `M-7 3${d}L7 3z`); 
    e.elements.eyelid.setAttribute('d', `M${d}`); 
  }) 
   
 
  requestAnimationFrame(draw); 
}
<svg viewbox="-20 -10 40 20" height="90vh"> 
  <defs id="defs"></defs> 
  <g id="g"></g> 
</svg>

PS: функция сглаживания взята отсюда: https://gist.github.com/gre/1650294

Answer 2

Версия на Smil

<svg width="300px" xmlns="http://www.w3.org/2000/svg"> 
 <g transform="translate(-8,-121)"> 
 <g id="eye"> 
  <ellipse cx="106.2113" cy="150.72321" rx="27.59226" ry="22.300594"/> 
  <ellipse cx="108.47916" cy="149.58928" rx="10.205358" ry="8.3154764" fill="#fff"/> 
 
  <animateTransform  
   	  attributeName="transform" 
      attributeType="XML" 
      type="translate" 
      from="-5 0" 
      to="5 0" 
      dur="6s" 
      repeatCount="indefinite"/> 
    <animate  
       attributeName="fill" 
       dur="3000ms"  
       repeatCount="indefinite" 
       values="#1eb287; 
               #1eb287; 
               #1ca69e; 
               #188fc2; 
               #188fc2; 
               #bb625e; 
               #ca5f52; 
               #1eb287;"/> 
</g> 
  <path d="" fill="#fff" stroke="#000" stroke-width="12" stroke-linecap="round"> 
     <animate  
      attributeName="d" 
      dur="1.8s" 
      repeatCount="indefinite" 
      values=  
      "m195.79166 129.17857c-59.10423 2.90575-116.58946 5.9255-177.6488-3.02381; 
       M 195.79166,129.17857 C 140.04024,174.83267 83.866918,194.57929 18.142857,126.15476; 
       M 195.79166,129.17857 C 140.04024,174.83267 83.866918,194.57929 18.142857,126.15476; 
       M 195.79166,129.17857 C 140.04024,174.83267 83.866918,194.57929 18.142857,126.15476; 
       m195.79166 129.17857c-59.10423 2.90575-116.58946 5.9255-177.6488-3.02381;" 
       keyTimes="0; 0.11; 0.21; 0.72; 1" 
        />  
    <animate  
       attributeName="stroke" 
       dur="8000ms"  
       repeatCount="indefinite" 
      keyTimes="0; 
             .0625; 
             .208333333; 
             .3125; 
             1" 
       values="red; 
               green; 
               blue; 
               yellow; 
               pink;"/> 
  </path> 
 </g> 
 
 
</svg>

Answer 3

Решение SVG SMIL

  • Анимация века глаза достигается изменением атрибута "d" <path> с помощью перехода из верхнего положения вниз.
  • Для реалистичности изображения века (придания объема) использованы радиальные градиенты
  • Паузы в верхнем и нижнем положении века достигаются повторением позиций

    Более подробно об анимациях с паузами - Как в SVG реализовать анимацию туда и обратно

Вариант решения без счётчика

<svg version="1.1" xmlns="http://www.w3.org/2000/svg"  
    xmlns:xlink="http://www.w3.org/1999/xlink" 
   width="25%" height="25%"   viewBox="0 0 200 200" preserveAspectRatio="xMinYMin meet">   
<defs> 
 <radialGradient id="grad1" cx="40%" cy="20%" r="100%" fx="45%" fy="20%"> 
    
   <stop stop-color="#B7B3B8" offset="10%"/> 
   <stop stop-color="#CDC9D0" offset="65%"/> 
   <stop stop-color="#9D90A2" offset="85%"/> 
   <stop stop-color="#CDBED3" offset="100%"/> 
 </radialGradient> 
 </defs> 
<image xlink:href="https://i.stack.imgur.com/gDG2U.jpg" width="100%" height="100%" /> 
 
 <path id="veko" fill="url(#grad1)" stroke="#B9B5BB" stroke-width="4" d="m12.7 132c0 0 25.6-19.6 39.8-27.1 11.7-6.2 23.9-11.9 36.9-14.4 10.7-2.1 21.9-2 32.6-0.4 8.5 1.3 16.8 4.3 24.6 7.8 9 4.1 17.1 9.9 25.2 15.5 2.2 1.5 4.9 2.6 6.4 4.9 0.4 0.6 1.1 2.4 0.4 2.1-6.7-2.5-17.2-10.3-26.1-14.8-6.6-3.3-13.1-6.8-20.1-9.1-5.2-1.7-10.6-2.9-16.1-3.4-8.6-0.8-17.5-1.3-26.1 0.4-12.4 2.5-24 8.4-35.4 14-14.6 7.1-42.2 24.6-42.2 24.6z" > 
 <animate attributeName="d" dur="4s" repeatCount="indefinite" values=" 
   m12.7 132c0 0 25.6-19.6 39.8-27.1 11.7-6.2 23.9-11.9 36.9-14.4 10.7-2.1 21.9-2 32.6-0.4 8.5 1.3 16.8 4.3 24.6 7.8 9 4.1 17.1 9.9 25.2 15.5 2.2 1.5 4.9 2.6 6.4 4.9 0.4 0.6 1.1 2.4 0.4 2.1-6.7-2.5-17.2-10.3-26.1-14.8-6.6-3.3-13.1-6.8-20.1-9.1-5.2-1.7-10.6-2.9-16.1-3.4-8.6-0.8-17.5-1.3-26.1 0.4-12.4 2.5-24 8.4-35.4 14-14.6 7.1-42.2 24.6-42.2 24.6z;     
   m12.7 132c0 0 25.6-19.6 39.8-27.1 11.7-6.2 23.9-11.9 36.9-14.4 10.7-2.1 21.9-2 32.6-0.4 8.5 1.3 16.8 4.3 24.6 7.8 9 4.1 17.1 9.9 25.2 15.5 2.2 1.5 4.9 2.6 6.4 4.9 0.4 0.6 1.1 2.4 0.4 2.1-6.7-2.5-17.2-10.3-26.1-14.8-6.6-3.3-13.1-6.8-20.1-9.1-5.2-1.7-10.6-2.9-16.1-3.4-8.6-0.8-17.5-1.3-26.1 0.4-12.4 2.5-24 8.4-35.4 14-14.6 7.1-42.2 24.6-42.2 24.6z; 
    
   m12.7 132c0 0 25.6-19.6 39.8-27.1 11.7-6.2 23.9-11.9 36.9-14.4 10.7-2.1 21.9-2 32.6-0.4 8.5 1.3 16.8 4.3 24.6 7.8 9 4.1 17.1 9.9 25.2 15.5 2.2 1.5 6.4 4.9 6.4 4.9-0.1 0.7 2.8-0.5 0.4 2.1-4.7 5.2-11 10.6-17.4 14.6-6 3.8-12.7 6.5-19.5 8.9-6.1 2.1-12.4 3.9-18.9 4.7-8.3 1-16.8 0.5-25.2 0-13-0.8-26-2.3-38.8-4.7-15.6-2.9-46.2-11.9-46.2-11.9z;    
   m12.7 132c0 0 25.6-19.6 39.8-27.1 11.7-6.2 23.9-11.9 36.9-14.4 10.7-2.1 21.9-2 32.6-0.4 8.5 1.3 16.8 4.3 24.6 7.8 9 4.1 17.1 9.9 25.2 15.5 2.2 1.5 6.4 4.9 6.4 4.9-0.1 0.7 2.8-0.5 0.4 2.1-4.7 5.2-11 10.6-17.4 14.6-6 3.8-12.7 6.5-19.5 8.9-6.1 2.1-12.4 3.9-18.9 4.7-8.3 1-16.8 0.5-25.2 0-13-0.8-26-2.3-38.8-4.7-15.6-2.9-46.2-11.9-46.2-11.9z; 
   m12.7 132c0 0 25.6-19.6 39.8-27.1 11.7-6.2 23.9-11.9 36.9-14.4 10.7-2.1 21.9-2 32.6-0.4 8.5 1.3 16.8 4.3 24.6 7.8 9 4.1 17.1 9.9 25.2 15.5 2.2 1.5 4.9 2.6 6.4 4.9 0.4 0.6 1.1 2.4 0.4 2.1-6.7-2.5-17.2-10.3-26.1-14.8-6.6-3.3-13.1-6.8-20.1-9.1-5.2-1.7-10.6-2.9-16.1-3.4-8.6-0.8-17.5-1.3-26.1 0.4-12.4 2.5-24 8.4-35.4 14-14.6 7.1-42.2 24.6-42.2 24.6z"	   /> 
 </path> 
</svg>	 

Вариант с обратным счётчиком

var checks = 100, 
    checker = setInterval(Count, 2100); 
 
  function Count() { 
    document.getElementById('txt1').textContent = --checks; 
    if (0 === checks) clearInterval(checker); 
  }
.container { 
 background:silver; 
  
} 
svg { 
display:block; 
width:15%; 
height:23%; 
padding-left:0.5em; 
padding-bottom:1.5em; 
margin:1em; 
border-radius:50%; 
-webkit-box-shadow: 7px 7px 5px 0px rgba(50, 50, 50, 0.75); 
-moz-box-shadow:    7px 7px 5px 0px rgba(50, 50, 50, 0.75); 
box-shadow:         7px 7px 5px 0px rgba(50, 50, 50, 0.75); 
background:#8C6282; 
} 
#txt1 { 
  font-size: 40px; 
  font-weight:bold; 
  fill:#FFDD00; 
  stroke:#917E00; 
  text-anchor:middle; 
}
<div  class="container">  
 
<svg id="svg1" version="1.1" xmlns="http://www.w3.org/2000/svg"  
    xmlns:xlink="http://www.w3.org/1999/xlink" 
   width="50%" height="50%"   viewBox="0 0 200 200" preserveAspectRatio="xMinYMin meet">   
<defs>  
   
 <radialGradient id="grad1" cx="40%" cy="20%" r="100%" fx="45%" fy="20%"> 
    
   <stop stop-color="#B7B3B8" offset="10%"/> 
   <stop stop-color="#CDC9D0" offset="65%"/> 
   <stop stop-color="#9D90A2" offset="85%"/> 
   <stop stop-color="#CDBED3" offset="100%"/> 
 </radialGradient>  
  <mask id="msk1" >  
   <path fill="white" d="M0.9 129.9C10.6 74.7 114.5 44.3 176.2 88.8c8 5.1 16.2 15.8 16.8 23.4C200 200 1.1 166.8 0.9 129.9" /> 
  </mask> 
 </defs>  
 <g mask="url(#msk1)" > 
<image xlink:href="https://i.stack.imgur.com/gDG2U.jpg" width="100%" height="100%"   /> 
 
<text id="txt1" x="98" y="130"  >100</text>  
 
 <path id="veko" fill="url(#grad1)" stroke="#B9B5BB" stroke-width="1" d="m12.7 132c0 0 25.6-19.6 39.8-27.1 11.7-6.2 23.9-11.9 36.9-14.4 10.7-2.1 21.9-2 32.6-0.4 8.5 1.3 16.8 4.3 24.6 7.8 9 4.1 17.1 9.9 25.2 15.5 2.2 1.5 4.9 2.6 6.4 4.9 0.4 0.6 1.1 2.4 0.4 2.1-6.7-2.5-17.2-10.3-26.1-14.8-6.6-3.3-13.1-6.8-20.1-9.1-5.2-1.7-10.6-2.9-16.1-3.4-8.6-0.8-17.5-1.3-26.1 0.4-12.4 2.5-24 8.4-35.4 14-14.6 7.1-42.2 24.6-42.2 24.6z" > 
 <animate attributeName="d" dur="2.4s" repeatCount="indefinite" values=" 
   m12.7 132c0 0 25.6-19.6 39.8-27.1 11.7-6.2 23.9-11.9 36.9-14.4 10.7-2.1 21.9-2 32.6-0.4 8.5 1.3 16.8 4.3 24.6 7.8 9 4.1 17.1 9.9 25.2 15.5 2.2 1.5 4.9 2.6 6.4 4.9 0.4 0.6 1.1 2.4 0.4 2.1-6.7-2.5-17.2-10.3-26.1-14.8-6.6-3.3-13.1-6.8-20.1-9.1-5.2-1.7-10.6-2.9-16.1-3.4-8.6-0.8-17.5-1.3-26.1 0.4-12.4 2.5-24 8.4-35.4 14-14.6 7.1-42.2 24.6-42.2 24.6z;     
   m12.7 132c0 0 25.6-19.6 39.8-27.1 11.7-6.2 23.9-11.9 36.9-14.4 10.7-2.1 21.9-2 32.6-0.4 8.5 1.3 16.8 4.3 24.6 7.8 9 4.1 17.1 9.9 25.2 15.5 2.2 1.5 4.9 2.6 6.4 4.9 0.4 0.6 1.1 2.4 0.4 2.1-6.7-2.5-17.2-10.3-26.1-14.8-6.6-3.3-13.1-6.8-20.1-9.1-5.2-1.7-10.6-2.9-16.1-3.4-8.6-0.8-17.5-1.3-26.1 0.4-12.4 2.5-24 8.4-35.4 14-14.6 7.1-42.2 24.6-42.2 24.6z; 
    
   m12.7 132c0 0 25.6-19.6 39.8-27.1 11.7-6.2 23.9-11.9 36.9-14.4 10.7-2.1 21.9-2 32.6-0.4 8.5 1.3 16.8 4.3 24.6 7.8 9 4.1 17.1 9.9 25.2 15.5 2.2 1.5 6.4 4.9 6.4 4.9-0.1 0.7 2.8-0.5 0.4 2.1-4.7 5.2-11 10.6-17.4 14.6-6 3.8-12.7 6.5-19.5 8.9-6.1 2.1-12.4 3.9-18.9 4.7-8.3 1-16.8 0.5-25.2 0-13-0.8-26-2.3-38.8-4.7-15.6-2.9-46.2-11.9-46.2-11.9z;    
   m12.7 132c0 0 25.6-19.6 39.8-27.1 11.7-6.2 23.9-11.9 36.9-14.4 10.7-2.1 21.9-2 32.6-0.4 8.5 1.3 16.8 4.3 24.6 7.8 9 4.1 17.1 9.9 25.2 15.5 2.2 1.5 6.4 4.9 6.4 4.9-0.1 0.7 2.8-0.5 0.4 2.1-4.7 5.2-11 10.6-17.4 14.6-6 3.8-12.7 6.5-19.5 8.9-6.1 2.1-12.4 3.9-18.9 4.7-8.3 1-16.8 0.5-25.2 0-13-0.8-26-2.3-38.8-4.7-15.6-2.9-46.2-11.9-46.2-11.9z; 
   m12.7 132c0 0 25.6-19.6 39.8-27.1 11.7-6.2 23.9-11.9 36.9-14.4 10.7-2.1 21.9-2 32.6-0.4 8.5 1.3 16.8 4.3 24.6 7.8 9 4.1 17.1 9.9 25.2 15.5 2.2 1.5 4.9 2.6 6.4 4.9 0.4 0.6 1.1 2.4 0.4 2.1-6.7-2.5-17.2-10.3-26.1-14.8-6.6-3.3-13.1-6.8-20.1-9.1-5.2-1.7-10.6-2.9-16.1-3.4-8.6-0.8-17.5-1.3-26.1 0.4-12.4 2.5-24 8.4-35.4 14-14.6 7.1-42.2 24.6-42.2 24.6z"	   /> 
 </path> 
 </g> 
  
 </svg>	 
 </div>

Связанный вопрос: Анимация svg глаз кролика с помощью атрибутов path “d” и “keyTimes”

Answer 4

Я сделал бы это по-другому и рассмотрел бы вращение для получения эффекта мерцания. Трюк заключается в том, чтобы создать глаз с двумя элементами (веко), чтобы они имели возможность моргать.

Вот код только с анимацией мерцания:

.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>

Вот более реалистичное мигание век у всего глаза:

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>

Свободный перевод ответа Creating a CSS blinking eyelid effect от участника @Temani Afif.

Answer 5

Размер зрачка зависит от расстояния до мышки.

Глаз поворачивается в направлении указателя.

Процент загрузки выражается размером сектора радужной оболочки.

let mouse = {x:0, y:0},  
    progress = 0; 
     
setInterval(e => progress = (progress + Math.random()/100)%1, 100) 
requestAnimationFrame(draw); 
addEventListener('pointermove', e => {mouse.x = e.x, mouse.y = e.y}) 
 
function draw(t) { 
 
  requestAnimationFrame(draw); 
   
  // двигаем зрачок 
  let dx = mouse.x - innerWidth/2, 
      dy = mouse.y - innerHeight/2, 
      len = Math.sqrt(dx*dx + dy*dy), 
      ml = Math.min(len*10/innerHeight, 1), 
      a = Math.atan2(dy, dx), 
      x = Math.cos(a) * ml,  
      y = Math.sin(a)/2 * ml; 
       
  circle1.setAttribute('cx', x); 
  circle1.setAttribute('cy', y); 
  circle2.setAttribute('cx', x); 
  circle2.setAttribute('cy', y); 
   
  // процент загрузки 
  let r = 1.8,  
      p = progress *2 * Math.PI,  
      px = r*Math.cos(p),  
      py = r*Math.sin(p), 
      arc = 1-Math.round(progress); 
       
  load.setAttribute('d', `M${r},0 A${r},${r},0,${arc},0,${px},${py}L0,0z`) 
  load.setAttribute('transform', `translate(${x}, ${y})`) 
   
  // анимируем градиент 
  let offset = Math.max(0.2, (0.5 - len/2/innerHeight))*100 + "%";   
  grad1.setAttribute('offset', offset); 
  grad2.setAttribute('offset', offset); 
   
  // сглаживаем время по формуле easeInOutQuint 
  t = Math.max(0, Math.sin(t/300)); 
  t = (t<.5 ? 16*t*t*t*t*t : 1+16*(--t)*t*t*t*t)*6-3; 
   
  // кривая Безье в зависимости от сглаженного значения времени 
  let d = `-7 0C-2 ${t} 2 ${t} 7 0`; 
  mask.setAttribute('d', `M-7 -7${d}L7 -7z`); 
  eyelid.setAttribute('d', `M${d}`); 
}
<body style="margin:0 calc(50vw - 50vh); overflow:hidden;"> 
<svg viewbox="-10 -10 20 20" height="100vh"> 
  <defs> 
    <radialGradient id="g1" cx="50%" cy="50%" r="50%"> 
        <stop stop-color="black" offset="0%"/> 
        <stop id="grad1" stop-color="#4f899d" offset="30%"/> 
        <stop stop-color="white" offset="100%"/> 
    </radialGradient> 
    <radialGradient id="g2" cx="50%" cy="50%" r="50%"> 
        <stop stop-color="black" offset="0%"/> 
        <stop id="grad2" stop-color="#885d33" offset="30%"/> 
        <stop stop-color="white" offset="100%"/> 
    </radialGradient> 
    <mask id="m1"> 
      <path id="load" fill="#fff"></path> 
    </mask> 
  </defs> 
  <circle id="circle1" r="2" stroke="black" stroke-width="0.2" fill="url(#g2)"></circle> 
  <circle id="circle2" r="2" fill="url(#g1)" mask="url(#m1)"></circle> 
  <path id="mask" stroke="none" fill="white"></path> 
  <path id="eyelid" stroke="black" fill="none"></path> 
</svg> 
</body>

READ ALSO
Простая смена классов JS

Простая смена классов JS

У меня есть валидация с помощью регулярки, где я проверяю совпадают ли условия с введенными даннымиСейчас показан пример где нужно ввести...

100
Разделить строку на массив слов c++

Разделить строку на массив слов c++

В Java есть функцияsplit которая разделяет строку вокруг регулярного выражения и возвращает массив строк, так вот есть ли в C++ (стандартной библиотеке)...

95
Подключение локальной БД из файла на С++

Подключение локальной БД из файла на С++

Пытаюсь подключиться к базе данных, созданной через Visual Studio (Средства -> Подключиться к базе данных)

102