在 Tailwind CSS 中制作动画标签?
Posted
技术标签:
【中文标题】在 Tailwind CSS 中制作动画标签?【英文标题】:Make animated tabs in Tailwind CSS? 【发布时间】:2021-05-22 13:39:15 【问题描述】:我想制作一个像这样的动画标签:
我正在使用带有 Tailwind 的 React。这是我的代码:
import React from 'react'
import clsx from 'clsx'
export const Modal = () =>
const [theme, setTheme] = React.useState<'light' | 'dark' | 'system'>('light')
return (
<div className="flex mx-2 mt-2 rounded-md bg-blue-gray-100">
<div
className=clsx('flex-1 py-1 my-2 ml-2 text-center rounded-md',
'bg-white': theme === 'light',
'transition duration-1000 ease-out transform translate-x-10':
theme !== 'light',
)
>
<button
className=clsx(
'w-full text-sm cursor-pointer select-none focus:outline-none',
'font-bold text-blue-gray-900': theme === 'light',
'text-blue-gray-600': theme !== 'light',
)
onClick=() =>
setTheme('light')
>
Light
</button>
</div>
<div
className=clsx('flex-1 py-1 my-2 ml-2 text-center rounded-md',
'bg-white': theme === 'dark',
)
>
<button
className=clsx(
'w-full text-sm cursor-pointer select-none focus:outline-none',
'font-bold text-blue-gray-900': theme === 'dark',
'text-blue-gray-600': theme !== 'dark',
)
onClick=() =>
setTheme('dark')
>
Dark
</button>
</div>
<div
className=clsx('flex-1 py-1 my-2 mr-2 text-center rounded-md',
'bg-white': theme === 'system',
)
>
<button
className=clsx(
'w-full text-sm cursor-pointer select-none focus:outline-none',
'font-bold text-blue-gray-900': theme === 'system',
'text-blue-gray-600': theme !== 'system',
)
onClick=() =>
setTheme('system')
>
System
</button>
</div>
</div>
)
但它看起来像:
当主题不是light
时,我使用translate-x-10
,因此文本也会移动。
我希望 UI 与上面的完全一样,同时仍然使用实际选项卡的按钮。
最小代码沙盒 → https://codesandbox.io/s/mobx-theme-change-n1nvg?file=/src/App.tsx
我该怎么做?
【问题讨论】:
将动画移动到<span>
并应用translate-x-10
怎么样?
@markmead span
应该在哪里?我在button
上方尝试过,没有包围它,但我什么也没看到。
@markmead 这里是代码框 → codesandbox.io/s/mobx-theme-change-n1nvg
【参考方案1】:
事实证明,纯 Tailwind 是可能的。
tailwind.config.js
module.exports =
theme:
extend:
translate:
200: '200%',
,
,
,
App.tsx
import * as React from "react"
import observer from "mobx-react"
import clsx from "clsx"
import useStore from "./context"
const AppTheme = observer(() =>
const
theme: app ,
updateTheme,
= useStore()
return (
<>
<div className="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
<div className="mt-2">
<h4 className="text-xl font-bold text-gray-800">Background</h4>
</div>
</div>
<div className="relative mx-2 mt-2 rounded-md bg-gray-100">
<div
id="slider"
className=clsx(
"absolute inset-y-0 w-1/3 h-full px-4 py-1 transition-transform transform",
"translate-x-0": app === "light",
"translate-x-full": app === "dark",
"translate-x-200": app === "system",
,
)
style=
app === "system"
?
transform: "translateX(200%)", // if you added `translate-x-200` to `tailwind.config.js` then you can remove the `style` tag completely
:
>
<div
className=clsx(
"w-full h-full bg-white rounded-md",
active: app === "light",
"bg-gray-600": app === "dark",
,
// needs to be separate object otherwise dark/light & system keys overlap resulting in a visual bug
["bg-gray-600"]: app === "system",
,
)
></div>
</div>
<div className="relative flex w-full h-full">
<button
tabIndex=0
className=clsx(
"py-1 my-2 ml-2 w-1/3 text-sm cursor-pointer select-none focus:outline-none",
active: app === "light",
"font-bold text--gray-900": app === "light",
"text--gray-600": app !== "light",
,
)
onKeyUp=(event: React.KeyboardEvent<htmlElement>) =>
if (event.key === "Tab")
updateTheme(
app: "light",
)
onClick=() =>
updateTheme(
app: "light",
)
>
Light
</button>
<button
tabIndex=0
className=clsx(
"py-1 my-2 ml-2 w-1/3 text-sm cursor-pointer select-none focus:outline-none",
active: app === "dark",
"font-bold text-white": app === "dark",
"text--gray-600": app !== "dark",
,
)
onKeyUp=(event: React.KeyboardEvent<HTMLElement>) =>
if (event.key === "Tab")
updateTheme(
app: "dark",
)
onClick=() =>
updateTheme(
app: "dark",
)
>
Dark
</button>
<button
tabIndex=0
className=clsx(
"py-1 my-2 ml-2 w-1/3 text-sm cursor-pointer select-none focus:outline-none",
active: app === "system",
"font-bold text-white": app === "system",
"text--gray-600": app !== "system",
,
)
onKeyUp=(event: React.KeyboardEvent<HTMLElement>) =>
if (event.key === "Tab")
updateTheme(
app: "system",
)
onClick=() =>
updateTheme(
app: "system",
)
>
System
</button>
</div>
</div>
</>
)
)
export default observer(function App()
return <AppTheme />
)
代码沙盒 → https://codesandbox.io/s/mobx-theme-change-animated-18gc6?file=/src/App.tsx
想知道为什么它不在 Codesandbox 上制作动画,但它在本地工作。也许是 Codesandbox 错误 :)
【讨论】:
【参考方案2】:你可以很容易地做这个动画,你需要在包含三个按钮的父元素中添加另一个标签元素。
因此,该元素将跟踪哪个按钮处于活动状态,并将根据其宽度移动。
例如,如果第一个按钮是活动的,这个元素根本不会被翻译,因为它是第一个元素,所以位置会是0。
这个会做动画的元素会有绝对定位,像这样:
.tab-item-animate
position: absolute;
top: 6px;
left: 6px;
width: calc(100% - 12px);
height: 32px;
transform-origin: 0 0;
transition: transform 0.25s;
第一个按钮处于活动状态:
.tabs .tabs-item:first-child.active ~ .tab-item-animate
transform: translateX(0) scaleX(0.333);
第二个按钮激活:
.tabs .tabs-item:nth-child(2).active ~ .tab-item-animate
transform: translateX(33.333%) scaleX(0.333);
第三个按钮激活:
.tabs .tabs-item:nth-child(3).active ~ .tab-item-animate
transform: translateX(33.333% * 2) scaleX(0.333);
我没有太多使用 Tailwind 的经验,但我不确定你是否可以用它来管理整个事情(也许你可以用我的代码做一些其他操作,只用 Tailwind 来做)。
我为此添加了一个单独的 CSS 文件,我提供了一个演示,基于您共享的代码:
tabs animated link
PS:我对你的 HTML 结构做了一点改动,你不需要在每个按钮上方添加另一个 div,没有必要。
【讨论】:
该死的,非常感谢 Teuta。我也认为它不能用 Tailwind 来完成,但我从来没有尝试过动画任何东西所以不确定:) 嘿Teuta,你是怎么决定top
& left
成为6px
& height
成为32px
& width
成为calc(100% - 12px)
?你是在 DevTools 中检查了computed
属性还是通过添加font-size + margin + padding
来计算的?另外,我不明白scaleX
的必要性?如果你能在帖子中解释它会很高兴:)
再次感谢您。我之所以问,是因为当我向其中添加 focus-ring 时计算有点偏离,但我会从这里开始管理。再次感谢,感谢您的帮助:)
Oye Tueta,只是想让您知道 Tailwind 完全可以实现,我在下面发布了解决方案。
@deadcoder0904,哇,太棒了!我很高兴看到您找到了使用 Tailwind 的解决方案! :)以上是关于在 Tailwind CSS 中制作动画标签?的主要内容,如果未能解决你的问题,请参考以下文章
我使用 Tailwind 制作的 CSS 不适用于使用 gridsome 构建 netlify
当使用 Tailwind CSS 单击按钮时,从屏幕左侧制作侧边栏滑动