Post

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์ปดํฌ๋„ŒํŠธ ์‚ฌ์ด์ฆˆ๊ฐ€ ์ ์ ˆํžˆ ๋Œ€์‘ํ•˜์—ฌ ๋” ๋‚˜์€ ์‚ฌ์šฉ์„ฑ์„ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.

โœ… ์ฒดํฌ ํฌ์ธํŠธ

  1. ์ง€๊ธˆ์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ–ˆ์ง€๋งŒ, Tailwind v4๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ํ™˜๊ฒฝ์ด ๊ตฌ์ถ•๋˜๋ฉด ๋” ์‰ฝ๊ณ  ๋น ๋ฅด๊ฒŒ Container Query๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ์ด๋ผ ๊ธฐ๋Œ€๋œ๋‹ค.
  2. Container Query๋ฅผ ์‹ค์ œ ์‚ฌ์šฉํ•ด๋ณด๋Š”๊ฑด ์ฒ˜์Œ์ด์—ˆ๋Š”๋ฐ, ์ด์ „์— ์œ ํŠœ๋ธŒ๋ฅผ ํ†ตํ•ด ์ ‘ํ•œ ๋‚ด์šฉ์ด๋ผ ํ•„์š”ํ•œ ์ƒํ™ฉ์— ์ ์ ˆํžˆ ๋– ์˜ฌ๋ฆด ์ˆ˜ ์žˆ์—ˆ๋‹ค. ์—ญ์‹œ ์•„๋Š”๊ฒŒ ํž˜!

๐Ÿ—‚๏ธ์ฐธ๊ณ  ์‚ฌ์ดํŠธ

This post is licensed under CC BY 4.0 by the author.