Search

Tailwind

Tailwind

์œ ํ‹ธ๋ฆฌํ‹ฐ ๊ธฐ๋ฐ˜์˜ CSS ํ”„๋ ˆ์ž„์›Œํฌ
โ€ข
Tailwind vs Boostrap
โ€ข
์‚ฌ์šฉ ๋ฐฉ๋ฒ•
1.
CDN ๋ฐฉ์‹
2.
Node.js CLI ๋ฐฉ์‹
3.
React ์„ธํŒ…
โ€ข
๊ธฐ๋ณธ ์‚ฌ์šฉ
โ—ฆ
๋ฉ”์ธ ํ™”๋ฉด
โ—ฆ
๋กœ๊ทธ์ธ ํ™”๋ฉด

Tailwind vs Boostrap

ํ•ญ๋ชฉ
Tailwind CSS
Bootstrap
์Šคํƒ€์ผ๋ง ์ ‘๊ทผ ๋ฐฉ์‹
์œ ํ‹ธ๋ฆฌํ‹ฐ ํด๋ž˜์Šค ๊ธฐ๋ฐ˜
์ปดํฌ๋„ŒํŠธ ๊ธฐ๋ฐ˜
์ปค์Šคํ„ฐ๋งˆ์ด์ง•
์„ค์ • ํŒŒ์ผ์„ ํ†ตํ•œ ์œ ํ‹ธ๋ฆฌํ‹ฐ ํด๋ž˜์Šค ํ™•์žฅ ๋ฐ ์ˆ˜์ •
SCSS ๋ณ€์ˆ˜์™€ ๋ฏน์Šค์ธ์œผ๋กœ ์ปค์Šคํ„ฐ๋งˆ์ด์ง• ๊ฐ€๋Šฅ
๋ฏธ๋ฆฌ ์ •์˜๋œ ์ปดํฌ๋„ŒํŠธ
์—†์Œ
๋ฒ„ํŠผ, ์นด๋“œ, ๋„ค๋น„๊ฒŒ์ด์…˜ ๋ฐ” ๋“ฑ ์ œ๊ณต
CSS ํŒŒ์ผ ํฌ๊ธฐ
JIT ๋ชจ๋“œ๋กœ ์‹ค์ œ ์‚ฌ์šฉ๋œ ํด๋ž˜์Šค๋งŒ ๋นŒ๋“œ
๊ธฐ๋ณธ์ ์œผ๋กœ ๋ชจ๋“  ์Šคํƒ€์ผ ํฌํ•จ
๋ฐ˜์‘ํ˜• ๋””์ž์ธ
๋ฐ˜์‘ํ˜• ์œ ํ‹ธ๋ฆฌํ‹ฐ ํด๋ž˜์Šค (sm:, md:, ๋“ฑ)
๋ฏธ๋””์–ด ์ฟผ๋ฆฌ ๊ธฐ๋ฐ˜ ํด๋ž˜์Šค (col-md-6 ๋“ฑ)
ํ•™์Šต ๊ณก์„ 
์œ ํ‹ธ๋ฆฌํ‹ฐ ํด๋ž˜์Šค์˜ ์กฐํ•ฉ์„ ์ตํ˜€์•ผ ํ•จ
์ปดํฌ๋„ŒํŠธ ์‚ฌ์šฉ๋ฒ•์„ ๋ฐฐ์šฐ๊ธฐ ์‰ฌ์›€
๋””์ž์ธ ์‹œ์Šคํ…œ
์ง์ ‘ ๊ตฌ์ถ• ํ•„์š”
ํ”„๋ฆฌ์…‹ ์Šคํƒ€์ผ ์ œ๊ณต
์‚ฌ์šฉ ์‚ฌ๋ก€
๋งž์ถคํ˜• ๋””์ž์ธ, ๋””์ž์ธ ์‹œ์Šคํ…œ ๊ตฌ์ถ•์— ์ ํ•ฉ
์ผ๊ด€๋œ ์Šคํƒ€์ผ ์œ ์ง€, ๋น ๋ฅธ ์ดˆ๊ธฐ ๊ฐœ๋ฐœ์— ์ ํ•ฉ
๋ฐ˜์‘ํ˜• ๊ทธ๋ฆฌ๋“œ ์‹œ์Šคํ…œ
์œ ํ‹ธ๋ฆฌํ‹ฐ ํด๋ž˜์Šค ์กฐํ•ฉ
12-์ปฌ๋Ÿผ ๊ทธ๋ฆฌ๋“œ ์‹œ์Šคํ…œ
์ƒํƒœ ๋ณ€ํ˜• ์ง€์›
์ƒํƒœ๋ณ„ ์œ ํ‹ธ๋ฆฌํ‹ฐ ํด๋ž˜์Šค (ํ˜ธ๋ฒ„, ํฌ์ปค์Šค ๋“ฑ)
์ƒํƒœ๋ณ„ ์œ ํ‹ธ๋ฆฌํ‹ฐ ํด๋ž˜์Šค ์ œ๊ณต
๋‹คํฌ ๋ชจ๋“œ ์ง€์›
์œ ํ‹ธ๋ฆฌํ‹ฐ ํด๋ž˜์Šค ์ œ๊ณต
์ง์ ‘ ๊ตฌํ˜„ ํ•„์š”

