Framer Motion:修复 child 使用 AnimateSharedLayout 设置动画时的失真
Framer Motion: Fix child distortion when animated with AnimateSharedLayout
我想在卡片展开时使用 AnimateSharedLayout 交叉淡入淡出(div 与 children)。
但是,字体在布局动画中变形。
Here is a link to a codesandbox.
这是我的代码(我使用的是 Tailwind CSS):
这是 Projects
组件,它在 CSS 网格中包含所有卡片:
export default function Projects() {
const projectObjArray = [
{
title: "Project 1",
description: "some description",
background: "#f00",
link: ""
},
{
title: "Project 2",
description: "some description",
background: "#f00",
link: ""
},
{
title: "Project 3",
description: "some description",
background: "#f00",
link: ""
}
];
const [expanded, setExpanded] = useState(undefined);
return (
<div>
<h1 className="text-6xl mb-5 md:text-left md:ml-10 pb-5">My Projects</h1>
<div className="grid grid-cols-1 md:grid-cols-3 gap-10">
{projectObjArray.map((el, index) => {
if (index !== expanded) {
return (
<ProjectTemplate
projectobj={el}
key={el.title}
index={index}
setexpanded={setExpanded}
/>
);
} else {
return (
<ProjectTemplateExpanded
projectobj={el}
key={el.title}
index={index}
setexpanded={setExpanded}
/>
);
}
})}
</div>
</div>
);
}
单击卡片时,其索引会保存在 expanded
状态。
然后,ProjectTemplateExpanded
组件将在该位置呈现,而不是 ProjectTemplate
.
以下是这些组件:
export default function ProjectTemplate(props) {
return (
<motion.div
initial={{ borderRadius: "100px" }}
animate={{ borderRadius: "50px" }}
className="w-full h-56 flex flex-col justify-center"
style={{ background: props.projectobj.background }}
onClick={() => {
props.setexpanded(props.index);
}}
layoutId={`Container${props.projectobj.title}`}
transition={{ duration: 2 }}
>
<motion.h1
layoutId={`Title${props.projectobj.title}`}
// layout
transition={{ duration: 2 }}
className="text-2xl"
>
{props.projectobj.title}
</motion.h1>
<motion.p
layoutId={`Description${props.projectobj.title}`}
// layout
transition={{ duration: 2 }}
className="text-1xl"
>
{props.projectobj.description}
</motion.p>
</motion.div>
);
}
export default function ProjectTemplateExpanded(props) {
return (
<>
<div className="h-56"></div>
<motion.div
className="w-full fixed top-0 left-0 right-0 bottom-0 z-50 flex flex-col justify-center items-center"
style={{ background: "rgba(0, 0, 0, 0.5)" }}
onClick={() => {
props.setexpanded(undefined);
}}
>
<motion.div
layoutId={`Container${props.projectobj.title}`}
transition={{ duration: 2 }}
initial={{ borderRadius: "50px" }}
animate={{ borderRadius: "100px" }}
style={{
background: props.projectobj.background,
width: "80vw",
height: "50vh"
}}
onClick={(e) => {
e.stopPropagation();
}}
className="flex flex-col justify-center"
>
<motion.h1
layoutId={`Title${props.projectobj.title}`}
// layout
transition={{ duration: 2 }}
className="text-2xl"
>
{props.projectobj.title}
</motion.h1>
<motion.p
layoutId={`Description${props.projectobj.title}`}
// layout
transition={{ duration: 2 }}
className="text-1xl"
>
{props.projectobj.description}
</motion.p>
</motion.div>
</motion.div>
</>
);
}
Projects 组件用 AnimateSharedLayout
包装。
export default function App() {
return (
<div className="App text-white pt-5 px-5">
<AnimateSharedLayout type="crossfade">
<Projects />
</AnimateSharedLayout>
</div>
);
}
documentation 状态:
To correct distortion on immediate children, add layout to those too.
所以我尝试在 h1 和 p 标签上的 layoutId 旁边添加布局道具,但这并没有改变任何东西。
This blog post 声明比例校正应用于任何参与共享元素转换的组件(这里就是这种情况,因为在 children 上设置了 layoutId)
我错过了什么?
我已将传递给布局 属性 的值更改为“位置”。这样文本保持相同的风格。我还将 ProjectTemplateExpanded 函数中的高度和宽度样式从样式 属性 移动到动画 属性 以获得更流畅的动画。我使用 W3Schools 的 @keyframes 规则信息作为指南。尝试以下操作:
export default function ProjectTemplate(props) {
return (
<motion.div
initial={{ borderRadius: "100px" }}
animate={{ borderRadius: "50px" }}
className="w-full h-56 flex flex-col justify-center"
style={{ background: props.projectobj.background }}
onClick={() => {
props.setexpanded(props.index);
}}
layoutId={`Container${props.projectobj.title}`}
transition={{ duration: 2 }}
>
<motion.h1
layoutId={`Title${props.projectobj.title}`}
layout="position"
transition={{ duration: 2 }}
className="text-2xl"
>
{props.projectobj.title}
</motion.h1>
<motion.p
layoutId={`Description${props.projectobj.title}`}
layout="position"
transition={{ duration: 2 }}
className="text-1xl"
>
{props.projectobj.description}
</motion.p>
</motion.div>
);
}
export default function ProjectTemplateExpanded(props) {
return (
<>
<div className="h-56"></div>
<motion.div
className="w-full fixed top-0 left-0 right-0 bottom-0 z-50 flex flex-col justify-center items-center"
style={{ background: "rgba(0, 0, 0, 0.5)" }}
onClick={() => {
props.setexpanded(undefined);
}}
>
<motion.div
layoutId={`Container${props.projectobj.title}`}
transition={{ duration: 2 }}
initial={{ borderRadius: "50px" }}
animate={{ borderRadius: "100px",
width: "80vw",
height: "50vh" }}
style={{
background: props.projectobj.background,
}}
onClick={(e) => {
e.stopPropagation();
}}
className="flex flex-col justify-center"
>
<motion.h1
layoutId={`Title${props.projectobj.title}`}
layout="position"
transition={{ duration: 2 }}
className="text-2xl"
>
{props.projectobj.title}
</motion.h1>
<motion.p
layoutId={`Description${props.projectobj.title}`}
layout="position"
transition={{ duration: 2 }}
className="text-1xl"
>
{props.projectobj.description}
</motion.p>
</motion.div>
</motion.div>
</>
);
}
参考文献:
@keyframes 规则 - CSS 动画。 W3学校。 https://www.w3schools.com/css/css3_animations.asp。 (2021 年 8 月 24 日访问)。
解决办法是在容器上放items-center
。然后,h1
和 p
元素的宽度将在动画期间得到更正。
我想在卡片展开时使用 AnimateSharedLayout 交叉淡入淡出(div 与 children)。
但是,字体在布局动画中变形。
Here is a link to a codesandbox.
这是我的代码(我使用的是 Tailwind CSS):
这是 Projects
组件,它在 CSS 网格中包含所有卡片:
export default function Projects() {
const projectObjArray = [
{
title: "Project 1",
description: "some description",
background: "#f00",
link: ""
},
{
title: "Project 2",
description: "some description",
background: "#f00",
link: ""
},
{
title: "Project 3",
description: "some description",
background: "#f00",
link: ""
}
];
const [expanded, setExpanded] = useState(undefined);
return (
<div>
<h1 className="text-6xl mb-5 md:text-left md:ml-10 pb-5">My Projects</h1>
<div className="grid grid-cols-1 md:grid-cols-3 gap-10">
{projectObjArray.map((el, index) => {
if (index !== expanded) {
return (
<ProjectTemplate
projectobj={el}
key={el.title}
index={index}
setexpanded={setExpanded}
/>
);
} else {
return (
<ProjectTemplateExpanded
projectobj={el}
key={el.title}
index={index}
setexpanded={setExpanded}
/>
);
}
})}
</div>
</div>
);
}
单击卡片时,其索引会保存在 expanded
状态。
然后,ProjectTemplateExpanded
组件将在该位置呈现,而不是 ProjectTemplate
.
以下是这些组件:
export default function ProjectTemplate(props) {
return (
<motion.div
initial={{ borderRadius: "100px" }}
animate={{ borderRadius: "50px" }}
className="w-full h-56 flex flex-col justify-center"
style={{ background: props.projectobj.background }}
onClick={() => {
props.setexpanded(props.index);
}}
layoutId={`Container${props.projectobj.title}`}
transition={{ duration: 2 }}
>
<motion.h1
layoutId={`Title${props.projectobj.title}`}
// layout
transition={{ duration: 2 }}
className="text-2xl"
>
{props.projectobj.title}
</motion.h1>
<motion.p
layoutId={`Description${props.projectobj.title}`}
// layout
transition={{ duration: 2 }}
className="text-1xl"
>
{props.projectobj.description}
</motion.p>
</motion.div>
);
}
export default function ProjectTemplateExpanded(props) {
return (
<>
<div className="h-56"></div>
<motion.div
className="w-full fixed top-0 left-0 right-0 bottom-0 z-50 flex flex-col justify-center items-center"
style={{ background: "rgba(0, 0, 0, 0.5)" }}
onClick={() => {
props.setexpanded(undefined);
}}
>
<motion.div
layoutId={`Container${props.projectobj.title}`}
transition={{ duration: 2 }}
initial={{ borderRadius: "50px" }}
animate={{ borderRadius: "100px" }}
style={{
background: props.projectobj.background,
width: "80vw",
height: "50vh"
}}
onClick={(e) => {
e.stopPropagation();
}}
className="flex flex-col justify-center"
>
<motion.h1
layoutId={`Title${props.projectobj.title}`}
// layout
transition={{ duration: 2 }}
className="text-2xl"
>
{props.projectobj.title}
</motion.h1>
<motion.p
layoutId={`Description${props.projectobj.title}`}
// layout
transition={{ duration: 2 }}
className="text-1xl"
>
{props.projectobj.description}
</motion.p>
</motion.div>
</motion.div>
</>
);
}
Projects 组件用 AnimateSharedLayout
包装。
export default function App() {
return (
<div className="App text-white pt-5 px-5">
<AnimateSharedLayout type="crossfade">
<Projects />
</AnimateSharedLayout>
</div>
);
}
documentation 状态:
To correct distortion on immediate children, add layout to those too.
所以我尝试在 h1 和 p 标签上的 layoutId 旁边添加布局道具,但这并没有改变任何东西。
This blog post 声明比例校正应用于任何参与共享元素转换的组件(这里就是这种情况,因为在 children 上设置了 layoutId)
我错过了什么?
我已将传递给布局 属性 的值更改为“位置”。这样文本保持相同的风格。我还将 ProjectTemplateExpanded 函数中的高度和宽度样式从样式 属性 移动到动画 属性 以获得更流畅的动画。我使用 W3Schools 的 @keyframes 规则信息作为指南。尝试以下操作:
export default function ProjectTemplate(props) {
return (
<motion.div
initial={{ borderRadius: "100px" }}
animate={{ borderRadius: "50px" }}
className="w-full h-56 flex flex-col justify-center"
style={{ background: props.projectobj.background }}
onClick={() => {
props.setexpanded(props.index);
}}
layoutId={`Container${props.projectobj.title}`}
transition={{ duration: 2 }}
>
<motion.h1
layoutId={`Title${props.projectobj.title}`}
layout="position"
transition={{ duration: 2 }}
className="text-2xl"
>
{props.projectobj.title}
</motion.h1>
<motion.p
layoutId={`Description${props.projectobj.title}`}
layout="position"
transition={{ duration: 2 }}
className="text-1xl"
>
{props.projectobj.description}
</motion.p>
</motion.div>
);
}
export default function ProjectTemplateExpanded(props) {
return (
<>
<div className="h-56"></div>
<motion.div
className="w-full fixed top-0 left-0 right-0 bottom-0 z-50 flex flex-col justify-center items-center"
style={{ background: "rgba(0, 0, 0, 0.5)" }}
onClick={() => {
props.setexpanded(undefined);
}}
>
<motion.div
layoutId={`Container${props.projectobj.title}`}
transition={{ duration: 2 }}
initial={{ borderRadius: "50px" }}
animate={{ borderRadius: "100px",
width: "80vw",
height: "50vh" }}
style={{
background: props.projectobj.background,
}}
onClick={(e) => {
e.stopPropagation();
}}
className="flex flex-col justify-center"
>
<motion.h1
layoutId={`Title${props.projectobj.title}`}
layout="position"
transition={{ duration: 2 }}
className="text-2xl"
>
{props.projectobj.title}
</motion.h1>
<motion.p
layoutId={`Description${props.projectobj.title}`}
layout="position"
transition={{ duration: 2 }}
className="text-1xl"
>
{props.projectobj.description}
</motion.p>
</motion.div>
</motion.div>
</>
);
}
参考文献:
@keyframes 规则 - CSS 动画。 W3学校。 https://www.w3schools.com/css/css3_animations.asp。 (2021 年 8 月 24 日访问)。
解决办法是在容器上放items-center
。然后,h1
和 p
元素的宽度将在动画期间得到更正。