Hello,
I have a question about how to replicate the hover effect in boxes like this site (https://www.vovi.studio/).
My question is how to have the box background changed to black but in a smooth way like the example website and split the text.
I managed to do something with the code below, but it wasn't as smooth as on the example site.
// react box component
import { useRef } from 'react';
import gsap from 'gsap';
import { ArrowCircleRight } from 'phosphor-react';
import { Flex, SplitElement } from '@/components';
import * as S from './styles';
import { DefaultTheme } from '@/styles';
interface IGridBoxProps {
alignWrapper?: 'center' | 'flex-end';
justifyChildren?: 'center' | 'space-between';
}
const GridBox = ({
alignWrapper = 'center',
justifyChildren = 'space-between'
}: IGridBoxProps) => {
const splitElementRef = useRef<HTMLDivElement>(null);
const gridBoxRef = useRef<HTMLDivElement>(null);
const tl = gsap.timeline({
defaults: { duration: 0.2, ease: 'power1.inOut' }
});
const onEnter = () => {
if (splitElementRef.current && gridBoxRef.current) {
const splitChildren = gsap.utils.toArray(
splitElementRef.current.children
);
tl.to(gridBoxRef.current, {
background: DefaultTheme.colors.text.heading,
duration: 0.3,
stagger: -0.05
});
tl.to(splitChildren, {
yPercent: -100,
stagger: -0.05
});
}
};
const onLeave = () => {
if (splitElementRef.current && gridBoxRef.current) {
const splitChildren = gsap.utils.toArray(
splitElementRef.current.children
);
tl.to(splitChildren, {
yPercent: 0
});
tl.to(gridBoxRef.current, {
background: DefaultTheme.colors.white,
duration: 0.15
});
}
};
return (
<S.GridBoxWrapper
align={alignWrapper}
ref={gridBoxRef}
onMouseEnter={onEnter}
onMouseLeave={onLeave}
>
<Flex
align="flex-end"
justify={justifyChildren}
style={{
width: '100%'
}}
>
<SplitElement
firstChild="firstChild"
lastChild="lastChild"
ref={splitElementRef}
/>
<ArrowCircleRight size={20} weight="bold" />
</Flex>
</S.GridBoxWrapper>
);
};
export default GridBox;
//styles box component
import styled, { css } from 'styled-components';
import { Flex } from '..';
export const GridBoxWrapper = styled(Flex)`
${({ theme }) => css`
width: 100%;
height: 200px;
border: 1px solid ${theme.colors.gray[50]};
padding: 3.2rem;
svg {
color: ${theme.colors.gray[200]};
}
`}
`;
//react split component
import {
ForwardRefRenderFunction,
HTMLAttributes,
ReactNode,
forwardRef
} from 'react';
import * as S from './styles';
type SlitWrapperDivType = HTMLAttributes<HTMLDivElement>;
interface ISplitElementProps extends SlitWrapperDivType {
firstChild: ReactNode;
lastChild: ReactNode;
}
const SplitElement: ForwardRefRenderFunction<
HTMLDivElement,
ISplitElementProps
> = ({ firstChild, lastChild, ...props }, ref) => {
return (
<S.SplitWrapper {...props} ref={ref}>
<S.SplitChildren>{firstChild}</S.SplitChildren>
<S.SplitChildren>{lastChild}</S.SplitChildren>
</S.SplitWrapper>
);
};
export default forwardRef(SplitElement);
//styles split component
import styled, { css } from 'styled-components';
export const SplitWrapper = styled.div`
width: fit-content;
height: 2em;
overflow: hidden;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: flex-start;
`;
export const SplitChildren = styled.span`
${({ theme }) => css`
color: ${theme.colors.gray[200]};
font-size: 2em;
line-height: 1;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
`}
`;
Can anyone help me improve this gsap code and make the animation as smooth as possible?
Thank you all very much in advance.
Gravação de Tela 2023-10-17 às 18.51.17.mov