TailwindCSS (7) - Tailwind v3๊ณผ Container Query
๐ ๋ค์ด๊ฐ๋ฉฐ
์ด๋ฒ ํฌ์คํ ์ ์ ๋ฌด ์งํ ์ค ๋ง์ฃผ์ณค๋ ๋ฌธ์ ์ ๊ทธ ํด๊ฒฐ ๊ณผ์ ์ ๋ํด ์์ฑํด๋ณด๊ณ ์ ํ๋ค.
โจ๊ตฌํ ์๊ตฌ์ฌํญ
ํ๋ฉด์ ๊ตฌ์ฑํ๋ ๊ฐ๋ก๋ก ๋์ด๋ 3๊ฐ์ ์ปดํฌ๋ํธ๊ฐ ์๋ค. ๊ฐ๊ฐ์ ์ปดํฌ๋ํธ๊ฐ A, B, C ๋ผ๊ณ ํ ๋ A๋ ์์ ํ ์ ์ ์ ์๊ณ , C๋ ์ฌ์ฉ์๊ฐ ๋๋๊ทธํด์ ์ฌ์ด์ฆ๋ฅผ ์กฐ์ ํ ์ ์๋ resizable Component๋ค.
๋ง์ง๋ง์ผ๋ก B๋ flex-1
๋ก ๋จ์ ๊ณต๊ฐ์ ์ ๋ถ ์ฐจ์งํ๊ธฐ ๋๋ฌธ์, ์ฌ์ฉ์๊ฐ A์ C๋ฅผ ์กฐ์ ํจ์ ๋ฐ๋ผ ์๋์ผ๋ก B์ ์ฌ์ด์ฆ๊ฐ ์กฐ์ ๋๋ค.
๋ค์๊ณผ ๊ฐ์ ์ํฉ์ A์ C๋ ๋ชจ๋ CSS ์์ ์ด ๋๋ฌ์ง๋ง B๋ ๊ธฐ์กด์ ์์ ํ๋ Media Query๋ก๋ ๋ถ์กฑํ๋ค๋ ์์ฌ์์ด ์์๋ค. ex) ์ฌ์ด์ฆ๋ฅผ ์ค์์ ๋ ๊ธ์ ๊นจ์ง ๋ฐ์ ๋ฑ
์ด ๊ฒ์ ํด๊ฒฐํ๋ (์๋ง) ๊ฐ์ฅ ์ข์ ๋ฐฉ๋ฒ์ Container Query๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด๋ค! ๋ ์์ด๋์ด๋ ๋ฐ๋ก ๋ ์ฌ๋๋๋ฐ,
๋ฌธ์ ๋โฆ๐ค
โ์๊ฐํด ๋ณผ ์
ํ์ฌ ํ๋ก์ ํธ์์ ์ฌ์ฉํ๊ณ ์๋ Tailwind CSS๋ 3๋ฒ์ ์ผ๋ก ํด๋น ๋ฒ์ Tailwind ์์ฒด๋ก๋ Container Query๋ฅผ ์ ๊ณตํ์ง ์๊ณ v4์์ ์ ์์ผ๋ก ๋ค์ด์จ ๊ฒ์ผ๋ก ์๊ณ ์์๊ธฐ์, ์ง์ CSS๋ก ์์ฑํด์ผ ํ๋? ์๊ฐํ๋ฉด์ ๋จผ์ ๊ด๋ จ ๋ด์ฉ์ ๊ฒ์ํด๋ณด๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ํตํด v3์์๋ ์ถฉ๋ถํ ์ฌ์ฉํ ์ ์์๋ค.
๐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ค์นํ๊ธฐ
์ด๋ฒ์ ์ฌ์ฉํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ @tailwindcss/container-queries
๋ค.
๋จผ์ ์ค์น๋ถํฐ ํ์.
1
npm install @tailwindcss/container-queries
tailwind.config.ts
ํ์ผ์ ํด๋น ํ๋ฌ๊ทธ์ธ์ ์ฌ์ฉํ๊ฒ ๋ค๊ณ ์์ฑํ๋ค.
1
2
3
4
5
6
7
8
9
10
// tailwind.config.js
module.exports = {
theme: {
// ...
},
plugins: [
require("@tailwindcss/container-queries"),
// ...
],
}
๋๋ ๋ฑ ๋๊ฐ์ง์ container breakpoint
๊ฐ ํ์ํ๊ธฐ์ ์๋์ ๊ฐ์ด ์์ฑํด์ฃผ์๋ค.
1
2
3
4
theme: {
containers: {sm: '640px', md: '768px'},
// ...
}
๐ก ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฌ์ฉํ๊ธฐ
์ฌ์ฉ ๋ฐฉ์๋ ๊ต์ฅํ ๊ฐ๋จํ๋ค!
โ ๊ธฐ๋ณธ ์ฌ์ฉ๋ฒ
๋จผ์ container (๊ธฐ์ค)์ด ๋์ด์ผ ํ๋ elements์ container
๋ฅผ ๋ช
์ํด์ฃผ๊ณ , ํด๋น container
ํฌ๊ธฐ์ ๋ฐ๋ผ ๋ฌ๋ผ์ ธ์ผ ํ๋ ์์๋ค์ @์ฌ์ด์ฆ:ํด๋์ค
๋ฅผ ์์ฑํด์ฃผ๋ฉด ๋๋ค!!
1
2
3
<div class="@container">
<div class="@lg:underline">lg ์ฌ์ด์ฆ ์ด์์ผ ๋ underline์ด ์๊น๋๋ค!</div>
</div>
โ ์ด๋ฆ ์ง์ ํ๊ธฐ
@container/container์ด๋ฆ
์ ํตํด ๊ธฐ์ค์ด ๋ ํน์ container
๋ฅผ ๋ง๋ค์ด ์ฃผ๊ณ ์ค์ ์ฌ์ฉํ ๋๋ @์ฌ์ด์ฆ:ํด๋์ค/container์ด๋ฆ
๊ณผ ๊ฐ์ด ์์ฑํด์ ์ฌ์ฉํ๋ค.
1
2
3
4
5
<div class="@container/main">
<div class="@lg/main:underline">
main container๊ฐ lg ์ฌ์ด์ฆ ์ด์์ผ ๋ underline์ด ์๊น๋๋ค!
</div>
</div>
โ ์์์ ํฌ๊ธฐ ์ง์ ํ๊ธฐ
๊ธฐ๋ณธ์ ์ผ๋ก ์ ๊ณต๋๋ ์ปจํ ์ด๋ ํฌ๊ธฐ ๋ฟ๋ง ์๋๋ผ ์์์ ๊ฐ์ ์ฌ์ฉํด ์ผํ์ฑ ์ฌ์ด์ฆ๋ฅผ ์ง์ ํด์ค ์๋ ์๋ค.
1
2
3
4
5
<div class="@container">
<div class="@[17.5rem]:underline"></div>
container๊ฐ 17.5rem ์ฌ์ด์ฆ ์ด์์ผ ๋ underline์ด ์๊น๋๋ค!
</div>
</div>
โ container ์ญ์ ํ๊ธฐ
container๊ฐ ๋์ด์ container์ ์ญํ ์ ํ์ง ์๋๋ก ํ๊ณ ์ถ๋ค๋ฉด @container-normal
์ ์ฌ์ฉํ๋ฉด ๋๋ค.
๐ฉโ๐ป custom Hook ๋ณ๊ฒฝ
ํ์ฌ ์์
ํ ๋ด์ฉ ์ค์๋ custom Hook์ ์ฌ์ฉํด, resize
์ด๋ฒคํธ๊ฐ ๋ฐ์ํ์ ๋, ์ ์ ํ ์ฌ์ด์ฆ๊ฐ ๋๋ฉด ํ์ํ ์ปดํฌ๋ํธ๋ฅผ ๋ ๋๋ง ํ๋๋ก ํ๋ค.
container Query๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด์ ํด๋น customHook์ container
๋ก ์ผ์ elements
์ offsetWidth
๋ฅผ ์ถ์ ํ ํ์๊ฐ ์์๋ค.
๊ทธ๋ฐ๋ฐ.. ์ฐฝ ์ฌ์ด์ฆ๋ฅผ ์ง์ ์ค์ด๋ ๊ฒ์ด ์๋๋ผ ํน์ element์ ํฌ๊ธฐ๋ฅผ ์ค์ด๋ ๊ฒ์ธ๋ฐ ์ด๋ฅผ ์ด๋ป๊ฒ ๊ฐ์งํ์ง? ๐ค ๊ณ ๋ฏผํ๋ ์์ค ResizeObserver
๋ฅผ ๋ฐ๊ฒฌํ๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import { useState, useEffect } from "react"
//์์ฃผ ์ฌ์ฉํ๋ container ์ breakPoint
// 768px, 640px
const useIsSmallContainer = (breakpoint: number) => {
const [isSmallContainer, setIsSmallContainer] = useState(false)
useEffect(() => {
const container = document.querySelector("[data-content]")
if (!container) return
//ํน์ ์์์ ํฌ๊ธฐ ๋ณํ๋ฅผ ๊ฐ์งํ๋ค.
const observer = new ResizeObserver(([entry]) => {
if (!entry) return
const width = entry.contentRect.width
setIsSmallContainer(width < breakpoint)
})
observer.observe(container)
return () => observer.disconnect()
}, [breakpoint])
return isSmallContainer
}
export default useIsSmallContainer
๐ข ํด๊ฒฐํ๊ธฐ ์ด๋ ค์ ๋ ์ํฉ
๊ทธ๋ฐ๋ฐ, ์ด๋ฏธ tailwind์ ๊ธฐ๋ณธ md
์ฌ์ด์ฆ๋ฅผ ์์ฑํด ๋๊ฑธ @md
๋ก ๊ต์ฒดํ๋ ๊ฒ ๋ง์ผ๋ก๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ค. ์๋ํ๋ฉด ๋ทฐํฌ์ธํธ ๊ธฐ์ค์ผ๋ก 4๊ฐ์ง์ breakpoint๊ฐ ์๋๋ฐ, B์ปดํฌ๋ํธ ์์ ์๋ B-1
์ปดํฌ๋ํธ๋ ํน์ ์ฌ์ด์ฆ๋ฅผ ์ ์งํ๋ค๊ฐ ์ค์ด๋ค์ด์ผ ํ๊ธฐ ๋๋ฌธ์ด์๋ค.
๊ทธ๋์ ์ด ๋ถ๋ถ์ ๊ทธ๋ฅ CSS๋ก ์ฒ๋ฆฌํ๋ ๊ฒ์ด ๋ ํธ๋ฆฌํ ๊ฒ ๊ฐ๋ค๋ ํ๋จํ์, ์๋์ ๊ฐ์ด ์์ฑํ๋ค.
์ฃผ์ํ ์ ์ @container
์์ @media
๋ฅผ ์ค์ฒฉ์ํค๋ ๊ฒ์ ๊ฐ๋ฅํ์ง๋ง ๋ฐ๋๋ ๋ถ๊ฐ๋ฅ ํ๋ค๋ ๊ฒ์ด๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* container query์ media query ๋ ์กฐ๊ฑด์ ๊ณ์ฐํด์ผ ๋๋ ๊ฒฝ์ฐ */
.container {
container-type: inline-size;
}
@container (max-width: 639px) {
@media (min-width: 1280px) {
.this-content span {
@apply text-basic;
}
}
}
@container (max-width: 749px) {
@media (min-width: 1280px) {
.box-container {
@apply px-4;
}
}
}
๐ ๊ฒฐ๊ณผ
๊ฒฐ๊ณผ์ ์ผ๋ก ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก ํด๊ฒฐํ ์ ์๋ ๋ถ๋ถ์ ์ต๋ํ CSS ์์ฑ ์์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก ์ฒ๋ฆฌํ์ฌ ์ต์ํ์ CSS๋ง ์์ฑํ๊ณ , ๋๋จธ์ง๋ Tailwind๋ฅผ ์ฌ์ฉํ์ฌ, A์ C์ปดํฌ๋ํธ ํฌ๊ธฐ๊ฐ ๋ณ๊ฒฝํ์ ๋ B์ปดํฌ๋ํธ ์ฌ์ด์ฆ๊ฐ ์ ์ ํ ๋์ํ์ฌ ๋ ๋์ ์ฌ์ฉ์ฑ์ ์ ๊ณตํ ์ ์์๋ค.
โ ์ฒดํฌ ํฌ์ธํธ
- ์ง๊ธ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ง๋ง, Tailwind v4๋ฅผ ์ฌ์ฉํ ์ ํ๊ฒฝ์ด ๊ตฌ์ถ๋๋ฉด ๋ ์ฝ๊ณ ๋น ๋ฅด๊ฒ Container Query๋ฅผ ์ฌ์ฉํ ์ ์์ ๊ฒ์ด๋ผ ๊ธฐ๋๋๋ค.
- Container Query๋ฅผ ์ค์ ์ฌ์ฉํด๋ณด๋๊ฑด ์ฒ์์ด์๋๋ฐ, ์ด์ ์ ์ ํ๋ธ๋ฅผ ํตํด ์ ํ ๋ด์ฉ์ด๋ผ ํ์ํ ์ํฉ์ ์ ์ ํ ๋ ์ฌ๋ฆด ์ ์์๋ค. ์ญ์ ์๋๊ฒ ํ!