๐๐ป ์นด๋๋ ์น ์ฑ์ด๋ ๋ชจ๋ฐ์ผ ์ฑ์์ ๋งค์ฐ ๋ง์ด ์ฐ์ด๋ ์์์
๋๋ค.
Cards are a widely used element in web and mobile apps.
๐๐ป ๋ฐ์ดํฐ๋ฅผ ํ๋ฉด์ ํ์ํ ๋ ์นด๋ ์์์ ๋ฐ์ดํฐ๋ฅผ ๋ด์ ํ๋ฉด์ ํํํ๋ ๊ฒฝ์ฐ๊ฐ ๋งค์ฐ ๋ง์ต๋๋ค.
When displaying data on the screen, it is very common to present it using card elements.
๐๐ป tailwind๋ ์๋์ ์น์ฌ์ดํธ์ ๊ฒ์์ ํตํด์ ์์ธํ ๋ด์ฉ์ ํ์ธ ํ ์ ์์ต๋๋ค.
You can find detailed information about Tailwind by searching on the website below.
https://tailwindcss.com/docs/installation/using-vite
๐๐ป ์ ์ฒด ์ฝ๋๋ ๊นํ๋ธ์์ ํ์ธ ํ ์ ์์ต๋๋ค.
You can find the full code on GitHub.
https://github.com/gideonslife01/flm-webui
๐ ํ์ ์คํฌ๋ฆฝํธ / Typescript
โ๏ธ page.tsx๋ ํ์
์คํฌ๋ฆฝํธ๋ฅผ ์ฌ์ฉํฉ๋๋ค.
page.tsx uses TypeScript.
โ๏ธ ๋ง์ฝ์ ์๋ํฐ๋ก ์ฝ๋ ์คํ์ ํ๊ทธ ๋ถ๋ถ์ ๋นจ๊ฐ ์ค์ด ์๊ธฐ๋ฉด ์๋์ฒ๋ผ ๋ชจ๋์ ์ค์นํฉ๋๋ค.
If a red line appears under the tag section when opening the code in the editor, install the module as shown below.
โ๏ธ vscode๋ ์๋ํฐ๊ฐ ํ์
์คํฌ๋ฆฝํธ๋ฅผ ์ธ์ํ ์ ์๊ฒ ๋ค์์ฒ๋ผ ์ค์นํฉ๋๋ค.
Install the following so that VS Code or your editor can recognize TypeScript.
npm install -D @types/react @types/node
๐ ํ๊ทธ ๊ตฌ์กฐ / Tag structure
โ๏ธ ์นด๋ ๋ถ๋ถ์ HTML๊ธฐ๋ณธ ๊ตฌ์กฐ๋ ์๋์ ๊ฐ์ต๋๋ค.
The basic HTML structure for the card section is as follows.
โ๏ธ ์ฌ๊ธฐ์ ์ค์ํ๊ฒ๋ด์ผํ๋๊ฑด ๊ฐ ์์(div,p,button…)๋ค์ ๋ฐฐ์น ๋ถ๋ถ์
๋๋ค.
The key aspect to focus on here is the layout of the individual elements (div, p, button, etc.).
<main className="min-h-screen flex items-center justify-center bg-gray-50 p-4">
{/* ์นด๋ ์์ / Start Card */}
<div className="w-full max-w-sm bg-white rounded-2xl shadow-lg overflow-hidden">
{/* ์ด๋ฏธ์ง ์์ญ / Image Area */}
<div className="h-48 bg-gradient-to-br from-blue-400 to-purple-500 flex items-center justify-center">
<span className="text-5xl">๐</span>
</div>
{/* ํ
์คํธ ์์ญ / Text area */}
<div className="p-6">
<div className="flex items-center justify-between">
<h2 className="text-xl font-bold text-gray-900">Freelifemakers</h2>
<span className="px-2 py-1 text-xs font-bold bg-blue-100 text-blue-600 rounded-full">NEW</span>
</div>
<p className="mt-2 text-sm text-gray-400">
Next.js + Tailwind๋ก ๋ง๋ ์๊ฐ ์นด๋์
๋๋ค.<br></br>
This is an introductory card built with Next.js and Tailwind.
</p>
{/* ๋ฒํผ / Button */}
<div className="mt-6 flex gap-3">
<button
onClick={() => setLiked(!liked)}
className={`flex-1 py-3 rounded-xl font-bold transition-all active:scale-95 ${liked ? 'bg-red-500 text-white' : 'bg-gray-100 text-gray-700 hover:bg-gray-200'}`}
>
{liked ? 'โค๏ธ ์ข์์/like' : '๐ค ์ข์์/like'}
</button>
<button className="flex-1 py-3 bg-blue-500 text-white rounded-xl font-bold shadow-md hover:bg-blue-600 hover:-translate-y-0.5 transition-all active:scale-95">
์์ํ๊ธฐ / Start
</button>
</div>
</div>
</div>
{/* ์นด๋ ๋ / card end */}
</main>
๐ ๊ฐ๋ก๋ฐฐ์น / Horizontal layout
โ๏ธ ๊ฐ ์์๋ค์ ๊ธฐ๋ณธ์ ์ผ๋ก ์ธ๋ก๋ก ๋ฐฐ์น๋ฉ๋๋ค.
Each element is arranged vertically by default.
โ๏ธ ์์๋ค์ ๋ฐฐ์น๋ฅผ ์ฝ๋๋ก ์กฐ์ ํ๋ ค๋ฉด flex๋ฅผ ์ฌ์ฉํฉ๋๋ค.
Use flex to adjust the layout of elements via code.
โ๏ธ ์นด๋๊ฐ ์์๋๋ ๋ถ๋ถ์ flex๋ฅผ ์ฌ์ฉํ์ง ์์ ๊ฒฝ์ฐ์
๋๋ค. ์ด ๊ฒฝ์ฐ ๊ธฐ๋ณธ ๊ฐ์ผ๋ก ๊ฐ ์์๋ ์ธ๋ก๋ก ๋ฐฐ์น๋ฉ๋๋ค.
This is a case where flex is not used at the start of the card. In this instance, the elements are arranged vertically by default.
{/* ์นด๋ ์์ / Start Card */}
<div className="w-full max-w-sm bg-white rounded-2xl shadow-lg overflow-hidden">
... ...
</div>

