개요
CSS와 JS를 사용해 다음과 같이 점성이 있는 느낌의 요소(전문용어로 메타볼)를 만들어 보겠습니다.

구현
1. 방법
만드는 방법은 생각보다 쉽습니다. 바로 CSS의 blur와 contrast를 사용하면 됩니다.
두 가지 모두 css의 filter 속성에서 설정할 수 있는데 기능은 다음과 같습니다.
- blur : 적용된 요소에 가우시안 블러 효과를 적용합니다. 픽셀로 조절하며 값이 클수록 요소가 더 흐려집니다.
- contrast : 적용된 요소에 대비를 증가시키거나 감소시킵니다. 값이 클수록 대비가 증가하며 이 효과는 요소의 이미지나 텍스트를 더 선명하게 만들거나 시각적으로 두드러지게 만들 때 사용됩니다.
위 두가지 기능을 이용해 blur로 물체를 흐리게 만든 후 contrast를 사용해 흐려진 부분까지 모두 선명하게 표시하는 것입니다.
2. HTML 생성
큰 배경과 그 안에 메타볼 2개를 만들기 위해 HTML은 다음과 같이 설정해 주세요.
<div id="background">
<div class="metaball first"></div>
<div class="metaball second"></div>
</div>
3. 배경과 메타볼 CSS
화면을 가득 채우는 background를 설정해 주고 그 안에 들어갈 메타볼의 크기와 위치를 설정해 주겠습니다.
메타볼은 효과가 잘 나타나는지 확인할 수 있도록 2개의 div를 바로 옆에 배치해 줬습니다.
body {
margin: 0;
}
#background {
width: 100%;
height: 100vh;
background-color: #155861;
}
.metaball {
background: yellow;
position: absolute;
width: 80px;
height: 80px;
border-radius: 50%;
}
.first {
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.second { /* JS코드 추가 후 제거 */
top: 50%;
left: calc(50% + 80px);
transform: translate(-50%, -50%);
}

4. blur 효과
메타볼에 blur 효과를 넣어주겠습니다.
blur를 키우면 키울수록 메타볼의 점성이 커집니다.
저는 12px 만 적용해 주겠습니다.
.metaball {
background: yellow;
position: absolute;
width: 80px;
height: 80px;
border-radius: 50%;
filter: blur(12px); /* 추가됨 */
}

4. contrast 효과
이제 배경에 contrast 효과를 넣어주게 되면 뿌옇게 흐려져 연하게 나타나는 노란색마저 선명한 노란색으로 바꿔주면서 메타볼 느낌이 나게 됩니다.
#background {
width: 100%;
height: 100vh;
filter: contrast(20); /* 추가됨 */
background-color: #155861;
}

5. 마우스 트래커 추가
마지막으로 CSS에서. second의 위치 값을 제거해 주고
JS에서 마우스의 좌표를 가져와 동적으로 이동시켜 주는 다음 코드를 추가하게 되면?
// 메타볼 반지름
const metaballRadius = 40;
// 마우스 이동 이벤트
document.addEventListener('mousemove', function(e) {
var secondMetaball = document.querySelector('.second');
secondMetaball.style.left = e.pageX - metaballRadius + 'px';
secondMetaball.style.top = e.pageY - metaballRadius + 'px';
});
바로 처음에 보셨던 마우스에 반응하는 메타볼이 완성됩니다!!.

전체 코드
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>metaball</title>
<style>
body {
margin: 0;
}
#background {
width: 100%;
height: 100vh;
filter: contrast(20);
background-color: #155861;
}
.metaball {
background: yellow;
position: absolute;
width: 80px;
height: 80px;
border-radius: 50%;
filter: blur(12px);
}
.first {
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
</style>
</head>
<body>
<div id="background">
<div class="metaball first"></div>
<div class="metaball second"></div>
</div>
<script>
const metaballRadius = 40;
document.addEventListener('mousemove', function(e) {
var secondMetaball = document.querySelector('.second');
secondMetaball.style.left = e.pageX - metaballRadius + 'px';
secondMetaball.style.top = e.pageY - metaballRadius + 'px';
});
</script>
</body>
</html>