You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Three Fiber中<Html>嵌套<Scroll>的可行性及替代方案咨询

问题:React Three Drei中<ScrollControls>嵌套<Html>的风险与正确实现方式

背景

我在使用React Three Drei的<ScrollControls>组件,它会在画布前创建HTML滚动容器,必须把<Scroll>组件嵌套在里面,内部元素会受滚动影响。目前我直接把@react-three/drei的<Html>组件嵌套在<Scroll>里,看似能用,但听说这不是标准用法,可能有问题。

想咨询:

  1. 这种嵌套方式存在哪些风险?
  2. 如何在R3F项目中无问题地添加文本、图片(比如About.jsx里的示例)?

相关代码

App.jsx

<Canvas>  

// some code .... 

<ScrollControls               
enabled={true}               
damping={0.1}               
horizontal={true}               
pages={3} >  
             
<Scroll>                 
<ThreeScene position={[1, 0, 0]} />              
</Scroll> 
            
</ScrollControls> 
</Canvas>

ThreeScene.jsx

const ThreeScene = () => {
//... some code

return (
<>
{/* Note: This whole group scrolls along, due to the Scrollcontainer in the parent App.jsx */}
<group position={[0, 0, 0]}>
<LandingPage ref={ref} >
{/* Note: Every element inside of these Child-Components of ThreeScene will follow along when scrolling */}
</group>
<group position={[19, 3, 0]}>
<About >
</group>
<group position={[40, 3, 0]}>
<TechStack />
</group>
</>
);
};
export default ThreeScene;

About.jsx

const About = forwardRef(function About(props, ref) {
return (
<>
{/* Note: <Html>: The <Html> component from Drei is designed to render HTML elements directly onto the canvas. These HTML elements are not part of the 3D scene but are instead rendered on top of the canvas. This is useful for overlaying UI elements, text, or other web-based content over your 3D scene. */}
<Html>
<main className={styles.aboutWrapper}>
<img
className={styles.portrait}
src="/assets/images/Portrait.png"
alt=""
/>
<section className={styles.aboutTextSection}>
<h1 className={styles.aboutHeading}>Hey</h1>
<div className={styles.aboutTextBox}>
<p>
orem ipsum dolor sit amet consectetur adipisicing elit. Iusto, maiores ut esse nulla ipsum distinctio iure veniam cum harum soluta sapiente laudantium similique possimus non labore ducimus quibusdam perspiciatis voluptatem expedita illo. Sapiente voluptates, corporis temporibus iure possimus quia commodi molestias porro sit modi.
</p>
</div>
</section>
</main>
</Html>
</>
);
});

解答

一、<Scroll>嵌套<Html>的风险

  1. 滚动同步异常:<Scroll>负责驱动3D场景元素随滚动位移,而<Html>是挂载在画布上层的独立DOM元素,它的定位依赖Three.js相机投影,和<Scroll>的滚动驱动逻辑不兼容,易出现滚动时HTML元素与3D场景错位、延迟的情况。
  2. 性能损耗:<Scroll>会在每一帧更新子元素的3D位置,嵌套的<Html>会被迫频繁重排,额外增加DOM渲染开销,复杂HTML内容时更明显。
  3. 事件冲突:<ScrollControls>会拦截滚动事件实现平滑滚动,嵌套的<Html>若有自身交互逻辑(如文本选中、内部滚动),可能与滚动控件的事件处理冲突,导致交互失效。
  4. 定位逻辑混乱:<Html>默认基于相机视角定位,<Scroll>通过修改3D位置实现滚动,两者叠加会让HTML元素的最终定位不可预测,比如缩放、旋转相机时,位置可能完全偏离预期。

二、正确添加文本、图片的三种方案

方案1:将<Html>放在<ScrollControls>外部,手动同步滚动状态

把<Html>移出<Scroll>和<ScrollControls>,通过useScroll钩子获取滚动进度,手动控制HTML元素的位置或样式,实现与3D场景的同步。

示例修改(About.jsx):

import { useScroll } from '@react-three/drei';

const About = forwardRef(function About(props, ref) {
  const scroll = useScroll();
  // 根据滚动进度计算HTML元素的水平偏移(对应水平滚动场景)
  const htmlOffset = scroll.offset * 60; // 60为总滚动范围,需根据pages和场景调整

  return (
    <Html style={{ left: `${htmlOffset}vw`, position: 'absolute' }}>
      {/* 原HTML内容不变 */}
    </Html>
  );
});

方案2:使用3D原生文本/纹理图片替代HTML

如果不需要复杂HTML样式(如富文本、复杂布局),直接用Three.js原生元素实现,完全融入3D场景,随<Scroll>滚动无兼容问题:

  • 文本:用Drei的<Text>组件渲染3D文本;
  • 图片:用<mesh>+<meshBasicMaterial>加载纹理图片,作为3D平面存在。

示例修改(About.jsx):

import { Text } from '@react-three/drei';
import { useLoader } from '@react-three/fiber';
import { TextureLoader } from 'three';

const About = forwardRef(function About(props, ref) {
  const portraitTexture = useLoader(TextureLoader, '/assets/images/Portrait.png');

  return (
    <group {...props} ref={ref}>
      {/* 3D图片 */}
      <mesh position={[-2, 0, 0]}>
        <planeGeometry args={[3, 4]} />
        <meshBasicMaterial map={portraitTexture} />
      </mesh>
      {/* 3D标题文本 */}
      <Text position={[1, 1, 0]} fontSize={0.5} color="#333">
        Hey
      </Text>
      {/* 3D段落文本(wrapCount控制换行) */}
      <Text position={[1, 0, 0]} fontSize={0.2} color="#666" wrapCount={60}>
        orem ipsum dolor sit amet consectetur adipisicing elit. Iusto, maiores ut esse nulla ipsum distinctio iure veniam cum harum soluta sapiente laudantium similique possimus non labore ducimus quibusdam perspiciatis voluptatem expedita illo.
      </Text>
    </group>
  );
});

方案3:混合模式(兼顾复杂HTML与性能)

必须用复杂HTML(如富文本、表单)时用方案1同步位置;简单图片、标题用方案2的3D元素,既满足布局需求,又避免性能和兼容问题。


内容的提问来源于stack exchange,提问作者Nadja Probst

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 14:04:52