Twin.Macro

1,236 阅读2分钟

twin logo

Twin 融合了 Tailwind 的魔力和 css-in-js 的灵活性 使用 Tailwind 类为 jsx 元素设置样式:

import 'twin.macro'

const Input = () => <input tw="border hover:border-black" />

Nest Twin 中的 tw 设置个属性添加条件样式

import tw from 'twin.macro'
const Input = ({ hasHover }) => (
  <input css={[tw`border`, hasHover && tw`hover:border-black`]} />
)

可以用 css 来 混入 sass :

import tw, { css } from 'twin.macro'
const hoverStyles = css`
  &:hover {
    border-color: black;
    ${tw`text-black`}
  }
`
const Input = ({ hasHover }) => (
  <input css={[tw`border`, hasHover && hoverStyles]} />
)

Styled Components

可以用 tw 创建新的样式组件

import tw from 'twin.macro'
const Input = tw.input`border hover:border-black`

克隆存在的样式组件

const PurpleInput = tw(Input)`border-purple-500`

切换到使用styled来添加条件样式

import tw, { styled } from 'twin.macro'

const StyledInput = styled.input(({ hasBorder }) => [
  `color: black;`,
  hasBorder && tw`border-purple-500`,
])
const Input = () => <StyledInput hasBorder />

使用 `` 去混入sass中的样式

import tw, { styled } from 'twin.macro'

const StyledInput = styled.input`
  color: black;
  ${({ hasBorder }) => hasBorder && tw`border-purple-500`}
`
const Input = () => <StyledInput hasBorder />

How it works

当 babel 在编译时运行你的 javascript 或 typescript 文件时,twin 抓取您的类并将它们转换为 css 对象,然后将这些 css 对象传递到您选择的 css-in-js 库中,而无需额外的客户端包

import tw from 'twin.macro'

tw`text-sm md:text-lg`

// ↓ ↓ ↓ ↓ ↓ ↓

{
  fontSize: '0.875rem',
  '@media (min-width: 768px)': {
    fontSize: '1.125rem',
  },
}

Features

  • Simple imports
+ import tw, { styled, css } from 'twin.macro'
- import tw from 'twin.macro'
- import styled from '@emotion/styled'
- import css from '@emotion/react'
  • Adds no size to your build

Twin 使用 Babel 将您使用的类转换为 css 对象,然后编译离开,不留下运行时代码

  • Helpful suggestions for mistypings

Twin chimes in with class and variant values from your Tailwind config:

✕ ml-7 was not found

Try one of these classes:

ml-0 [0] / ml-1 [0.25rem] / ml-2 [0.5rem] / ml-3 [0.75rem] / ml-4 [1rem] / ml-5 [1.25rem] / ml-6 [1.5rem]
ml-8 [2rem] / ml-10 [2.5rem] / ml-12 [3rem] / ml-16 [4rem] / ml-20 [5rem] / ml-24 [6rem] / ml-32 [8rem]
ml-40 [10rem] / ml-48 [12rem] / ml-56 [14rem] / ml-64 [16rem] / ml-auto [auto] / ml-px [1px]
  • Works with the official tailwind vscode plugin

  • Over 40 variants to prefix on your classes

与 Tailwind 不同,前缀始终可以添加到您的类中

-   以 before: 和 after: 为前缀来设置伪元素的样式
-   带有 hocus 的前缀:同时设置悬停 + 焦点样式
-   带有额外组状态的样式,例如 group-hocus: 和 group-active:
-   样式表单字段状态为 `checked:``invalid:` and `required:`
-   在您需要时堆叠变体 `sm:hover:first:bg-black``

Check out the full list of variants →

Apply variants to multiple classes at once with variant groups

import 'twin.macro'

const interactionStyles = () => (
  <div tw="hover:(text-black underline) focus:(text-blue-500 underline)" />
)

const mediaStyles = () => <div tw="sm:(w-4 mt-3) lg:(w-8 mt-6)" />

const pseudoElementStyles = () => (
  <div tw="before:(content block w-10 h-10 bg-black)" />
)

const stackedVariants = () => <div tw="sm:hover:(bg-black text-white)" />

const groupsInGroups = () => <div tw="sm:(bg-black hover:(bg-white w-10))" />

Add vanilla css that integrates with twins features

const alongsideTailwindClasses = () => (
  <div tw="after:(content['hello'] bg-black text-white)" />
)

const setCssVariables = () => <div tw="--base-color[#C0FFEE]" />

const useCssVariables = () => <div tw="background-color[var(--base-color)]" />

const customGridProperties = () => <div tw="grid-area[1 / 1 / 4 / 2]" />

const vendorPrefixes = () => <div tw="-webkit-mask-image[url(mask.png)]" />

Use the theme import to add values from your tailwind config

import { theme, css } from 'twin.macro'

const Input = () => <input css={css({ color: theme`colors.purple.500` })} />

See more examples using the theme import →

Add !important to any class with a trailing or leading bang!

<div tw="hidden!" /> || <div tw="!hidden" />
// ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
<div css={{ "display": "none !important" }} />

Add !important to multiple classes with bracket groups

<div tw="(hidden ml-auto)!" />
// ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
<div css={{ "display": "none !important", "marginLeft": "auto !important" }} />