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

如何为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单位过渡兼容性较差)。

实现步骤

  1. 定义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);
}
  1. 修改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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 08:25:29