์‚ฌ์šฉ ๋ฐฉ๋ฒ•

1.
CDN ๋ฐฉ์‹
2.
Node.js CLI ๋ฐฉ์‹
3.
React ์„ธํŒ…

CDN ๋ฐฉ์‹

1.
CDN script ์ถ”๊ฐ€
2.
์„ค์ •
3.
์ฝ”๋“œ

CDN script ์ถ”๊ฐ€

<script src="https://cdn.tailwindcss.com"></script>
HTML
๋ณต์‚ฌ

์„ค์ •

<!-- ์„ค์ • --> <script> tailwind.config = { theme: { extend: { colors: { primary: '#262626', secondary: '#38BDF8', } } } } </script>
HTML
๋ณต์‚ฌ

์ฝ”๋“œ

<!doctype html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- CDN script ์ถ”๊ฐ€ --> <script src="https://cdn.tailwindcss.com"></script> <!-- ์„ค์ • --> <script> tailwind.config = { theme: { extend: { colors: { primary: '#262626', secondary: '#38BDF8', } } } } </script> </head> <body class="text-white flex flex-col items-center justify-center gap-10 min-h-screen"> <div class="max-w-lg mx-auto bg-secondary p-6 rounded-lg shadow-md"> <h1 class="text-2xl font-bold mb-4">Hello, Tailwind!</h1> <p>tailwind ์„ค์ •์œผ๋กœ ํ…Œ๋งˆ ์ปฌ๋Ÿฌ๋ฅผ ์„ค์ •ํ•˜๊ณ  ์‚ฌ์šฉํ•ด๋ด…๋‹ˆ๋‹ค.</p> <button class="mt-4 bg-primary text-white py-2 px-4 rounded">Primary Button</button> </div> <div class="max-w-lg mx-auto bg-primary p-6 rounded-lg border shadow-md"> <h1 class="text-2xl font-bold mb-4">Hello, Tailwind!</h1> <p>tailwind ์„ค์ •์œผ๋กœ ํ…Œ๋งˆ ์ปฌ๋Ÿฌ๋ฅผ ์„ค์ •ํ•˜๊ณ  ์‚ฌ์šฉํ•ด๋ด…๋‹ˆ๋‹ค.</p> <button class="mt-4 bg-secondary text-white py-2 px-4 rounded">Secondary Button</button> </div> </body> </html>
HTML
๋ณต์‚ฌ

Node.js CLI ๋ฐฉ์‹

1.
tailwind ์„ค์น˜
2.
tailwind.config.js ์„ค์ • ํŒŒ์ผ ์ƒ์„ฑ
3.
tailwind.config.js ์„ค์ •
4.
input.css ์ž‘์„ฑ
5.
output.css ๋นŒ๋“œ
6.
html ์ž‘์„ฑ

tailwind ์„ค์น˜

npm install -D tailwindcss
Bash
๋ณต์‚ฌ

tailwind.config.js ์„ค์ • ํŒŒ์ผ ์ƒ์„ฑ

npx tailwindcss init
Bash
๋ณต์‚ฌ

tailwind.config.js ์„ค์ •

/** @type {import('tailwindcss').Config} */ module.exports = { content: ["./src/**/*.{html,js}"], theme: { extend: { colors: { primary: '#262626', secondary: '#38BDF8', } } }, plugins: [], }
JavaScript
๋ณต์‚ฌ

