Mô phỏng hiện tượng nhật thực toàn phần bằng HTML5 và CSS3

Giới thiệu

Xin chào các bạn, ngoài công việc là một frontend developer thì mình cũng là người rất thích tìm hiểu về khoa học, các hiện tượng thiên nhiên kỳ thú, 1 trong số đó là hiện tượng nhật thực. Đây là một hiện tượng thiên nhiên khá đặc biệt mà trong đời mỗi người thường chỉ được quan sát một lần, thậm chí có những người còn chưa bao giờ được thấy hiện tượng thiên nhiên đặc biệt này. Đầu tiên, mình xin nói qua một chút về hiện tượng nhật thực nói chung và nhật thực toàn phần nói riêng cho những ai chưa rõ lắm về hiện tượng này. Nhật thực xảy ra khi Mặt Trăng đi qua giữa Trái Đất và Mặt Trời và quan sát từ Trái Đất, lúc đó Mặt Trăng che khuất hoàn toàn hay một phần Mặt Trời. Điều này chỉ có thể xảy ra tại thời điểm sóc trăng non khi nhìn từ Trái Đất, lúc Mặt Trời bị Mặt Trăng che khuất và bóng của Mặt Trăng phủ lên Trái Đất. Trong lúc nhật thực toàn phần, đĩa Mặt Trời bị che khuất hoàn toàn. Với nhật thực một phần hoặc hình khuyên, đĩa Mặt Trời chỉ bị che khuất một phần. Các bạn có thể xem một số hình ảnh mô tả dưới đây về hiện tượng nhật thực.

Mô tả trực quan

Sau đây mình xin đi vào phần chính là sử dụng HTML/CSS để mô tả một cách trực quan nhất về hiện tượng nhật thực với vị trí quan sát của chúng ta là đang đứng ở Trái Đất.

HTML code

Phần code HTML chỉ cần 3 thẻ div đơn giản như bên dưới. Thẻ div class="universe" bao ngoài dùng để mô tả bầu trời, div class="sun" ta dùng để mô tả Mặt Trời và div class="moon" để mô tả Mặt Trăng.

<div class="universe">
<div class="sun"></div>
  <div class="moon"></div>
</div>

CSS code

Reset một số thuộc tính mặc định của HTML

html, body {
  width: 100%;
  overflow-x: hidden;
}
*, *:before, *:after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

Đầu tiên là mô tả bầu trời cùng những vì sao

.universe {
  width:100vw;
  height: 100vh;
  background: #fff;
  display: block;
  position: relative;
  animation: skyDim 20s linear infinite;
}

@keyframes skyDim {
  0%, 100% {
    background: #fff;
  }
  50% {
    background: #000;
  }
}

.universe:before {
    content: "";
    box-shadow: 
      10vw 1vh #fff,
      14vw 29vh 2px #FFF,
      23vw 34vh 1px #FFF,
      1vw 99vh 1px #FFF,
      20vw 80vh #FFF,
      90vw 10vh 2px #fff,
      55vw 9vh #FFF,
      24vw 4vh 1px #FFF,
      50vw 99vh 1px #FFF,
      74vw 40vh 1px #FFF,
      80vw 9vh 1px #FFF,
      20vw 80vh #FFF,
      85vw 78vh #fff;
    width: 4px;
    height: 4px;
    position: absolute;
    border-radius: 50%;
}

.universe:after {
    content: "";
    box-shadow: 
      37vw 78vh #fff,
      17vw 69vh #FFF,
      68vw 4vh 1px #FFF,
      98vw 9vh 1px #FFF,
      45vw 67vh #FFF,
      95vw 1vh 2px #fff,
      35vw 75vh 2px #FFF,
      44vw 47vh 1px #FFF,
      54vw 5vh 1px #FFF,
      22vw 29vh 1px #FFF,
      39vw 71vh 1px #FFF,
      11vw 11vh #FFF,
      88vw 82vh #fff;
    width: 2px;
    height: 2px;
    position: absolute;
    border-radius: 50%;
}

