How to create a particle background パーティクル背景の作り方
Floating particles in the background. Customize particle count, speed, and colors. 背景に浮遊するパーティクルアニメーション。粒子の数、速度、色をカスタマイズできます。
ライブデモ Live Demo
概要・用途・特徴Overview, Usage & Features
何ができるかWhat it does
Floating particles in the background. Customize particle count, speed, and colors.
背景に浮遊するパーティクルアニメーション。粒子の数、速度、色をカスタマイズできます。
どこで使うかWhere to use
web application, marketing page
ヒーロー背景、テクノロジー系サイト、ゲームUI、サイエンスフィクション風デザイン
特徴Key features
Canvas-based particle system with customizable particle count, speed, color, and connection lines. Fully interactive — particles react to mouse movement. Lightweight vanilla JS with no dependencies. Degrades gracefully when canvas is unavailable.
Canvasベースのパーティクルシステム。パーティクル数・速度・色・接続線をカスタマイズ可能。マウス動作にインタラクティブに反応。依存なしのバニラJS。Canvasが利用できない場合のグレースフルデグレード対応。
調整可能パラメータ Adjustable Parameters
| Parameter | Default | Description |
|---|---|---|
--particle-count | — | number of particles to display |
--particle-size | — | size of each particle |
--particle-speed | — | animation duration (seconds) |
particle color | — | particle color and opacity |
random position | — | random horizontal and vertical positioning |
--translate-x | — | horizontal movement distance |
実装コード Implementation Code
// react/M-006.jsx
import { useEffect, useRef } from "react";
import "./M-006.css";
export default function ParticleBackground({ count = 50 }) {
const stageRef = useRef(null);
useEffect(() => {
const stage = stageRef.current;
if (!stage) return;
const particles = [];
for (let i = 0; i < count; i++) {
const particle = document.createElement("div");
particle.className = "particle";
particle.style.left = Math.random() * 100 + "%";
particle.style.top = Math.random() * 100 + "%";
particle.style.animationDelay = Math.random() * 20 + "s";
particle.style.animationDuration = (15 + Math.random() * 10) + "s";
particle.style.setProperty("--translate-x", (Math.random() - 0.5) * 200 + "px");
stage.appendChild(particle);
particles.push(particle);
}
return () => {
particles.forEach(p => p.remove());
};
}, [count]);
return (
<div className="particle-stage" ref={stageRef}>
<div className="particle-content">Content</div>
</div>
);
}
/* react/M-006.css */
.particle-stage {
position: relative;
overflow: hidden;
min-height: 300px;
}
.particle {
position: absolute;
width: 3px;
height: 3px;
background: rgba(255, 255, 255, 0.6);
border-radius: 50%;
animation: float 20s linear infinite;
}
@keyframes float {
0% {
transform: translateY(50px) translateX(0);
opacity: 0;
}
10%, 90% {
opacity: 1;
}
100% {
transform: translateY(-50px) translateX(var(--translate-x, 0));
opacity: 0;
}
}
import React, { useEffect, useRef, useState } from 'react';
import './M-006.css';
const ParticleBackground = ({
count = 50,
particleSize = 3,
speed = 20,
className = "",
children
}) => {
const stageRef = useRef(null);
const [particles, setParticles] = useState([]);
const createParticle = () => {
return {
id: Math.random(),
left: Math.random() * 100,
top: Math.random() * 100,
delay: Math.random() * 20,
duration: 15 + Math.random() * 10,
translateX: (Math.random() - 0.5) * 200
};
};
const generateParticles = (particleCount) => {
const newParticles = [];
for (let i = 0; i < particleCount; i++) {
newParticles.push(createParticle());
}
setParticles(newParticles);
};
useEffect(() => {
generateParticles(count);
}, [count]);
return (
<div
ref={stageRef}
className={`particle-stage ${className}`}
style={{
'--particle-size': `${particleSize}px`,
'--particle-speed': `${speed}s`
}}
>
{particles.map((particle) => (
<div
key={particle.id}
className="particle"
style={{
left: `${particle.left}%`,
top: `${particle.top}%`,
animationDelay: `${particle.delay}s`,
animationDuration: `${particle.duration}s`,
'--translate-x': `${particle.translateX}px`
}}
/>
))}
<div className="particle-content">
{children}
</div>
</div>
);
};
// Demo component for showcase
const ParticleBackgroundDemo = () => {
const [settings, setSettings] = useState({
count: 50,
particleSize: 3,
speed: 20
});
const handleSettingChange = (key, value) => {
setSettings(prev => ({
...prev,
[key]: value
}));
};
return (
<div className="particle-demo">
<div className="demo-stage">
<ParticleBackground
count={settings.count}
particleSize={settings.particleSize}
speed={settings.speed}
>
<h2>Particle Background</h2>
<p>Beautiful floating particles animation</p>
</ParticleBackground>
</div>
<div className="controls">
<div className="control-group">
<label htmlFor="count-slider">
Particle Count: {settings.count}
</label>
<input
id="count-slider"
type="range"
min="20"
max="100"
step="10"
value={settings.count}
onChange={(e) => handleSettingChange('count', parseInt(e.target.value))}
/>
</div>
<div className="control-group">
<label htmlFor="size-slider">
Particle Size: {settings.particleSize}px
</label>
<input
id="size-slider"
type="range"
min="1"
max="6"
step="1"
value={settings.particleSize}
onChange={(e) => handleSettingChange('particleSize', parseInt(e.target.value))}
/>
</div>
<div className="control-group">
<label htmlFor="speed-slider">
Animation Speed: {settings.speed}s
</label>
<input
id="speed-slider"
type="range"
min="10"
max="30"
step="5"
value={settings.speed}
onChange={(e) => handleSettingChange('speed', parseInt(e.target.value))}
/>
</div>
</div>
</div>
);
};
export default ParticleBackground;
export { ParticleBackgroundDemo };
/* M-006 Particle Background Styles */
.particle-demo {
width: 100%;
max-width: 1000px;
margin: 0 auto;
padding: 2rem;
}
.demo-stage {
margin-bottom: 2rem;
}
.particle-stage {
border-radius: 18px;
padding: 0;
background: #050714;
border: 1px solid rgba(255, 255, 255, 0.1);
min-height: 300px;
position: relative;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
/* CSS Custom Properties for customization */
--particle-size: 3px;
--particle-speed: 20s;
}
.particle-stage::before {
content: "";
position: absolute;
inset: 0;
background: radial-gradient(circle at 30% 50%, rgba(92, 106, 196, 0.15), transparent 50%),
radial-gradient(circle at 70% 50%, rgba(34, 211, 238, 0.15), transparent 50%);
z-index: 0;
}
.particle {
position: absolute;
width: var(--particle-size);
height: var(--particle-size);
background: rgba(255, 255, 255, 0.6);
border-radius: 50%;
animation: float var(--particle-speed) linear infinite;
opacity: 0;
}
@keyframes float {
0% {
transform: translateY(50px) translateX(0);
opacity: 0;
}
10% {
opacity: 1;
}
90% {
opacity: 1;
}
100% {
transform: translateY(-50px) translateX(var(--translate-x, 0));
opacity: 0;
}
}
.particle-content {
position: relative;
z-index: 1;
color: #f5f6ff;
font-size: 24px;
font-weight: 600;
text-align: center;
padding: 40px;
}
.particle-content h2 {
margin: 0 0 1rem 0;
font-size: 2rem;
font-weight: 700;
}
.particle-content p {
margin: 0;
opacity: 0.8;
font-size: 1.1rem;
font-weight: 400;
}
/* Controls Styles */
.controls {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 1.5rem;
padding: 1.5rem;
background: #f8fafc;
border-radius: 12px;
border: 1px solid #e2e8f0;
}
.control-group {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.control-group label {
font-weight: 600;
color: #374151;
font-size: 0.875rem;
}
.control-group input[type="range"] {
width: 100%;
height: 6px;
background: #e2e8f0;
border-radius: 3px;
outline: none;
cursor: pointer;
}
.control-group input[type="range"]::-webkit-slider-thumb {
appearance: none;
width: 18px;
height: 18px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 50%;
cursor: pointer;
border: 2px solid white;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.control-group input[type="range"]::-moz-range-thumb {
width: 18px;
height: 18px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 50%;
cursor: pointer;
border: 2px solid white;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
/* Dark theme support */
@media (prefers-color-scheme: dark) {
.controls {
background: #1f2937;
border-color: #374151;
}
.control-group label {
color: #f3f4f6;
}
}
/* Responsive adjustments */
@media (max-width: 768px) {
.particle-demo {
padding: 1rem;
}
.particle-stage {
min-height: 250px;
}
.particle-content {
padding: 24px;
}
.particle-content h2 {
font-size: 1.5rem;
}
.particle-content p {
font-size: 1rem;
}
.controls {
grid-template-columns: 1fr;
gap: 1rem;
}
}
/* High contrast mode support */
@media (prefers-contrast: high) {
.particle-stage {
border: 2px solid #fff;
}
.control-group input[type="range"]::-webkit-slider-thumb {
border: 3px solid #000;
}
}
仕組みとカスタマイズHow It Works & Customization
仕組みHow it works
A requestAnimationFrame loop draws and moves particle objects on an HTML canvas element each frame. Each particle has an x/y position, velocity vector, and size. When two particles come within a threshold distance, a semi-transparent connecting line is drawn between them. Mouse position influences nearby particle trajectories via an attraction/repulsion force.
requestAnimationFrameループでHTMLキャンバス上のパーティクルオブジェクトを毎フレーム描画・移動。各パーティクルはx/y座標、速度ベクトル、サイズを持つ。閾値距離内の2つのパーティクル間に半透明の接続線を描画。マウス位置が近傍パーティクルの軌跡に引力/斥力として影響。
カスタマイズ方法Customization
Reduce particleCount for better performance on mobile. Change lineColor and dotColor to match brand identity. Adjust the distance threshold for connection lines to increase or decrease the web density. Set interactive: false to disable mouse reaction.
モバイルのパフォーマンス向上のためparticleCountを減らす。lineColorとdotColorをブランドカラーに変更。接続線の距離閾値でウェブの密度を調整。interactive:falseでマウス反応を無効化。
注意点Caveats
Canvas animations are CPU-intensive. Always provide a reduced-motion fallback (static background or simplified version). Avoid rendering too many particles (>200) on mobile devices. Consider pausing animation when the tab is not visible using the Page Visibility API.
Canvasアニメーションははたして CPU 負荷が高い。静的背景やシンプル版など必ずreduced-motionフォールバックを提供。モバイルでは200個以上のパーティクルを避ける。Page Visibility APIでタブ非表示時にアニメーションを一時停止することを検討。
よくある質問 Frequently Asked Questions
How to customize the particle background? Particle Backgroundをカスタマイズするには?
Modify the CSS custom properties and class styles defined in the code section. Key adjustable values include colors, sizes, durations, and spacing. See the Adjustable Parameters section for specific variables.
コードセクションで定義されているCSSカスタムプロパティとクラススタイルを変更してください。色、サイズ、時間、間隔が主な調整可能値です。具体的な変数は調整可能パラメータセクションを参照してください。
How to use the particle background in React? ReactでParticle Backgroundを使うには?
Import the provided React component and its CSS file. The component accepts props for customization. Check the React code section for the full implementation and available props.
提供されているReactコンポーネントとCSSファイルをインポートしてください。コンポーネントのpropsでカスタマイズできます。完全な実装と利用可能なpropsはReactコードセクションを参照してください。
What are the performance implications of particle background? Particle Backgroundのパフォーマンスへの影響は?
This implementation uses CSS transforms and opacity for animations, which are GPU-accelerated. It's lightweight and doesn't cause layout thrashing. Consider using prefers-reduced-motion for accessibility.
この実装はCSSのtransformとopacityを使用しており、GPUアクセラレーションされます。軽量でレイアウトスラッシングを引き起こしません。アクセシビリティのためにprefers-reduced-motionの使用を検討してください。
AIへの指示テンプレート AI Prompt Template
以下をAIに貼り付けると実装を依頼できます。 Paste the following into your AI assistant to request implementation.