input.css ์ž‘์„ฑ

๋‹ค์Œ ์ง€์‹œ์ž๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ, tailwind ์˜ ์Šคํƒ€์ผ ๋ ˆ์ด์–ด๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
@tailwind base; @tailwind components; @tailwind utilities;
CSS
๋ณต์‚ฌ
โ€ข
@tailwind base;:
โ—ฆ
์ด ์ง€์‹œ์–ด๋Š” Tailwind์˜ ๊ธฐ๋ณธ ์Šคํƒ€์ผ์„ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค. ๊ธฐ๋ณธ ์Šคํƒ€์ผ์€ ๋ธŒ๋ผ์šฐ์ €์˜ ๊ธฐ๋ณธ ์Šคํƒ€์ผ์„ ๋ฆฌ์…‹ํ•˜๊ณ , ์ผ๊ด€๋œ ๊ธฐ์ดˆ ๋””์ž์ธ์„ ์ œ๊ณตํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ๋Š” ์Šคํƒ€์ผ์˜ ์ผ๊ด€์„ฑ์„ ์œ ์ง€ํ•˜๊ณ  ๊ธฐ๋ณธ์ ์ธ ํƒ€์ดํฌ๊ทธ๋ž˜ํ”ผ ์Šคํƒ€์ผ์„ ์„ค์ •ํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค.
โ€ข
@tailwind components;:
โ—ฆ
์ด ์ง€์‹œ์–ด๋Š” Tailwind์˜ ์ปดํฌ๋„ŒํŠธ ์Šคํƒ€์ผ์„ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค. Tailwind์—์„œ ์ปดํฌ๋„ŒํŠธ๋Š” ์ž์ฃผ ์‚ฌ์šฉํ•˜๋Š” ์Šคํƒ€์ผ ์„ธํŠธ๋ฅผ ๋งํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ๋ฒ„ํŠผ, ํผ, ์•Œ๋ฆผ ๋“ฑ์˜ ์Šคํƒ€์ผ์ด ํฌํ•จ๋ฉ๋‹ˆ๋‹ค. ๋ฌผ๋ก  ์ž์‹ ๋งŒ์˜ ์ปค์Šคํ…€ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ •์˜ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.
โ€ข
@tailwind utilities;:
โ—ฆ
์ด ์ง€์‹œ์–ด๋Š” Tailwind์˜ ์œ ํ‹ธ๋ฆฌํ‹ฐ ํด๋ž˜์Šค๋ฅผ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค. ์œ ํ‹ธ๋ฆฌํ‹ฐ ํด๋ž˜์Šค๋Š” HTML ์š”์†Œ์— ์ง์ ‘ ์ ์šฉํ•˜์—ฌ ์Šคํƒ€์ผ์„ ์ง€์ •ํ•˜๋Š” ๋‚ฎ์€ ์ˆ˜์ค€์˜ ํด๋ž˜์Šค๋“ค์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ํŒจ๋”ฉ, ๋งˆ์ง„, ํ…์ŠคํŠธ ์ƒ‰์ƒ, ๋ฐฐ๊ฒฝ ์ƒ‰์ƒ ๋“ฑ์˜ ์Šคํƒ€์ผ์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋Š” ํด๋ž˜์Šค๋“ค์ž…๋‹ˆ๋‹ค.

output.css ๋นŒ๋“œ

npx tailwindcss -i ./src/input.css -o ./src/output.css --watch
Bash
๋ณต์‚ฌ

html ์ž‘์„ฑ

