Introduction
In the previous article, we explored the overall design concept and discussed the visual presentation and user experience of a modern tech website.
Since the initial internal design leaned toward minimalism, the team began exploring ways to enhance the overall design aesthetic. This article delves into the implementation details of creating an engaging dynamic background.
If you're interested in implementing dynamic backgrounds, this guide will walk you through building a visually stunning and functional corporate website from scratch.
Technology Stack
- Frontend Framework: Next.js
- UI Framework: Tailwind CSS
- Styling: Tailwind CSS (rapid development, built-in responsive design, utility-first approach)
Why Next.js?
- Team Compatibility: Based on React, facilitating team collaboration.
- SEO and Performance: Supports Server-Side Rendering (SSR) and Static Site Generation (SSG).
- Powerful Routing: Dynamic routing and file-based routing provide flexibility.
- Built-in Optimizations: Image optimization, enternationalization, and various performance enhancements.
- Dynamic Content Support: Easily handles blogs, news, and other dynamic scenarios.
- Excellent Loading Experience: Great user experience and page load speed.
Dynamic Background Solutions
Dynamic backgrounds can significantly enhance visual appeal. Here are common implementation approaches:
- CSS Animation Backgrounds: Pure CSS implementation using
@keyframeswith gradients, position transitions, and other properties. - Canvas-Based Animated Backgrounds: Using
<canvas>elements with JavaScript for dynamic effects like particle systems and wave animations. - Video Backgrounds: Using
<video>elements to play looping video content as background. - WebGL Dynamic Backgrounds: Using WebGL libraries like Three.js to render 3D dynamic backgrounds.
- Particle Backgrounds: Using existing particle libraries like particles.js or tsparticles for quick implementation.
How to Choose?
- Simple Requirements: Pure CSS animations, video backgrounds.
- Complex Interactions: Canvas animations, WebGL animations (Three.js).
- Quick Implementation: Particle background libraries (particles.js / tsparticles).
Implementation
The following example demonstrates creating a dynamic WebGL background component with React and Tailwind CSS.
1. Create Background Component
Create a new file called AnimatedBackground.tsx:
"use client";
import dynamic from "next/dynamic";
import { Suspense, useEffect, useState } from "react";
import { BackgroundContainer } from "./BackgroundContainer";
const GradientShader = dynamic(
() => import("shadergradient").then((mod) => mod.ShaderGradient),
{ ssr: false }
);
const SceneView = dynamic(() => import("./SceneView").then((mod) => mod.SceneView), {
ssr: false,
loading: () => (
<div
className="w-full h-full bg-cover bg-center"
style={{ backgroundImage: "url(/images/loading-bg.png)" }}
></div>
),
});
export default function AnimatedBackground() {
const shaderConfig: any = {
control: "props",
animate: "on",
brightness: 1.2,
cDistance: 3.6,
cameraZoom: 1,
color1: "#0600B8",
color2: "#9000E3",
color3: "#0B004F",
envPreset: "city",
grain: "off",
lightType: "3d",
reflection: 0.1,
shader: "defaults",
type: "waterPlane",
uSpeed: 0.2,
uTime: 0,
wireframe: false,
zoomOut: false,
toggleAxis: false,
};
const [webglSupported, setWebglSupported] = useState(false);
useEffect(() => {
const canvas = document.createElement("canvas");
const glContext =
canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
if (glContext) {
console.log("WebGL is supported in this browser");
setWebglSupported(true);
} else {
console.log("WebGL is not supported in this browser");
}
}, []);
return (
<>
{webglSupported ? (
<BackgroundContainer>
<SceneView className="w-full h-full">
<Suspense fallback={null}>
<GradientShader {...shaderConfig} />
</Suspense>
</SceneView>
</BackgroundContainer>
) : null}
</>
);
}
2. Create Container Component
Create BackgroundContainer.tsx:
"use client";
import { useRef } from "react";
import dynamic from "next/dynamic";
const ThreeScene = dynamic(() => import("./ThreeScene"), { ssr: false });
const BackgroundContainer = ({ children }: any) => {
const containerRef = useRef<any>();
return (
<div
ref={containerRef}
className="fade-in"
style={{
position: "fixed",
top: 0,
left: 0,
width: "100%",
height: "100%",
zIndex: -1,
overflow: "auto",
touchAction: "auto",
}}
>
{children}
<ThreeScene
style={{
position: "fixed",
top: 0,
left: 0,
width: "100%",
height: "100%",
pointerEvents: "none",
}}
eventSource={containerRef}
eventPrefix="client"
pixelDensity={1}
pointerEvents="none"
/>
</div>
);
};
export { BackgroundContainer };
3. Create Three.js Scene
Create ThreeScene.tsx:
"use client";
import { ShaderGradientCanvas } from "shadergradient";
import { Canvas } from "@react-three/fiber";
import { Preload } from "@react-three/drei";
import tunnel from "tunnel-rat";
const sceneTunnel = tunnel();
export default function ThreeScene({ ...props }) {
return (
<ShaderGradientCanvas {...props}>
{/* @ts-ignore */}
<sceneTunnel.Out />
<Preload all />
</ShaderGradientCanvas>
);
}
4. Create Scene View Component
Create SceneView.tsx:
"use client";
import { forwardRef, Suspense, useImperativeHandle, useRef } from "react";
import {
OrbitControls,
PerspectiveCamera,
View as ViewImpl,
} from "@react-three/drei";
import tunnel from "tunnel-rat";
const sceneTunnel = tunnel();
const ThreeCanvas = ({ children }: any) => {
return <sceneTunnel.In>{children}</sceneTunnel.In>;
};
export const Common = ({ color }: any) => (
<Suspense fallback={null}>
{color && <color attach="background" args={[color]} />}
<ambientLight intensity={0.5} />
<pointLight position={[20, 30, 10]} intensity={1} />
<pointLight position={[-10, -10, -10]} color="blue" />
<PerspectiveCamera makeDefault fov={40} position={[0, 0, 6]} />
</Suspense>
);
const SceneView = forwardRef(({ children, orbit, ...props }: any, ref) => {
const localRef = useRef<any>(null);
useImperativeHandle(ref, () => localRef.current);
return (
<>
<div ref={localRef} {...props} />
<ThreeCanvas>
<ViewImpl track={localRef}>
{children}
{orbit && <OrbitControls />}
</ViewImpl>
</ThreeCanvas>
</>
);
});
SceneView.displayName = "SceneView";
export { SceneView };
5. Integrate the Background
Use the background component in app/page.tsx:
import AnimatedBackground from "@/components/AnimatedBackground";
export default function Home() {
return (
<>
<AnimatedBackground></AnimatedBackground>
<div
className="min-h-screen bg-cover bg-center"
style={{ backgroundImage: "url(/svg/bg_n.svg)" }}
>
...page content...
</div>
</>
);
}
6. Install Dependencies
To run the code, install the required packages:
pnpm add @react-three/drei @react-three/fiber shadergradient tunnel-rat
By following these steps, you can implement a high-performance, responsive dynamic background for your website. Adjust the background type and interaction complexity based on your specific requirements to make your website more visually appealing!
Customization
To configure your own dynamic gradient effect, visit shadergradient.co to customize settings. Once configured, copy the generated parameters into the shaderConfig object in AnimatedBackground.tsx to achieve your unique dynamic background effect.