Trong đoạn CSS trên ta thấy class universebackground: #fff tượng trưng cho ban ngày lúc Mặt Trời chưa bị Mặt Trăng che khuất, để mô phỏng hiện tượng khi bị Mặt Trăng che khuất bầu trời sẽ tối dần đi ta thêm 1 animation cho class universeanimation: skyDim 20s linear infinite;, ta gọi keyframes là skyDim tương ứng với thời gian thay đổi trạng thái của bầu trời là 20s, thuộc tính linear mô tả trạng thái chuyển động nhanh-chậm-nhanhinfinite để quá trình này lặp lại liên tục. À, còn các đoạn CSS :before:after đó là mình dùng để mô phỏng các vì sao khác trên bầu trời cho thêm phần sinh động, có hay không cũng không sao nhé các bạn 😄 Tiếp theo ta sẽ vẽ Mặt Trời Ta có đoạn CSS sau:

.sun {
    height: 200px;
    width: 200px;
    border-radius: 50%;
    background: #ffd700;
    box-shadow: 0 0 60px #ffd700, 0 0 100px #b9a018, inset 0 5px 35px 53px #ffd700, inset 48px 8px 34px 25px #ffd700;
    left: calc(50% - 100px);
    top: calc(50% - 100px);
    position: absolute;
    animation: sunFreakOut 20s linear infinite;
}

@keyframes sunFreakOut {
  0%, 100% {
    box-shadow: 0 0 60px gold, 0 0 100px #b9a018, inset 0 5px 35px 53px #ffd700, inset 48px 8px 34px 25px #ffd700;
  }
  50% {
    box-shadow: 0 0 50px #e30000, 0 0 0px #b91818, inset 0 5px 35px 53px #ffd700, inset 48px 8px 34px 25px #ffd700;
  }
}

Tương tự như phía trên mô phỏng độ sáng tối của bầu trời, khi Mặt Trăng che khuất Mặt Trời ta sẽ thấy viền mặt trời chuyển dần sang màu đỏ sẫm. Với trạng thái của Mặt Trời ta có keyframes sunFreakOut, thời gian tương ứng cũng là 20s. Cuối cùng, phần quan trọng nhất là chuyển động của Mặt Trăng Ta có đoạn CSS sau đây

.moon {
    height: 50px;
    width: 50px;
    border-radius: 50%;
    background: rgba(0, 0, 0, 0.99);
    box-shadow: inset 5px 1px 10px -8px #d4d4d6;
    transition: 1s;
    top: calc(40% - 100px);
    position: absolute;
    z-index: 5;
    animation: Move 20s ease-in-out infinite;
}

@keyframes Move {
  0% {transform: translateX(100vw);}
  40%, 60% {
    top: calc(50% - 100px);
  }
  50%, 50.5% { 
    width: 200px;
    height: 200px;
    transform: translateX(calc(50vw - 100px));
    box-shadow: inset 20px 1px 35px -15px #d4d4d6;
    top: calc(50% - 100px);
  }
  60% {
    box-shadow: inset -20px 1px 35px -15px #d4d4d6;      
  }
  80% {
  }
  100% {
    width: 50px;
    height: 50px;
    transform: translateX(calc(-1vw - 60px));
    top: calc(40% - 100px);
    box-shadow: inset -5px 1px 10px -8px #d4d4d6;      
    
  }
}

Tương ứng với thời gian chuyển động 20s và hiệu ứng chuyển động của Mặt Trăng ta có keyframes Move. Khi Mặt Trăng di chuyển từ phải sang trái ta có các thuộc tính box-shadow tương ứng để mô phỏng ánh sáng của Mặt Trời chiếu vào các mặt của Mặt Trăng. Dưới đây là toàn bộ source của bài viết trên Codepen của mình

Như vậy là chúng ta đã hoàn thành 1 ứng dụng mô phỏng hiện tượng nhật thực toàn phần bằng HTML5 và CSS3. Tuy nó chưa thể mô tả hoàn toàn chính xác 100% hiện tượng nhật thực toàn phần nhưng mình hy vọng sẽ đem đến cho mọi người cái nhìn trực quan nhất có thể về hiện tượng này. Cảm ơn các bạn đã xem bài viết, hẹn gặp lại các bạn trong những bài viết sau.