如何为flex-direction切换添加平滑过渡动画?
如何为登录/注册切换面板添加平滑滑动动画?
你当前通过切换flex-direction实现面板左右交换,但flex-direction是离散属性,不支持CSS过渡,所以切换是瞬间完成的。下面是几个可行的实现方案:
方案一:原生CSS位移过渡(推荐)
核心思路是保留两个表单面板,通过transform: translateX()控制位置,配合transition实现滑动动画,同时用绝对定位让面板重叠在同一区域。
修改后的代码(基于你的Chakra UI实现)
// Imports... const Auth: React.FC = () => { const auth = useAuth() const isSignInForm = auth.state === AuthStates.signIn // 侧边栏样式:切换时从右侧滑到左侧 const boxStyle = { flex: '3', bg: 'teal.400', transition: 'transform 0.3s ease', transform: isSignInForm ? 'translateX(0)' : 'translateX(-100%)', position: 'absolute', right: 0, height: '100%', width: 'calc(3/(4+3)*100%)' // 固定宽度,避免flex布局影响 } // 登录表单样式:默认显示,切换时滑到左侧 const signInFormStyle = { flex: '4', transition: 'transform 0.3s ease', transform: isSignInForm ? 'translateX(0)' : 'translateX(-100%)', position: 'absolute', left: 0, height: '100%', width: 'calc(4/(4+3)*100%)', display: 'grid', placeItems: 'center' } // 注册表单样式:默认隐藏在右侧,切换时滑到原位 const signUpFormStyle = { ...signInFormStyle, transform: isSignInForm ? 'translateX(100%)' : 'translateX(0)' } return ( <Flex w='100%' h='100vh' pos='relative' overflow='hidden' // 防止滑动时内容溢出视口 > {/* 登录表单 */} <Grid sx={signInFormStyle}> {/* 登录表单内容 */} </Grid> {/* 注册表单 */} <Grid sx={signUpFormStyle}> {/* 注册表单内容 */} </Grid> {/* 侧边栏 */} <Box sx={boxStyle}> <VStack h='100%' justifyContent='center' alignItems='center'> <Heading fontSize='1rem' as='h1' pb='1rem' color='white'> {isSignInForm ? '还没有账号?' : '已经注册过了?'} </Heading> <Button variant='outline' size='sm' w='12rem' color='white' _hover={{}} onClick={() => { auth.updateState(isSignInForm ? AuthStates.signUp : AuthStates.signIn) }} > {isSignInForm ? '注册' : '登录'} </Button> </VStack> </Box> <Heading pos='absolute' top='2rem' left='2rem' color={isSignInForm ? 'teal.500' : 'white'} fontSize='xx-large' transition='color 0.3s ease' // 标题颜色同步添加过渡 > Ideator </Heading> </Flex> ) } export default Auth
关键说明
- 两个表单面板都渲染在页面中,通过
translateX控制左右位移,transition属性实现平滑过渡 - 侧边栏固定宽度并绝对定位,切换时跟随表单滑动
- 容器添加
overflow:hidden,避免滑动过程中内容超出视口
方案二:CSS Grid 列宽过渡
利用CSS Grid的grid-template-columns属性过渡,需要将列宽设置为百分比或固定数值(fr单位过渡兼容性较差)。
实现步骤
- 定义CSS类:
.auth-container { --form-ratio: 57.14%; /* 4/(4+3) */ --sidebar-ratio: 42.86%; /* 3/(4+3) */ display: grid; grid-template-columns: var(--form-ratio) var(--sidebar-ratio); transition: grid-template-columns 0.3s ease; } .auth-container.sign-up { grid-template-columns: var(--sidebar-ratio) var(--form-ratio); }
- 修改React组件:
<Flex className={`auth-container ${isSignInForm ? '' : 'sign-up'}`} w='100%' h='100vh' pos='relative' > <Grid flex='4' placeItems='center'> {/* 根据isSignInForm渲染对应表单 */} </Grid> <Box sx={boxStyle}> {/* 侧边栏内容 */} </Box> {/* 标题 */} </Flex>
注意事项
- 部分旧版浏览器对
grid-template-columns的过渡支持有限,适合现代浏览器环境 - 无需渲染双表单,只需根据状态切换表单内容即可
方案三:使用动画库(如framer-motion)
如果项目已引入动画库,可利用其封装好的动画能力快速实现效果,代码更简洁。
示例代码
import { motion, AnimatePresence } from 'framer-motion' const Auth: React.FC = () => { const auth = useAuth() const isSignInForm = auth.state === AuthStates.signIn const boxStyle = { flex: '3', bg: 'teal.400' } return ( <Flex w='100%' h='100vh' pos='relative' overflow='hidden' > <AnimatePresence mode='wait'> {/* 根据状态切换表单,添加滑动动画 */} {isSignInForm ? ( <motion.Grid key='sign-in' flex='4' placeItems='center' initial={{ x: '100%' }} animate={{ x: 0 }} exit={{ x: '-100%' }} transition={{ duration: 0.3 }} > {/* 登录表单 */} </motion.Grid> ) : ( <motion.Grid key='sign-up' flex='4' placeItems='center' initial={{ x: '-100%' }} animate={{ x: 0 }} exit={{ x: '100%' }} transition={{ duration: 0.3 }} > {/* 注册表单 */} </motion.Grid> )} </AnimatePresence> {/* 侧边栏滑动动画 */} <motion.Box sx={boxStyle} animate={{ x: isSignInForm ? 0 : '-100%' }} transition={{ duration: 0.3 }} > {/* 侧边栏内容 */} </motion.Box> <Heading pos='absolute' top='2rem' left='2rem' color={isSignInForm ? 'teal.500' : 'white'} fontSize='xx-large' transition='color 0.3s ease' > Ideator </Heading> </Flex> ) } export default Auth
优势
- 动画控制更灵活,支持自定义缓动、延迟等参数
- 内置
AnimatePresence组件处理组件卸载时的动画,避免闪屏问题
内容的提问来源于stack exchange,提问作者howranwin
相关产品推荐
相关产品推荐

