背景
在上一篇文章 《如何實現一個充滿科技感的官網(一)》 中,我們初步瞭解了該官網的整體設計,並與大家探討了它的視覺呈現和用户體驗。
我們前期的內部設計偏向簡潔,所以開始思考如何提升網站的整體設計感。這些嘗試便由此展開。
網站地址:https://infinilabs.com/
如果你對動態背景的實現感興趣,這篇文章將帶你深入探索,揭秘如何從零打造一個兼具美感與功能性的企業官網!
技術選型
- 前端框架:Next.js
- UI 框架:基於 Tailwind CSS
- CSS 樣式:Tailwind CSS(快速開發、內置響應式、豐富工具類)
為什麼選擇 Next.js?
- 兼容團隊技術棧:基於 React,便於團隊協作。
- SEO 和性能優化:支持服務端渲染(SSR)和靜態站點生成(SSG)。
- 路由強大:支持動態路由和文件路由,靈活易用。
- 內置優化:圖片優化、國際化、多種性能提升。
- 動態內容支持:博客、新聞等動態場景輕鬆應對。
- 加載體驗佳:用户體驗和頁面加載速度表現優秀。
動態的背景方案
動態背景可以顯著提升視覺吸引力,以下是常用實現方案:
- CSS 動畫背景:使用純 CSS 實現動態背景,通過
@keyframes配合漸變色、位置移動等屬性。 - 動態 Canvas 背景:使用
<canvas>元素,結合 JavaScript 繪製動態效果,比如粒子系統、波浪效果等。 - 動態視頻背景:使用
<video>元素播放循環視頻作為背景。 - WebGL 動態背景:使用 WebGL 庫(如 Three.js)渲染 3D 動態背景。
- 動態粒子背景:使用現有的粒子背景庫快速實現動態粒子效果。(particles.js 或 tsparticles)
- ......
如何選擇?
- 簡單需求: 純 CSS 動畫、動態視頻背景。
- 複雜交互:Canvas 動畫、WebGL 動畫(Three.js)。
- 快速實現:使用粒子背景庫(particles.js / tsparticles)。
動態背景代碼實現
以下示例通過 WebGL 創建了一個動態背景組件,支持 React 和 Tailwind CSS。
- 創建
GlobalBackground.tsx文件:
"use client";
import dynamic from "next/dynamic";
import { Suspense, useEffect, useState } from "react";
import { Layout } from "./Layout";
const ShaderGradient = dynamic(
() => import("shadergradient").then((mod) => mod.ShaderGradient),
{ ssr: false }
);
const View = dynamic(() => import("./View").then((mod) => mod.View), {
ssr: false,
loading: () => (
<div
className="w-full h-full bg-cover bg-center"
style={{ backgroundImage: "url(/images/loading-bg.png)" }}
></div>
),
});
export default function GlobalBackground() {
const defaultProps: any = {
control: "props",
animate: "on",
brightness: 1.2,
cDistance: 3.6,
cameraZoom: 1,
color1: "#0600B8",
color2: "#9000E3",
color3: "#0B004F",
// embedMode: "off",
envPreset: "city",
// gizmoHelper: "hide",
grain: "off",
lightType: "3d",
reflection: 0.1,
shader: "defaults",
type: "waterPlane",
uSpeed: 0.2,
uTime: 0,
wireframe: false,
zoomOut: false,
toggleAxis: false,
};
const [suspenseWebgl, setSuspenseWebgl] = useState(false);
useEffect(() => {
const canvas = document.createElement("canvas");
const gl =
canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
if (gl) {
// 瀏覽器支持 WebGL
console.log("The browser does support WebGL");
setSuspenseWebgl(true);
} else {
console.log("The browser does not support WebGL");
// 瀏覽器不支持 WebGL
}
}, []);
return (
<>
{suspenseWebgl ? (
<Layout>
<View className="w-full h-full">
<Suspense fallback={null}>
<ShaderGradient {...defaultProps} />
</Suspense>
</View>
</Layout>
) : null}
</>
);
}
- 創建
Layout.tsx文件:
"use client";
import { useRef } from "react";
import dynamic from "next/dynamic";
const Scene = dynamic(() => import("./Scene"), { ssr: false });
const Layout = ({ children }: any) => {
const ref = useRef<any>();
return (
<div
ref={ref}
className="fade-in"
style={{
position: "fixed",
top: 0,
left: 0,
width: "100%",
height: "100%",
zIndex: -1,
overflow: "auto",
touchAction: "auto",
}}
>
{children}
<Scene
style={{
position: "fixed",
top: 0,
left: 0,
width: "100%",
height: "100%",
pointerEvents: "none",
}}
eventSource={ref}
eventPrefix="client"
pixelDensity={1}
pointerEvents="none"
/>
</div>
);
};
export { Layout };
- 創建
Scene.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 r3f = tunnel();
export default function Scene({ ...props }) {
// Everything defined in here will persist between route changes, only children are swapped
return (
<ShaderGradientCanvas {...props}>
{/* @ts-ignore */}
<r3f.Out />
<Preload all />
</ShaderGradientCanvas>
);
}
- 創建
View.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 r3f = tunnel();
const Three = ({ children }: any) => {
return <r3f.In>{children}</r3f.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 View = forwardRef(({ children, orbit, ...props }: any, ref) => {
const localRef = useRef<any>(null);
useImperativeHandle(ref, () => localRef.current);
return (
<>
<div ref={localRef} {...props} />
<Three>
<ViewImpl track={localRef}>
{children}
{orbit && <OrbitControls />}
</ViewImpl>
</Three>
</>
);
});
View.displayName = "View";
export { View };
- 直接在
app/page.tsx使用背景組件:
import GlobalBackground from "@/components/GlobalBackground";
export default function Home() {
return (
<>
<GlobalBackground></GlobalBackground>
<div
className="min-h-screen bg-cover bg-center"
style={{ backgroundImage: "url(/svg/bg_n.svg)" }}
>
....
</div>
</>
);
}
- 當然,代碼弄好了,要想讓代碼運行起來,還需要安裝一下依賴:
pnpm add @react-three/drei @react-three/fiber shadergradient tunnel-rat
通過這些步驟,你將能夠為網站實現高性能、響應式的動態背景效果。根據具體需求調整背景類型和交互複雜度,讓你的官網更具吸引力!
效果
具體效果,可以直接在網站上瀏覽,效果更真實。網站地址:https://infinilabs.com/
分享
如果你也想配置自己的動態效果圖,可以前往 shadergradient.co 網站進行自定義設置。完成後,將生成的配置參數複製到 GlobalBackground.tsx 文件的 defaultProps 中,即可實現屬於你自己的動態背景效果。
參考
- https://github.com/ruucm/shadergradient
- https://www.shadergradient.co/
- https://infinilabs.com/
福利
INFINI Labs 一直致力於為開發者和企業提供優質的開源工具,提升整個技術生態的活力。除了維護國內最流行的分詞器 analysis-ik 和 analysis-pinyin,也在不斷推動更多高質量開源產品的誕生。
最近新開源的產品和工具:
- INFINI Framework https://github.com/infinilabs/framework
- INFINI Gateway https://github.com/infinilabs/gateway
- INFINI Console https://github.com/infinilabs/console
- INFINI Agent https://github.com/infinilabs/agent
- INFINI Loadgen https://github.com/infinilabs/loadgen
- INFINI Coco AI https://github.com/infinilabs/coco-app
以上開源軟件都可以在 Github 上面找到: https://github.com/infinilabs
希望大家都能給個免費的 Star🌟 支持一下!!!
作者:Rain9,極限科技(INFINI Labs) 高級前端開發工程師。