这是github链接,文末也有本人封装好的融球效果+讲解页面完整代码:
sq/UI/src/components/MetaballEffect at main · afigzb/sq (github.com)https://github.com/afigzb/sq/tree/main/UI/src/components/MetaballEffect讲解部分看这个静态页面截图即可:
融球组件代码:
/**
* 融球效果 Web Component
* 为容器内的元素提供融球效果,支持任意HTML内容
*/
class MetaballContainer extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
this.blurIntensity = 10;
this.contrastLevel = 20;
this.init();
}
init() {
this.shadowRoot.innerHTML = `
<style>
:host {
display: block;
position: relative;
/* 核心:高对比度滤镜实现融球效果 */
filter: contrast(${this.contrastLevel}) blur(0.5px);
background: inherit;
}
::slotted(*) {
/* 核心:为所有插槽内容添加模糊效果 */
filter: blur(${this.blurIntensity}px) !important;
}
.container {
width: 100%;
height: 100%;
position: relative;
}
</style>
<div class="container">
<slot></slot>
</div>
`;
}
/**
* 设置模糊强度
* @param {number} intensity - 模糊强度 (2-15)
*/
setBlur(intensity) {
this.blurIntensity = intensity;
this.updateStyles();
}
/**
* 设置对比度
* @param {number} level - 对比度级别 (10-40)
*/
setContrast(level) {
this.contrastLevel = level;
this.updateStyles();
}
/**
* 更新样式
* @private
*/
updateStyles() {
const style = this.shadowRoot.querySelector('style');
style.textContent = `
:host {
display: block;
position: relative;
filter: contrast(${this.contrastLevel}) blur(0.5px);
background: inherit;
}
::slotted(*) {
filter: blur(${this.blurIntensity}px) !important;
}
.container {
width: 100%;
height: 100%;
position: relative;
}
`;
}
/**
* 获取所有子元素
* @returns {Array} 子元素数组
*/
getItems() {
return Array.from(this.children);
}
/**
* 获取当前模糊强度
* @returns {number} 当前模糊强度
*/
getBlur() {
return this.blurIntensity;
}
/**
* 获取当前对比度
* @returns {number} 当前对比度
*/
getContrast() {
return this.contrastLevel;
}
}
// 注册Web Component
customElements.define('metaball-container', MetaballContainer);
// 导出组件
export default MetaballContainer;
融球组件示例页面代码:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>融球控件 - Web Component</title>
<style>
body {
margin: 0;
padding: 20px;
background: #1a1a1a;
font-family: Arial, sans-serif;
color: white;
}
.demo-container {
position: relative;
width: 100vw;
height: 80vh;
background: #000;
border-radius: 10px;
overflow: hidden;
}
.demo-item {
position: absolute;
transition: all 0.1s ease;
}
.ball {
width: 80px;
height: 80px;
border-radius: 50%;
background: #ff6b6b;
}
.square {
width: 60px;
height: 60px;
background: #4ecdc4;
}
.triangle {
width: 0;
height: 0;
border-left: 30px solid transparent;
border-right: 30px solid transparent;
border-bottom: 52px solid #ffe66d;
}
.text-item {
font-size: 24px;
font-weight: bold;
color: #a8e6cf;
padding: 10px 20px;
background: #a8e6cf;
border-radius: 20px;
}
.controls {
margin-bottom: 20px;
display: flex;
gap: 10px;
align-items: center;
}
button {
padding: 8px 16px;
background: #4ecdc4;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
}
button:hover {
background: #45b7aa;
}
.info {
margin-bottom: 20px;
padding: 15px;
background: rgba(255, 255, 255, 0.1);
border-radius: 8px;
}
</style>
</head>
<body>
<div class="info">
<h2>融球控件 (Metaball Component)</h2>
<p>这是一个Web Component封装的融球控件,可以为任何插入的元素提供融球效果。</p>
<p>控件只负责融球效果,元素的移动由外部控制。</p>
</div>
<div class="controls">
<button onclick="toggleAnimation()">开始/停止动画</button>
<button onclick="resetPositions()">重置位置</button>
<label>
模糊强度:
<input type="range" id="blurSlider" min="2" max="15" value="8"
onchange="updateBlur(this.value)">
<span id="blurValue">8</span>px
</label>
<label>
对比度:
<input type="range" id="contrastSlider" min="10" max="40" value="20"
onchange="updateContrast(this.value)">
<span id="contrastValue">20</span>
</label>
</div>
<!-- 使用融球控件 -->
<metaball-container class="demo-container">
<div class="demo-item ball" style="left: 100px; top: 100px;"></div>
<div class="demo-item square" style="left: 300px; top: 200px;"></div>
<div class="demo-item triangle" style="left: 500px; top: 150px;"></div>
<div class="demo-item text-item" style="left: 200px; top: 300px;">TEXT</div>
</metaball-container>
<script type="module">
// 导入融球控件
import MetaballContainer from './MetaballEffect.js';
// 演示动画控制
let animationId = null;
let isAnimating = false;
const items = [];
// 初始化演示项目
function initDemo() {
const container = document.querySelector('metaball-container');
const demoItems = container.querySelectorAll('.demo-item');
demoItems.forEach((item, index) => {
const rect = item.getBoundingClientRect();
const containerRect = container.getBoundingClientRect();
items.push({
element: item,
x: parseFloat(item.style.left) || 0,
y: parseFloat(item.style.top) || 0,
vx: (Math.random() - 0.5) * 2,
vy: (Math.random() - 0.5) * 2,
width: item.offsetWidth,
height: item.offsetHeight
});
});
}
// 动画循环
function animate() {
if (!isAnimating) return;
const container = document.querySelector('metaball-container');
const containerRect = container.getBoundingClientRect();
items.forEach(item => {
// 更新位置
item.x += item.vx;
item.y += item.vy;
// 边界检测
if (item.x <= 0 || item.x >= containerRect.width - item.width) {
item.vx *= -1;
item.x = Math.max(0, Math.min(containerRect.width - item.width, item.x));
}
if (item.y <= 0 || item.y >= containerRect.height - item.height) {
item.vy *= -1;
item.y = Math.max(0, Math.min(containerRect.height - item.height, item.y));
}
// 应用位置
item.element.style.left = `${item.x}px`;
item.element.style.top = `${item.y}px`;
});
animationId = requestAnimationFrame(animate);
}
// 控制函数
window.toggleAnimation = function() {
isAnimating = !isAnimating;
if (isAnimating) {
animate();
} else {
cancelAnimationFrame(animationId);
}
};
window.resetPositions = function() {
items.forEach(item => {
item.x = Math.random() * 400;
item.y = Math.random() * 300;
item.vx = (Math.random() - 0.5) * 2;
item.vy = (Math.random() - 0.5) * 2;
item.element.style.left = `${item.x}px`;
item.element.style.top = `${item.y}px`;
});
};
window.updateBlur = function(value) {
const container = document.querySelector('metaball-container');
container.setBlur(value);
document.getElementById('blurValue').textContent = value;
};
window.updateContrast = function(value) {
const container = document.querySelector('metaball-container');
container.setContrast(value);
document.getElementById('contrastValue').textContent = value;
};
// 初始化
document.addEventListener('DOMContentLoaded', () => {
// 等待Web Component注册完成
setTimeout(() => {
initDemo();
}, 100);
});
// 鼠标交互演示
document.addEventListener('mousemove', (e) => {
if (!isAnimating) return;
const container = document.querySelector('metaball-container');
const rect = container.getBoundingClientRect();
const mouseX = e.clientX - rect.left;
const mouseY = e.clientY - rect.top;
// 鼠标吸引效果
items.forEach(item => {
const dx = mouseX - (item.x + item.width / 2);
const dy = mouseY - (item.y + item.height / 2);
const distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 150) {
const force = (150 - distance) / 150 * 0.01;
item.vx += dx / distance * force;
item.vy += dy / distance * force;
}
});
});
</script>
</body>
</html>
这是文首的讲解页面代码:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>融球效果原理讲解</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
line-height: 1.6;
color: #333;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
padding: 20px;
}
.container {
max-width: 1200px;
margin: 0 auto;
background: white;
border-radius: 20px;
box-shadow: 0 20px 40px rgba(0,0,0,0.1);
overflow: hidden;
}
.header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 40px;
text-align: center;
}
.header h1 {
font-size: 2.5em;
margin-bottom: 10px;
}
.header p {
font-size: 1.2em;
opacity: 0.9;
}
.content {
padding: 40px;
}
.section {
margin-bottom: 50px;
}
.section h2 {
color: #667eea;
font-size: 1.8em;
margin-bottom: 20px;
border-bottom: 3px solid #667eea;
padding-bottom: 10px;
}
.demo-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 30px;
margin: 30px 0;
}
.demo-box {
background: #f8f9fa;
border-radius: 15px;
padding: 20px;
border: 2px solid #e9ecef;
transition: all 0.3s ease;
}
.demo-box:hover {
transform: translateY(-5px);
box-shadow: 0 10px 25px rgba(0,0,0,0.1);
}
.demo-box h3 {
color: #495057;
margin-bottom: 15px;
font-size: 1.3em;
}
.demo-area {
width: 100%;
height: 200px;
background: #000;
border-radius: 10px;
position: relative;
overflow: hidden;
margin: 15px 0;
}
.ball {
position: absolute;
width: 60px;
height: 60px;
background: #fff;
border-radius: 50%;
}
.ball-1 { left: 50px; top: 70px; }
.ball-2 { left: 100px; top: 70px; }
/* 四种状态演示 */
.state-1 .demo-area {
/* 无模糊,无对比度 */
}
.state-2 .demo-area {
/* 只有模糊,无对比度 */
}
.state-2 .ball {
filter: blur(10px);
}
.state-3 .demo-area {
/* 无模糊,只有对比度 */
filter: contrast(20);
}
.state-4 .demo-area {
/* 融球效果:容器对比度 + 元素模糊 */
filter: contrast(20) blur(0.5px);
}
.state-4 .ball {
filter: blur(10px);
}
.interactive-demo {
background: #f8f9fa;
border-radius: 15px;
padding: 30px;
margin: 30px 0;
}
.controls {
display: flex;
flex-wrap: wrap;
gap: 20px;
margin-bottom: 20px;
align-items: center;
}
.control-group {
display: flex;
flex-direction: column;
gap: 5px;
}
.control-group label {
font-weight: 600;
color: #495057;
}
.control-group input[type="range"] {
width: 200px;
height: 6px;
border-radius: 3px;
background: #ddd;
outline: none;
-webkit-appearance: none;
}
.control-group input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 20px;
height: 20px;
border-radius: 50%;
background: #667eea;
cursor: pointer;
}
.value-display {
font-weight: bold;
color: #667eea;
}
.interactive-area {
width: 100%;
height: 300px;
background: #000;
border-radius: 10px;
position: relative;
overflow: hidden;
}
.movable-ball {
position: absolute;
width: 80px;
height: 80px;
background: #fff;
border-radius: 50%;
transition: all 0.1s ease;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
color: #333;
}
.ball-a { left: 100px; top: 110px; background: #ff6b6b; }
.ball-b { left: 200px; top: 110px; background: #4ecdc4; }
.explanation {
background: #e3f2fd;
border-left: 4px solid #2196f3;
padding: 20px;
margin: 20px 0;
border-radius: 0 10px 10px 0;
}
.explanation h4 {
color: #1976d2;
margin-bottom: 10px;
}
.code-block {
background: #2d3748;
color: #e2e8f0;
padding: 20px;
border-radius: 10px;
font-family: 'Courier New', monospace;
margin: 20px 0;
overflow-x: auto;
font-size: 14px;
line-height: 1.5;
}
.code-block .comment {
color: #68d391;
}
.code-block .property {
color: #63b3ed;
}
.code-block .value {
color: #fbb6ce;
}
.highlight {
background: #ffd54f;
padding: 2px 4px;
border-radius: 3px;
color: #333;
}
.principle-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 20px;
margin: 30px 0;
}
.principle-card {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 25px;
border-radius: 15px;
text-align: center;
}
.principle-card h4 {
font-size: 1.3em;
margin-bottom: 15px;
}
.principle-card .icon {
font-size: 3em;
margin-bottom: 15px;
opacity: 0.8;
}
.warning {
background: #fff3cd;
border: 1px solid #ffeaa7;
border-radius: 8px;
padding: 15px;
margin: 20px 0;
color: #856404;
}
.warning strong {
color: #d63031;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>🌊 融球效果原理讲解</h1>
<p>深入理解容器对比度 + 元素模糊如何创造神奇的融球效果</p>
</div>
<div class="content">
<!-- 原理概述 -->
<div class="section">
<h2>🎯 核心原理</h2>
<p>融球效果(Metaball Effect)的实现原理是:<span class="highlight">容器应用高对比度滤镜</span> + <span class="highlight">元素应用模糊滤镜</span>。当模糊的元素靠近时,它们的边缘会在高对比度的作用下自然融合。</p>
<div class="warning">
<strong>重要:</strong>很多人误以为是同时对元素应用模糊和对比度,实际上正确的做法是分层应用 - 容器负责对比度,元素负责模糊!
</div>
<div class="principle-grid">
<div class="principle-card">
<div class="icon">📦</div>
<h4>容器对比度</h4>
<p>容器应用高对比度滤镜,将灰色区域转换为黑白分明的边界</p>
</div>
<div class="principle-card">
<div class="icon">🌫️</div>
<h4>元素模糊</h4>
<p>每个元素应用模糊滤镜,创造柔和的渐变边缘</p>
</div>
<div class="principle-card">
<div class="icon">🔗</div>
<h4>融合效果</h4>
<p>模糊元素的重叠区域经过容器对比度处理后形成连接</p>
</div>
</div>
</div>
<!-- 四种状态对比 -->
<div class="section">
<h2>📚 四种状态对比演示</h2>
<p>让我们通过四种不同的状态来理解融球效果的形成过程:</p>
<div class="demo-grid">
<div class="demo-box state-1">
<h3>状态 1: 无模糊 + 无对比度</h3>
<div class="demo-area">
<div class="ball ball-1"></div>
<div class="ball ball-2"></div>
</div>
<div class="code-block">
<span class="comment">/* 容器 */</span>
.<span class="property">container</span> {
<span class="comment">/* 无滤镜 */</span>
}
<span class="comment">/* 元素 */</span>
.<span class="property">ball</span> {
<span class="comment">/* 无滤镜 */</span>
}
</div>
<p>两个清晰的圆球,边界分明,无任何效果。</p>
</div>
<div class="demo-box state-2">
<h3>状态 2: 有模糊 + 无对比度</h3>
<div class="demo-area">
<div class="ball ball-1"></div>
<div class="ball ball-2"></div>
</div>
<div class="code-block">
<span class="comment">/* 容器 */</span>
.<span class="property">container</span> {
<span class="comment">/* 无滤镜 */</span>
}
<span class="comment">/* 元素 */</span>
.<span class="property">ball</span> {
<span class="property">filter</span>: <span class="value">blur(10px)</span>;
}
</div>
<p>球体变模糊,但没有融合效果,只是单纯的模糊。</p>
</div>
<div class="demo-box state-3">
<h3>状态 3: 无模糊 + 有对比度</h3>
<div class="demo-area">
<div class="ball ball-1"></div>
<div class="ball ball-2"></div>
</div>
<div class="code-block">
<span class="comment">/* 容器 */</span>
.<span class="property">container</span> {
<span class="property">filter</span>: <span class="value">contrast(20)</span>;
}
<span class="comment">/* 元素 */</span>
.<span class="property">ball</span> {
<span class="comment">/* 无滤镜 */</span>
}
</div>
<p>边界更加锐利,但仍然没有融合效果。</p>
</div>
<div class="demo-box state-4">
<h3>状态 4: 有模糊 + 有对比度</h3>
<div class="demo-area">
<div class="ball ball-1"></div>
<div class="ball ball-2"></div>
</div>
<div class="code-block">
<span class="comment">/* 容器 */</span>
.<span class="property">container</span> {
<span class="property">filter</span>: <span class="value">contrast(20) blur(0.5px)</span>;
}
<span class="comment">/* 元素 */</span>
.<span class="property">ball</span> {
<span class="property">filter</span>: <span class="value">blur(10px)</span>;
}
</div>
<p>🎉 完美的融球效果!模糊的边缘在高对比度下形成自然连接。</p>
</div>
</div>
</div>
<!-- 技术原理详解 -->
<div class="section">
<h2>🔬 技术原理详解</h2>
<!-- 基础概念讲解 -->
<div class="section">
<h3>📖 基础概念:什么是模糊和对比度?</h3>
<div class="explanation">
<h4>🌫️ 什么是"模糊"?</h4>
<p>想象一下你摘掉眼镜看东西,或者相机没有对焦时的效果 - 这就是模糊。在计算机图形学中,模糊就是让图像的边缘变得不清晰,从锐利的边界变成柔和的过渡。</p>
</div>
<div class="demo-grid">
<div class="demo-box">
<h4>模糊效果对比</h4>
<div style="display: flex; gap: 15px; align-items: center; margin: 15px 0;">
<div style="width: 50px; height: 50px; background: #ff6b6b; border-radius: 50%;"></div>
<span>→</span>
<div style="width: 50px; height: 50px; background: #ff6b6b; border-radius: 50%; filter: blur(3px);"></div>
</div>
<p style="text-align: center; color: #666;">清晰的圆 → 模糊的圆</p>
<p><strong>看到了吗?</strong>右边的圆边缘变得柔和了,不再是硬邦邦的边界。</p>
</div>
<div class="demo-box">
<h4>Web开发中的模糊应用</h4>
<ul style="margin-left: 20px;">
<li>🖼️ 图片背景虚化效果</li>
<li>🎭 遮罩层后的内容模糊</li>
<li>🔍 搜索结果的渐进加载</li>
<li>🎨 毛玻璃效果 (backdrop-filter)</li>
<li>💫 悬停时的焦点突出</li>
</ul>
<p><strong>共同点:</strong>都是通过模糊来创造视觉层次和焦点!</p>
</div>
</div>
<div class="explanation">
<h4>⚡ 什么是"对比度"?</h4>
<p>对比度就是黑白之间的差别程度。高对比度意味着黑的更黑,白的更白,中间的灰色会被"推向"黑色或白色。就像调节电视机的对比度旋钮一样。</p>
</div>
<div class="demo-grid">
<div class="demo-box">
<h4>对比度效果对比</h4>
<div style="background: linear-gradient(to right, #000, #333, #666, #999, #ccc, #fff); height: 40px; margin: 10px 0; border-radius: 5px; position: relative;">
<span style="position: absolute; left: 5px; top: 10px; color: white; font-size: 12px; font-weight: bold;">正常对比度</span>
</div>
<div style="background: linear-gradient(to right, #000, #333, #666, #999, #ccc, #fff); height: 40px; margin: 10px 0; border-radius: 5px; filter: contrast(5); position: relative;">
<span style="position: absolute; left: 5px; top: 10px; color: white; font-size: 12px; font-weight: bold;">高对比度</span>
</div>
<p><strong>看到了吗?</strong>下面的渐变中,灰色部分变少了,更多的是纯黑和纯白。</p>
</div>
<div class="demo-box">
<h4>Web开发中的对比度应用</h4>
<ul style="margin-left: 20px;">
<li>🎨 主题切换中的色彩增强</li>
<li>🖼️ 图像处理和滤镜效果</li>
<li>📱 无障碍设计的可读性提升</li>
<li>🎭 蒙版效果的边缘锐化</li>
<li>🔲 SVG图标的清晰度优化</li>
</ul>
<p><strong>共同点:</strong>都是通过对比度来增强视觉效果的清晰度!</p>
</div>
</div>
</div>
<!-- CSS中的模糊和对比度 -->
<div class="section">
<h3>💻 CSS中如何实现模糊和对比度?</h3>
<div class="explanation">
<h4>CSS滤镜 (filter) 是什么?</h4>
<p>CSS滤镜就像给图片加特效的工具,就像美图软件里的滤镜一样。我们可以用它来让元素变模糊、调整对比度等。</p>
</div>
<div class="code-block">
<span class="comment">/* 基础语法 - 就像给元素"戴眼镜" */</span>
.<span class="property">my-element</span> {
<span class="property">filter</span>: <span class="value">blur(5px)</span>; <span class="comment">/* 让元素变模糊 */</span>
<span class="property">filter</span>: <span class="value">contrast(2)</span>; <span class="comment">/* 增加对比度 */</span>
<span class="property">filter</span>: <span class="value">blur(5px) contrast(2)</span>; <span class="comment">/* 同时应用多个效果 */</span>
}
</div>
<div class="demo-grid">
<div class="demo-box">
<h4>模糊值的含义</h4>
<div class="code-block">
<span class="comment">/* 数字越大,越模糊 */</span>
<span class="property">filter</span>: <span class="value">blur(0px)</span>; <span class="comment">/* 不模糊 */</span>
<span class="property">filter</span>: <span class="value">blur(3px)</span>; <span class="comment">/* 轻微模糊 */</span>
<span class="property">filter</span>: <span class="value">blur(10px)</span>; <span class="comment">/* 很模糊 */</span>
<span class="property">filter</span>: <span class="value">blur(20px)</span>; <span class="comment">/* 非常模糊 */</span>
</div>
<p><strong>记住:</strong>数字越大,越看不清!</p>
</div>
<div class="demo-box">
<h4>对比度值的含义</h4>
<div class="code-block">
<span class="comment">/* 数字越大,黑白越分明 */</span>
<span class="property">filter</span>: <span class="value">contrast(1)</span>; <span class="comment">/* 正常 */</span>
<span class="property">filter</span>: <span class="value">contrast(2)</span>; <span class="comment">/* 增强一点 */</span>
<span class="property">filter</span>: <span class="value">contrast(10)</span>; <span class="comment">/* 很强 */</span>
<span class="property">filter</span>: <span class="value">contrast(20)</span>; <span class="comment">/* 非常强 */</span>
</div>
<p><strong>记住:</strong>数字越大,黑白越分明!</p>
</div>
</div>
</div>
<!-- 融球效果中的应用 -->
<div class="section">
<h3>🎯 它们在融球效果中的神奇作用</h3>
<div class="explanation">
<h4>为什么模糊+对比度能产生融球效果?</h4>
<p>这就像一个魔术!让我们一步步揭秘:</p>
</div>
<div class="demo-grid">
<div class="demo-box">
<h4>第一步:模糊创造"过渡地带"</h4>
<div style="display: flex; gap: 10px; align-items: center; margin: 15px 0;">
<div style="width: 40px; height: 40px; background: #fff; border: 2px solid #333; border-radius: 50%;"></div>
<span>+</span>
<div style="width: 40px; height: 40px; background: #fff; border: 2px solid #333; border-radius: 50%;"></div>
<span>=</span>
<span>两个分离的圆</span>
</div>
<div style="display: flex; gap: 10px; align-items: center; margin: 15px 0; background: #333; padding: 10px; border-radius: 5px;">
<div style="width: 40px; height: 40px; background: #fff; border-radius: 50%; filter: blur(5px);"></div>
<span style="color: #fff;">+</span>
<div style="width: 40px; height: 40px; background: #fff; border-radius: 50%; filter: blur(5px);"></div>
<span style="color: #fff;">=</span>
<span style="color: #fff;">边缘变柔和了</span>
</div>
<p><strong>关键:</strong>模糊让硬边界变成了柔和的"过渡地带"</p>
</div>
<div class="demo-box">
<h4>第二步:对比度"决定"黑白</h4>
<p>当两个模糊的圆靠近时,它们的"过渡地带"会重叠,产生灰色区域。</p>
<p><strong>这时对比度出场了!</strong></p>
<ul style="margin-left: 20px; margin-top: 10px;">
<li>🔍 对比度说:"灰色?不行!"</li>
<li>⚫ "要么变成黑色(背景)"</li>
<li>⚪ "要么变成白色(连接)"</li>
<li>🎉 结果:两个圆"融合"了!</li>
</ul>
</div>
</div>
<div class="explanation">
<h4>具体在代码中是怎么做的?</h4>
<p>我们需要分工合作:</p>
</div>
<div class="code-block">
<span class="comment">/* 容器负责"决定黑白" */</span>
.<span class="property">container</span> {
<span class="property">filter</span>: <span class="value">contrast(20)</span>; <span class="comment">/* 我来决定什么是黑,什么是白! */</span>
}
<span class="comment">/* 元素负责"变模糊" */</span>
.<span class="property">ball</span> {
<span class="property">filter</span>: <span class="value">blur(10px)</span>; <span class="comment">/* 我来创造柔和的边缘! */</span>
}
<span class="comment">/* 结果:当模糊的球靠近时,重叠的灰色区域被对比度"判决"为白色连接! */</span>
</div>
</div>
<div class="explanation">
<h4>总结:融球效果的"魔法公式"</h4>
<p><strong>模糊</strong>(创造柔和边缘)+ <strong>对比度</strong>(决定黑白)= <strong>融球效果</strong>(液体般的融合)</p>
<p>关键在于分层应用:容器负责对比度处理,元素负责模糊效果,两者协同工作创造出自然的融合效果。</p>
</div>
</div>
<!-- 交互式演示 -->
<div class="section">
<h2>🎮 交互式演示</h2>
<p>观看下面的自动演示,体验融球效果的形成过程:</p>
<div class="interactive-demo">
<div class="controls">
<div class="control-group">
<label>元素模糊强度: <span class="value-display" id="blurValue">10</span>px</label>
<input type="range" id="blurSlider" min="0" max="20" value="10">
</div>
<div class="control-group">
<label>容器对比度: <span class="value-display" id="contrastValue">20</span></label>
<input type="range" id="contrastSlider" min="1" max="50" value="20">
</div>
<div class="control-group">
<label>容器额外模糊: <span class="value-display" id="containerBlurValue">0.5</span>px</label>
<input type="range" id="containerBlurSlider" min="0" max="3" step="0.1" value="0.5">
</div>
</div>
<div class="interactive-area" id="interactiveArea">
<div class="movable-ball ball-a" id="ballA">A</div>
<div class="movable-ball ball-b" id="ballB">B</div>
</div>
<p style="margin-top: 15px; color: #666;">
💡 <strong>提示:</strong>调整上方的参数,观察球体的自动运动和融合效果。试试将模糊或对比度调到0,看看会发生什么!
</p>
</div>
</div>
<!-- 实际应用 -->
<div class="section">
<h2>🚀 实际应用场景</h2>
<div class="demo-grid">
<div class="demo-box">
<h3>🎨 UI设计</h3>
<p>流体按钮、动态加载指示器、有机形状的界面元素</p>
</div>
<div class="demo-box">
<h3>🎮 游戏开发</h3>
<p>液体物理效果、粒子系统、动态地形变化</p>
</div>
<div class="demo-box">
<h3>📱 移动应用</h3>
<p>手势反馈效果、动态图标、流体导航</p>
</div>
<div class="demo-box">
<h3>🎬 动画制作</h3>
<p>角色变形、液体模拟、有机过渡效果</p>
</div>
</div>
</div>
<!-- 总结 -->
<div class="section">
<h2>📝 总结</h2>
<div class="explanation">
<h4>融球效果的关键要素:</h4>
<ul style="margin-left: 20px; margin-top: 10px;">
<li><strong>分层应用</strong>:容器应用对比度,元素应用模糊</li>
<li><strong>元素模糊</strong>:为形状创建柔和的边缘渐变</li>
<li><strong>容器对比度</strong>:将重叠的渐变区域转换为清晰的连接</li>
<li><strong>参数平衡</strong>:模糊强度和对比度需要合理搭配</li>
<li><strong>Web Component封装</strong>:使用Shadow DOM实现样式隔离和复用</li>
</ul>
</div>
<p>理解了这个分层滤镜的原理,你就掌握了融球效果的精髓。通过Web Component的封装,可以轻松地在任何项目中应用这种效果,创造出令人印象深刻的用户体验!</p>
</div>
</div>
</div>
<script type="module">
// 导入融球控件(模拟导入,实际使用时需要正确的路径)
// import MetaballContainer from './MetaballEffect.js';
// 交互式演示控制
const interactiveArea = document.getElementById('interactiveArea');
const blurSlider = document.getElementById('blurSlider');
const contrastSlider = document.getElementById('contrastSlider');
const containerBlurSlider = document.getElementById('containerBlurSlider');
const blurValue = document.getElementById('blurValue');
const contrastValue = document.getElementById('contrastValue');
const containerBlurValue = document.getElementById('containerBlurValue');
// 更新滤镜效果
function updateFilters() {
const blur = blurSlider.value;
const contrast = contrastSlider.value;
const containerBlur = containerBlurSlider.value;
// 更新显示值
blurValue.textContent = blur;
contrastValue.textContent = contrast;
containerBlurValue.textContent = containerBlur;
// 应用滤镜(按照正确的融球原理)
interactiveArea.style.filter = `contrast(${contrast}) blur(${containerBlur}px)`;
const balls = interactiveArea.querySelectorAll('.movable-ball');
balls.forEach(ball => {
ball.style.filter = `blur(${blur}px)`;
});
}
// 绑定滑块事件
blurSlider.addEventListener('input', updateFilters);
contrastSlider.addEventListener('input', updateFilters);
containerBlurSlider.addEventListener('input', updateFilters);
// 初始化
updateFilters();
// 自动演示动画
function autoDemo() {
const ballA = document.getElementById('ballA');
const ballB = document.getElementById('ballB');
let time = 0;
function animate() {
time += 0.02;
const centerX = interactiveArea.offsetWidth / 2 - 40;
const centerY = interactiveArea.offsetHeight / 2 - 40;
ballA.style.left = (centerX - 50 + Math.cos(time) * 40) + 'px';
ballA.style.top = (centerY + Math.sin(time * 0.7) * 25) + 'px';
ballB.style.left = (centerX + 50 + Math.cos(time + Math.PI) * 40) + 'px';
ballB.style.top = (centerY + Math.sin(time * 0.7 + Math.PI) * 25) + 'px';
requestAnimationFrame(animate);
}
// 立即开始自动演示
animate();
}
autoDemo();
</script>
</body>
</html>