<!doctype html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- ๋นŒ๋“œ๋œ CSS ํฌํ•จํ•˜๊ธฐ --> <link href="./output.css" rel="stylesheet"> </head> <body class="text-white flex flex-col items-center justify-center gap-10 min-h-screen"> <div class="max-w-lg mx-auto bg-secondary p-6 rounded-lg shadow-md"> <h1 class="text-2xl font-bold mb-4">Hello, Tailwind!</h1> <p>tailwind ์„ค์ •์œผ๋กœ ํ…Œ๋งˆ ์ปฌ๋Ÿฌ๋ฅผ ์„ค์ •ํ•˜๊ณ  ์‚ฌ์šฉํ•ด๋ด…๋‹ˆ๋‹ค.</p> <button class="mt-4 bg-primary text-white py-2 px-4 rounded">Primary Button</button> </div> <div class="max-w-lg mx-auto bg-primary p-6 rounded-lg border shadow-md"> <h1 class="text-2xl font-bold mb-4">Hello, Tailwind!</h1> <p>tailwind ์„ค์ •์œผ๋กœ ํ…Œ๋งˆ ์ปฌ๋Ÿฌ๋ฅผ ์„ค์ •ํ•˜๊ณ  ์‚ฌ์šฉํ•ด๋ด…๋‹ˆ๋‹ค.</p> <button class="mt-4 bg-secondary text-white py-2 px-4 rounded">Secondary Button</button> </div> </body> </html>
HTML
๋ณต์‚ฌ

React ์„ธํŒ…

1.
React ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ
2.
tailwind ์„ค์น˜
3.
tailwind.config.js ์„ค์ • ํŒŒ์ผ ์ƒ์„ฑ
4.
tailwind.config.js ์„ค์ •
5.
index.css ์ž‘์„ฑ
6.
ํ”„๋กœ์ ํŠธ ๋นŒ๋“œ
7.
์ปดํฌ๋„ŒํŠธ ์ž‘์„ฑ

React ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ

npx create-react-app tailwind-app cd tailwind-app
Bash
๋ณต์‚ฌ

tailwind ์„ค์น˜

npm install -D tailwindcss
Bash
๋ณต์‚ฌ

tailwind.config.js ์„ค์ • ํŒŒ์ผ ์ƒ์„ฑ

npx tailwindcss init
Bash
๋ณต์‚ฌ

tailwind.config.js ์„ค์ •

/** @type {import('tailwindcss').Config} */ module.exports = { content: [ "./src/**/*.{js,jsx,ts,tsx}", ], theme: { extend: { colors: { primary: '#262626', secondary: '#38BDF8', } } }, plugins: [], }
JavaScript
๋ณต์‚ฌ

index.css ์ž‘์„ฑ

/* tailwind ์ง€์‹œ์ž ์ถ”๊ฐ€ */ @tailwind base; @tailwind components; @tailwind utilities; /* index.css ๊ธฐ๋ณธ ์ฝ”๋“œ */ body { margin: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } code { font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace; }
CSS
๋ณต์‚ฌ

ํ”„๋กœ์ ํŠธ ๋นŒ๋“œ

npm run start
Bash
๋ณต์‚ฌ

์ปดํฌ๋„ŒํŠธ ์ž‘์„ฑ - App.js

import React from 'react'; const App = () => { return ( <div className="text-white flex flex-col items-center justify-center gap-10 min-h-screen"> <div className="max-w-lg mx-auto bg-secondary p-6 rounded-lg shadow-md"> <h1 className="text-2xl font-bold mb-4">Hello, Tailwind!</h1> <p>tailwind ์„ค์ •์œผ๋กœ ํ…Œ๋งˆ ์ปฌ๋Ÿฌ๋ฅผ ์„ค์ •ํ•˜๊ณ  ์‚ฌ์šฉํ•ด๋ด…๋‹ˆ๋‹ค.</p> <button className="mt-4 bg-primary text-white py-2 px-4 rounded">Primary Button</button> </div> <div className="max-w-lg mx-auto bg-primary p-6 rounded-lg border shadow-md"> <h1 className="text-2xl font-bold mb-4">Hello, Tailwind!</h1> <p>tailwind ์„ค์ •์œผ๋กœ ํ…Œ๋งˆ ์ปฌ๋Ÿฌ๋ฅผ ์„ค์ •ํ•˜๊ณ  ์‚ฌ์šฉํ•ด๋ด…๋‹ˆ๋‹ค.</p> <button className="mt-4 bg-secondary text-white py-2 px-4 rounded">Secondary Button</button> </div> </div> ); }; export default App;
JavaScript
๋ณต์‚ฌ

๊ธฐ๋ณธ ์‚ฌ์šฉ

โ€ข
๊ธฐ๋ณธ ์„ค์ •
โ€ข
๋ฉ”์ธ ํ™”๋ฉด
โ€ข
๋กœ๊ทธ์ธ ํ™”๋ฉด