โ๏ธ flex๋ฅผ ์ฌ์ฉํ ๊ฒฝ์ฐ์ ๋๋ค. ์ด ๊ฒฝ์ฐ ์ด๋ฏธ์ง์ ํ ์คํธ๊ฐ ๊ฐ๋ก ๋ฐฐ์น๋๋ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค.
{/* ์นด๋ ์์ / Start Card */}
<div className="w-full flex max-w-sm bg-white rounded-2xl shadow-lg overflow-hidden">
... ...
</div>

๐ ์ธ๋ก๋ฐฐ์น / Vertical layout
โ๏ธ ๊ธฐ๋ณธ๊ฐ์ ์ธ๋ก ๋ฐฐ์น์ง๋ง ์ ๋ ฌ๊ธฐ๋ฅ์ ์ฌ์ฉํ๊ธฐ ์ํด์ flex-col๋ฅผ ์ฌ์ฉํฉ๋๋ค.
โ๏ธ ์๋์ฒ๋ผ ๋ฒํผ ๋ถ๋ถ์ ์๋ ์ฒ๋ผ flex-1๋ก ์ ์ฉํ๊ณ <div className=”mt-6 flex gap-3″> ์ด๋ ๊ฒ ์ ์ฉํ๋ฉด ๋ ์ด์์์ด ๊นจ์ง ์ ์์ต๋๋ค.
โ๏ธ flex-1 ๊ฐ๋ก ๋ชจ๋์์ ์์ดํ ์ด ์ฐจ์งํ๋ ๊ณต๊ฐ์ด 1:1 ๋น์จ๋ก ๋ฐฐ์นํ๋ ์ฝ๋์ ๋๋ค.
<button
onClick={() => setLiked(!liked)}
className={`flex-1 py-3 rounded-xl ... ... > ... ... </button>
โ๏ธ ๊ทธ๋์ ์ฝ๋๋ฅผ ๋ค์๊ณผ ๊ฐ์ด ๋ฐ๊ฟ๋๋ค. w-full์ ์์๊ฐ ์ ์ฒด ๊ณต๊ฐ์ ์ฐจ์งํ๊ฒ ํฉ๋๋ค.
โ๏ธ ๋ฒํผ์ด ๋๊ฐ ์๋ค๋ฉด ๊ฐ๋ก๋ชจ๋์์ w-full์ ์ ์ฉํ๋ฉด 1:1๋น์จ๋ก ๋ฐฐ์น๋๊ณ ์ธ๋ก ๋ชจ๋์์๋ ์ ์ฒด ๊ณต๊ฐ์ ์ฐจ์ง ํฉ๋๋ค.
<button
onClick={() => setLiked(!liked)}
className={`w-full py-3 rounded-xl ... ...> ... ... </button?
โ๏ธ ์๋๋ flex-col์ ์ด์ฉํด์ ์ธ๋ก ๋ฐฐ์น๋ฅผ ์ ์ฉํ ๋ชจ์ต์ ๋๋ค.
— ์ฝ๋ / Code
{/* ๋ฒํผ / Button */}
<div className="mt-6 flex-col gap-3">
<button
onClick={() => setLiked(!liked)}
className={`w-full py-3 rounded-xl font-bold transition-all active:scale-95 ${liked ? 'bg-red-500 text-white' : 'bg-gray-100 text-gray-700 hover:bg-gray-200'}`}
>
{liked ? 'โค๏ธ ์ข์์/like' : '๐ค ์ข์์/like'}
</button>
<button className="w-full py-3 bg-blue-500 text-white rounded-xl font-bold shadow-md hover:bg-blue-600 hover:-translate-y-0.5 transition-all active:scale-95">
์์ํ๊ธฐ / Start
</button>
</div>
{/* ๋ฒํผ flex / Button flex *}
<div className="mt-6 flex">
<button
onClick={() => setLiked(!liked)}
className={`w-full py-3 ${liked ? 'bg-red-500 text-white' : 'bg-gray-100 text-gray-700 hover:bg-gray-200'}`}
>
{liked ? 'โค๏ธ ์ข์์/like' : '๐ค ์ข์์/like'}
</button>
<button className="w-full py-3 bg-blue-500 ">
์์ํ๊ธฐ / Start
</button>
</div>

๐ก flex์์ ์ค์ ๊ฐ
1.flex
- ์์ ๊ฐ๋ก ๋ฐฐ์น / Horizontal element layout
2.flex-col
- ์์ ์ธ๋ก ๋ฐฐ์น / Vertical element arrangement
3.justify-center
- ๊ฐ๋ก ์ค์ ์ ๋ ฌ / Center-aligned horizontally
4.items-center
- ์ ์๋ ์ค์ ์ ๋ ฌ / Vercital center alignment
5.gap-3
- ์์ ์ฌ์ด ๊ฐ๊ฒฉ 12px / 12px spacing between elements
6.justify-between
- ์์๋ฅผ ์์ชฝ ๋์ผ๋ก ๋ฐฐ์น (ex. ์ ๋ชฉ์ ์ผ์ชฝ, ๋ฑ์ง๋ ์ค๋ฅธ์ชฝ)
Position elements at both ends (e.g., title on the left, badge on the right).
๐ CSS
โ๏ธ ์ธ๋ก ์ ๋ ฌ(๊ธฐ๋ณธ ๊ฐ) / Vertical alignment (default)
<style> ...
/* ์นด๋ ๋ณธ์ฒด / Card body */
.card {
width: 100%;
max-width: 384px; /* max-w-sm = 384px */
background-color: white;
border-radius: 16px; /* rounded-2xl */
box-shadow: 0 10px 15px rgba(0,0,0,0.1);
overflow: hidden;
} ...
</style>
โ๏ธ ๊ฐ๋ก์ ๋ ฌ / Horizontal alignment(flex)
<style> ...
.card-actions {
margin-top: 24px;
display: flex;
gap: 12px;
} ... ...
</style>
โ๏ธ ์ธ๋ก์ ๋ ฌ flex / Vertical alignment flex
<style> ...
.card-actions {
display: flex;
flex-direction: column; /* vertical */
gap: 12px;
} ... ...
</style>