はじめに
自分が詰まったので。特にtailwind。
style attributeを使う
一番手っ取り早いのはこれです。
<div style={{ backgroundImage: imageUrl }}>
....
</div>
擬似クラス使えない問題
style attibute内では:hoverなどの擬似クラスが使えないので、この手法は背景画像が常に表示されるデザインにのみ使えます。「hover時のみ表示したい」などといった場合は以下から紹介するアプローチが必要になります。
css-modulesを使う
import style from './Component.module.css'
const Component = ({ imageUrl }) => {
const cssProperties = {
'--image-url': `url(${imageUrl})`
}
return (
<div style={{ cssProperties }} className={style.backgroundImage}>
....
</div>
)
}
.backgroundImage:hover {
background-image: var(--image-url);
}
これでhover時のみ背景画像を表示させることができます。
TypeScriptの場合
custom propertyを含むオブジェクトに正しい型を付けてあげないとstyle attributeで弾かれます。
import { CSSProperties } from 'react'
const cssProperties = {
'--image-url': `url(${imageUrl})`
} as CSSProperties
ありがちなミス
// ❌
const cssProperties = {
'--image-url': imageUrl
}
// ⭕
const cssProperties = {
'--image-url': `url(${imageUrl})`
}
/* ❌ */
.backgroundImage:hover {
background-image: url(var(--image-url));
}
/* ⭕ */
.backgroundImage:hover {
background-image: var(--image-url);
}
tailwindcssを使う
注: version3以上が必要です。
const Component = ({ imageUrl }) => {
const cssProperties = {
'--image-url': `url(${imageUrl})`
}
return (
<div style={{ cssProperties }} className='hover:bg-[image:var(--image-url)]'>
....
</div>
)
}
ありがちなミス
<div className={`hover:bg-[url(${imageUrl})]`}>
....
</div>
tailwindはコンパイル時にcssを生成しているので、クラス名の一部に動的な値が含まれているとそのクラス名は生成されません。
<div style={{ cssProperties }} className='hover:bg-[var(--image-url)]'>
....
</div>
bg-[]
の中のimage:
が抜けているので、tailwind側からするとvar(--image-url)
が背景色なのか背景画像なのか分からない状況になっています。
styled-componentsを使う
import styled from "styled-components";
const Component = ({ imageUrl }) => {
return (
<DivWithImage url={imageUrl}>
....
</DivWithImage>
)
}
const DivWithImage = styled.div`
&:hover{
background-image: url(${prop => prop.url});
}
`
TypeScriptの場合
const DivWithImage = styled.div<{ url: string }>`
&:hover{
background-image: url(${prop => prop.url});
}
`
propの型を定義しましょう。
ありがちなミス
import styled from "styled-components";
const Component = ({ imageUrl }) => {
return (
<DivWithImage>
....
</DivWithImage>
)
}
const DivWithImage = styled.div`
&:hover{
background-image: url(${imageUrl}); // ❌
}
`
DivWithImage
の定義が親コンポーネントの外で行われているので、親のpropであるimageUrl
には直接アクセスできません。
これを可能にするには、DivWithImage
の定義を親コンポーネント内で行えばよいのですが、レンダーごとに定義し直されてしまうのでパフォーマンスが落ちます。最初の例のように外で定義して別でpropを渡しましょう。
おわりに
tailwind君、基本的には使いやすいけど動的な値が絡んでくると途端にポンコツになりがち。
なにか間違いがあればコメントで教えてくれると助かります。