๊ธฐ๋ณธ ์„ค์ •

โ€ข
ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ
โ€ข
tailwind
โ€ข
react-router
โ€ข
ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ
โ€ข
์ปดํฌ๋„ŒํŠธ

ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ

npx create-react-app basic-app
Bash
๋ณต์‚ฌ

tailwind

npm install -D tailwindcss npx tailwindcss init
Bash
๋ณต์‚ฌ

react-router

npm install react-router-dom
Bash
๋ณต์‚ฌ

ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ

์ปดํฌ๋„ŒํŠธ

โ€ข
Header.jsx
โ€ข
Footer.jsx

Header.jsx

import React from 'react'; import { Link } from 'react-router-dom'; const Header = () => { return ( <header className="bg-gray-800 text-white p-4"> <div className="container mx-auto flex justify-between items-center"> <Link to="/"><h1 className="text-xl font-bold">ALOHA CLASS</h1></Link> <nav> <Link to="/" className="mx-2 hover:underline">Home</Link> <Link to="/login" className="mx-2 hover:underline">Login</Link> </nav> </div> </header> ); }; export default Header;
JavaScript
๋ณต์‚ฌ

Footer.jsx

import React from 'react'; const Footer = () => { return ( <footer className="bg-gray-800 text-white p-4"> <div className="container mx-auto text-center"> <p>&copy; 2024 ALOHA CLASS. All rights reserved.</p> </div> </footer> ); }; export default Footer;
JavaScript
๋ณต์‚ฌ

๋ฉ”์ธ ํ™”๋ฉด

โ€ข
Main.jsx
import React from 'react' import Header from '../components/Header' import Footer from '../components/Footer' import { Link } from 'react-router-dom' const Main = () => { return ( <div className='min-h-screen flex flex-col'> <Header /> <main className="flex-1 container"> <Section /> </main> <Footer /> </div> ) } export default Main export const Section = () => { return ( <section className="p-40 shadow-lg"> <div className="container mx-auto text-center"> <h2 className="text-3xl font-bold mb-4">๋ฉ”์ธ ํ™”๋ฉด</h2> <p className="mb-6">์•ˆ๋…•ํ•˜์„ธ์š”~! React x Tailwind ๊ธฐ๋ณธ ํ”„๋กœ์ ํŠธ์ž…๋‹ˆ๋‹ค.</p> <Link to="/login"> <button className="bg-yellow-400 text-gray-800 py-2 px-6 rounded-lg hover:bg-yellow-500"> Login </button> </Link> </div> </section> ) }
JavaScript
๋ณต์‚ฌ

๋กœ๊ทธ์ธ ํ™”๋ฉด

โ€ข
Login.jsx
import React from 'react'; import Header from '../components/Header'; import Footer from '../components/Footer'; const Login = () => { return ( <div className="min-h-screen flex flex-col"> <Header /> <main className="flex-1 flex items-center justify-center bg-gray-100"> <div className="bg-white p-8 rounded-lg shadow-md w-full max-w-sm"> <h2 className="text-2xl font-bold mb-6 text-center">Login</h2> <form> <div className="mb-4"> <label htmlFor="username" className="block text-sm font-medium text-gray-700">์•„์ด๋””</label> <input type="text" id="username" name="username" required className="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm" placeholder="์•„์ด๋””๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”." /> </div> <div className="mb-6"> <label htmlFor="password" className="block text-sm font-medium text-gray-700">๋น„๋ฐ€๋ฒˆํ˜ธ</label> <input type="password" id="password" name="password" required className="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm" placeholder="โ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ข" /> </div> <button type="submit" className="w-full py-2 px-4 bg-blue-500 text-white font-semibold rounded-lg shadow-md hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2" > ๋กœ๊ทธ์ธ </button> </form> </div> </main> <Footer /> </div> ); }; export default Login;
JavaScript
๋ณต์‚ฌ

index.js

import React from 'react'; import ReactDOM from 'react-dom/client'; import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'; import './index.css'; import Main from './pages/Main'; import Login from './pages/Login'; const root = ReactDOM.createRoot(document.getElementById('root')); root.render( <Router> <Routes> <Route path="/" element={<Main />} /> <Route path="/login" element={<Login />} /> </Routes> </Router> );
JavaScript
๋ณต์‚ฌ