CSS λ ˆμ΄μ•„μ›ƒ

CSS λ ˆμ΄μ•„μ›ƒ

κ°œμš”

CSS λ ˆμ΄μ•„μ›ƒμ€ μ›Ή νŽ˜μ΄μ§€μ˜ μš”μ†Œλ“€μ„ μ›ν•˜λŠ” μœ„μΉ˜μ— λ°°μΉ˜ν•˜λŠ” κΈ°μˆ μž…λ‹ˆλ‹€. ν˜„λŒ€ μ›Ή κ°œλ°œμ—μ„œλŠ” 주둜 Flexbox와 CSS Gridλ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€.

μ„ μˆ˜ 지식: 03_CSS_Basics.md


λͺ©μ°¨

  1. 전톡적 λ ˆμ΄μ•„μ›ƒ
  2. Flexbox
  3. CSS Grid
  4. Flexbox vs Grid
  5. Position
  6. μ‹€μ „ λ ˆμ΄μ•„μ›ƒ 예제

전톡적 λ ˆμ΄μ•„μ›ƒ

Float (λ ˆκ±°μ‹œ)

과거에 μ‚¬μš©λ˜λ˜ λ°©μ‹μœΌλ‘œ, ν˜„μž¬λŠ” ν…μŠ€νŠΈ 감싸기 μ •λ„μ—λ§Œ μ‚¬μš©ν•©λ‹ˆλ‹€.

.image {
    float: left;
    margin-right: 20px;
}

/* float ν•΄μ œ */
.clearfix::after {
    content: "";
    display: table;
    clear: both;
}

μ°Έκ³ : μƒˆ ν”„λ‘œμ νŠΈμ—μ„œλŠ” Flexboxλ‚˜ Gridλ₯Ό μ‚¬μš©ν•˜μ„Έμš”.


Flexbox

1차원 λ ˆμ΄μ•„μ›ƒ μ‹œμŠ€ν…œμœΌλ‘œ, ν–‰(row) λ˜λŠ” μ—΄(column) λ‹¨μœ„λ‘œ μš”μ†Œλ₯Ό λ°°μΉ˜ν•©λ‹ˆλ‹€.

κΈ°λ³Έ κ°œλ…

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Flex Container                          β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”       β”‚
β”‚  β”‚ Flex   β”‚ β”‚ Flex   β”‚ β”‚ Flex   β”‚       β”‚
β”‚  β”‚ Item 1 β”‚ β”‚ Item 2 β”‚ β”‚ Item 3 β”‚       β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜       β”‚
β”‚  ◄─────────── main axis ──────────►     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
       β–²
       β”‚ cross axis
       β–Ό

Flex Container 속성

.container {
    display: flex;  /* λ˜λŠ” inline-flex */
}

flex-direction

μ£Ό μΆ•(main axis) λ°©ν–₯을 μ„€μ •ν•©λ‹ˆλ‹€.

.container {
    flex-direction: row;            /* κΈ°λ³Έκ°’: 쒌 β†’ 우 */
    flex-direction: row-reverse;    /* 우 β†’ 쒌 */
    flex-direction: column;         /* μœ„ β†’ μ•„λž˜ */
    flex-direction: column-reverse; /* μ•„λž˜ β†’ μœ„ */
}
row:            row-reverse:      column:         column-reverse:
[1][2][3]       [3][2][1]         [1]             [3]
                                  [2]             [2]
                                  [3]             [1]

flex-wrap

μ€„λ°”κΏˆ μ„€μ •μž…λ‹ˆλ‹€.

.container {
    flex-wrap: nowrap;       /* κΈ°λ³Έκ°’: ν•œ 쀄에 λͺ¨λ‘ 배치 */
    flex-wrap: wrap;         /* λ„˜μΉ˜λ©΄ λ‹€μŒ μ€„λ‘œ */
    flex-wrap: wrap-reverse; /* μ—­λ°©ν–₯으둜 μ€„λ°”κΏˆ */
}

flex-flow (단좕 속성)

.container {
    flex-flow: row wrap;  /* direction + wrap */
}

justify-content

μ£Ό μΆ• μ •λ ¬ (κ°€λ‘œ λ°©ν–₯ μ •λ ¬, flex-direction: row κΈ°μ€€)

.container {
    justify-content: flex-start;    /* κΈ°λ³Έκ°’: μ‹œμž‘μ  μ •λ ¬ */
    justify-content: flex-end;      /* 끝점 μ •λ ¬ */
    justify-content: center;        /* 쀑앙 μ •λ ¬ */
    justify-content: space-between; /* 양끝 μ •λ ¬, 사이 κ· λ“± */
    justify-content: space-around;  /* 각 μš”μ†Œ μ£Όλ³€ κ· λ“± */
    justify-content: space-evenly;  /* μ™„μ „ κ· λ“± 배치 */
}
flex-start:     [1][2][3]
flex-end:                  [1][2][3]
center:              [1][2][3]
space-between:  [1]      [2]      [3]
space-around:    [1]    [2]    [3]
space-evenly:    [1]    [2]    [3]

align-items

ꡐ차 μΆ• μ •λ ¬ (μ„Έλ‘œ λ°©ν–₯ μ •λ ¬, flex-direction: row κΈ°μ€€)

.container {
    align-items: stretch;    /* κΈ°λ³Έκ°’: λŠ˜λ €μ„œ 채움 */
    align-items: flex-start; /* μ‹œμž‘μ  μ •λ ¬ */
    align-items: flex-end;   /* 끝점 μ •λ ¬ */
    align-items: center;     /* 쀑앙 μ •λ ¬ */
    align-items: baseline;   /* ν…μŠ€νŠΈ κΈ°μ€€μ„  μ •λ ¬ */
}
stretch:     flex-start:   flex-end:    center:      baseline:
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ [1][2] β”‚   β”‚ [1][2] β”‚   β”‚        β”‚   β”‚        β”‚   β”‚Text    β”‚
β”‚        β”‚   β”‚        β”‚   β”‚        β”‚   β”‚ [1][2] β”‚   β”‚  [1][2]β”‚
β”‚        β”‚   β”‚        β”‚   β”‚ [1][2] β”‚   β”‚        β”‚   β”‚        β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜

align-content

μ—¬λŸ¬ 쀄일 λ•Œ 쀄 간격 μ •λ ¬ (flex-wrap: wrap ν•„μš”)

.container {
    align-content: flex-start;
    align-content: flex-end;
    align-content: center;
    align-content: space-between;
    align-content: space-around;
    align-content: stretch;  /* κΈ°λ³Έκ°’ */
}

gap

μ•„μ΄ν…œ 사이 간격

.container {
    gap: 20px;           /* ν–‰κ³Ό μ—΄ λͺ¨λ‘ */
    gap: 10px 20px;      /* ν–‰ μ—΄ */
    row-gap: 10px;       /* ν–‰ κ°„κ²©λ§Œ */
    column-gap: 20px;    /* μ—΄ κ°„κ²©λ§Œ */
}

Flex Item 속성

flex-grow

남은 곡간을 μ°¨μ§€ν•˜λŠ” λΉ„μœ¨

.item {
    flex-grow: 0;  /* κΈ°λ³Έκ°’: λŠ˜μ–΄λ‚˜μ§€ μ•ŠμŒ */
    flex-grow: 1;  /* 남은 곡간 1만큼 μ°¨μ§€ */
    flex-grow: 2;  /* 남은 곡간 2만큼 μ°¨μ§€ */
}
flex-grow: 0 0 0    [1][2][3]
flex-grow: 1 1 1    [  1  ][  2  ][  3  ]
flex-grow: 1 2 1    [ 1 ][    2    ][ 3 ]

flex-shrink

곡간 λΆ€μ‘± μ‹œ μ€„μ–΄λ“œλŠ” λΉ„μœ¨

.item {
    flex-shrink: 1;  /* κΈ°λ³Έκ°’: λΉ„μœ¨λŒ€λ‘œ 쀄어듦 */
    flex-shrink: 0;  /* 쀄어듀지 μ•ŠμŒ */
}

flex-basis

κΈ°λ³Έ 크기 μ„€μ •

.item {
    flex-basis: auto;  /* κΈ°λ³Έκ°’: μ½˜ν…μΈ  크기 */
    flex-basis: 200px; /* κ³ μ • 크기 */
    flex-basis: 25%;   /* λΉ„μœ¨ */
}

flex (단좕 속성)

.item {
    flex: 0 1 auto;    /* κΈ°λ³Έκ°’: grow shrink basis */
    flex: 1;           /* flex: 1 1 0 */
    flex: auto;        /* flex: 1 1 auto */
    flex: none;        /* flex: 0 0 auto */
}

align-self

κ°œλ³„ μ•„μ΄ν…œμ˜ ꡐ차 μΆ• μ •λ ¬

.item {
    align-self: auto;       /* κΈ°λ³Έκ°’: λΆ€λͺ¨μ˜ align-items 따름 */
    align-self: flex-start;
    align-self: flex-end;
    align-self: center;
    align-self: stretch;
}

order

배치 μˆœμ„œ λ³€κ²½

.item1 { order: 2; }
.item2 { order: 1; }
.item3 { order: 3; }
/* ν™”λ©΄: [2][1][3] */

Flexbox μ‹€μ „ νŒ¨ν„΄

μ™„λ²½ν•œ 쀑앙 μ •λ ¬

.container {
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100vh;
}

λ„€λΉ„κ²Œμ΄μ…˜ λ°”

.navbar {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 1rem 2rem;
}

.nav-links {
    display: flex;
    gap: 2rem;
}
<nav class="navbar">
    <div class="logo">Logo</div>
    <ul class="nav-links">
        <li><a href="#">Home</a></li>
        <li><a href="#">About</a></li>
        <li><a href="#">Contact</a></li>
    </ul>
</nav>

μΉ΄λ“œ λ ˆμ΄μ•„μ›ƒ

.card-container {
    display: flex;
    flex-wrap: wrap;
    gap: 1rem;
}

.card {
    flex: 1 1 300px;  /* μ΅œμ†Œ 300px, κ· λ“± λΆ„λ°° */
    max-width: 400px;
}
body {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}

main {
    flex: 1;  /* 남은 곡간 λͺ¨λ‘ μ°¨μ§€ */
}

footer {
    /* μžλ™μœΌλ‘œ μ•„λž˜μ— μœ„μΉ˜ */
}

CSS Grid

2차원 λ ˆμ΄μ•„μ›ƒ μ‹œμŠ€ν…œμœΌλ‘œ, ν–‰κ³Ό 열을 λ™μ‹œμ— μ œμ–΄ν•©λ‹ˆλ‹€.

κΈ°λ³Έ κ°œλ…

      column 1   column 2   column 3
      ◄──────►  ◄──────►  ◄──────►
    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β–²
row β”‚    1    β”‚    2    β”‚    3    β”‚  β”‚ row 1
 1  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β–Ό
    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β–²
row β”‚    4    β”‚    5    β”‚    6    β”‚  β”‚ row 2
 2  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β–Ό

Grid Container 속성

.container {
    display: grid;  /* λ˜λŠ” inline-grid */
}

grid-template-columns / grid-template-rows

μ—΄κ³Ό ν–‰μ˜ 크기λ₯Ό μ •μ˜ν•©λ‹ˆλ‹€.

.container {
    /* κ³ μ • 크기 */
    grid-template-columns: 100px 200px 100px;

    /* λΉ„μœ¨ (fr: fraction) */
    grid-template-columns: 1fr 2fr 1fr;

    /* ν˜Όν•© */
    grid-template-columns: 200px 1fr 1fr;

    /* repeat ν•¨μˆ˜ */
    grid-template-columns: repeat(3, 1fr);      /* 1fr 1fr 1fr */
    grid-template-columns: repeat(4, 100px);    /* 100px 100px 100px 100px */

    /* auto-fill / auto-fit */
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}
/* ν–‰ μ •μ˜ */
.container {
    grid-template-rows: 100px 200px;
    grid-template-rows: 1fr 2fr;
    grid-template-rows: auto 1fr auto;  /* header, main, footer */
}

auto-fill vs auto-fit

/* auto-fill: 빈 열도 μœ μ§€ */
grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));

/* auto-fit: 빈 열은 μΆ•μ†Œ */
grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
3개 μ•„μ΄ν…œ, μ»¨ν…Œμ΄λ„ˆ λ„“μŒ:
auto-fill: [1][2][3][  ][  ]  (빈 곡간 μœ μ§€)
auto-fit:  [  1  ][  2  ][  3  ]  (μ•„μ΄ν…œμ΄ ν™•μž₯)

gap

.container {
    gap: 20px;           /* ν–‰κ³Ό μ—΄ λͺ¨λ‘ */
    gap: 10px 20px;      /* ν–‰ μ—΄ */
    row-gap: 10px;
    column-gap: 20px;
}

justify-items / align-items

μ…€ λ‚΄λΆ€μ—μ„œ μ•„μ΄ν…œ μ •λ ¬

.container {
    /* κ°€λ‘œ μ •λ ¬ */
    justify-items: start;   /* μ™Όμͺ½ */
    justify-items: end;     /* 였λ₯Έμͺ½ */
    justify-items: center;  /* 쀑앙 */
    justify-items: stretch; /* κΈ°λ³Έκ°’: 늘림 */

    /* μ„Έλ‘œ μ •λ ¬ */
    align-items: start;
    align-items: end;
    align-items: center;
    align-items: stretch;

    /* 단좕 속성 */
    place-items: center center;  /* align justify */
}

justify-content / align-content

κ·Έλ¦¬λ“œ 전체λ₯Ό μ»¨ν…Œμ΄λ„ˆ λ‚΄μ—μ„œ μ •λ ¬

.container {
    justify-content: start;
    justify-content: end;
    justify-content: center;
    justify-content: space-between;
    justify-content: space-around;
    justify-content: space-evenly;

    align-content: start;
    align-content: end;
    align-content: center;

    /* 단좕 속성 */
    place-content: center center;
}

grid-template-areas

μ΄λ¦„μœΌλ‘œ μ˜μ—­μ„ μ •μ˜ν•©λ‹ˆλ‹€.

.container {
    display: grid;
    grid-template-columns: 200px 1fr 200px;
    grid-template-rows: auto 1fr auto;
    grid-template-areas:
        "header header header"
        "sidebar main aside"
        "footer footer footer";
}

.header  { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main    { grid-area: main; }
.aside   { grid-area: aside; }
.footer  { grid-area: footer; }
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚            header              β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚sidebar β”‚     main     β”‚ aside  β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚            footer              β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

빈 곡간은 .으둜 ν‘œμ‹œ:

grid-template-areas:
    "header header ."
    "sidebar main main"
    "footer footer footer";

Grid Item 속성

grid-column / grid-row

μ•„μ΄ν…œμ΄ μ°¨μ§€ν•˜λŠ” μ˜μ—­μ„ μ§€μ •ν•©λ‹ˆλ‹€.

.item {
    /* μ‹œμž‘ 라인 / 끝 라인 */
    grid-column: 1 / 3;     /* 1λ²ˆλΆ€ν„° 3번 λΌμΈκΉŒμ§€ (2μΉΈ) */
    grid-row: 1 / 2;        /* 1λ²ˆλΆ€ν„° 2번 λΌμΈκΉŒμ§€ (1μΉΈ) */

    /* span ν‚€μ›Œλ“œ */
    grid-column: 1 / span 2;  /* 1λ²ˆλΆ€ν„° 2μΉΈ */
    grid-column: span 2;      /* ν˜„μž¬ μœ„μΉ˜μ—μ„œ 2μΉΈ */

    /* λμ—μ„œλΆ€ν„° */
    grid-column: 1 / -1;      /* 첫 λ²ˆμ§ΈλΆ€ν„° λ§ˆμ§€λ§‰κΉŒμ§€ */
}
라인 번호:
    1     2     3     4
    β–Ό     β–Ό     β–Ό     β–Ό
    β”Œβ”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”
1 β–Ί β”‚  1  β”‚  2  β”‚  3  β”‚
    β”œβ”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€
2 β–Ί β”‚  4  β”‚  5  β”‚  6  β”‚
    β””β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”˜
3 β–Ί

justify-self / align-self

κ°œλ³„ μ•„μ΄ν…œ μ •λ ¬

.item {
    justify-self: start;
    justify-self: end;
    justify-self: center;
    justify-self: stretch;

    align-self: start;
    align-self: end;
    align-self: center;
    align-self: stretch;

    /* 단좕 속성 */
    place-self: center center;
}

Grid μ‹€μ „ νŒ¨ν„΄

12μ—΄ κ·Έλ¦¬λ“œ μ‹œμŠ€ν…œ

.grid-12 {
    display: grid;
    grid-template-columns: repeat(12, 1fr);
    gap: 1rem;
}

.col-6 { grid-column: span 6; }
.col-4 { grid-column: span 4; }
.col-3 { grid-column: span 3; }
.col-2 { grid-column: span 2; }

λ°˜μ‘ν˜• μΉ΄λ“œ κ·Έλ¦¬λ“œ

.card-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    gap: 1.5rem;
}

Holy Grail λ ˆμ΄μ•„μ›ƒ

.layout {
    display: grid;
    grid-template-columns: 200px 1fr 200px;
    grid-template-rows: auto 1fr auto;
    grid-template-areas:
        "header header header"
        "nav main aside"
        "footer footer footer";
    min-height: 100vh;
}

이미지 가러리 (λΆˆκ·œμΉ™ κ·Έλ¦¬λ“œ)

.gallery {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    grid-auto-rows: 200px;
    gap: 10px;
}

.gallery-item.wide {
    grid-column: span 2;
}

.gallery-item.tall {
    grid-row: span 2;
}

.gallery-item.big {
    grid-column: span 2;
    grid-row: span 2;
}

Flexbox vs Grid

μ–Έμ œ 무엇을 μ‚¬μš©ν• κΉŒ?

상황 μΆ”μ²œ
ν•œ λ°©ν–₯ μ •λ ¬ (κ°€λ‘œ OR μ„Έλ‘œ) Flexbox
λ„€λΉ„κ²Œμ΄μ…˜ λ°” Flexbox
λ²„νŠΌ κ·Έλ£Ή Flexbox
μΉ΄λ“œ λ‚΄λΆ€ λ ˆμ΄μ•„μ›ƒ Flexbox
2차원 λ ˆμ΄μ•„μ›ƒ (ν–‰ + μ—΄) Grid
전체 νŽ˜μ΄μ§€ λ ˆμ΄μ•„μ›ƒ Grid
μΉ΄λ“œ κ·Έλ¦¬λ“œ Grid
λΆˆκ·œμΉ™ν•œ λ ˆμ΄μ•„μ›ƒ Grid

ν•¨κ»˜ μ‚¬μš©ν•˜κΈ°

/* 전체 νŽ˜μ΄μ§€: Grid */
.page {
    display: grid;
    grid-template-columns: 250px 1fr;
    grid-template-rows: auto 1fr auto;
}

/* λ„€λΉ„κ²Œμ΄μ…˜: Flexbox */
.nav {
    display: flex;
    justify-content: space-between;
    align-items: center;
}

/* μΉ΄λ“œ μ»¨ν…Œμ΄λ„ˆ: Grid */
.cards {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
    gap: 1rem;
}

/* μΉ΄λ“œ λ‚΄λΆ€: Flexbox */
.card {
    display: flex;
    flex-direction: column;
}

.card-body {
    flex: 1;
}

Position

μš”μ†Œμ˜ μœ„μΉ˜ μ§€μ • 방식을 μ„€μ •ν•©λ‹ˆλ‹€.

position 속성값

.element {
    position: static;    /* κΈ°λ³Έκ°’: λ¬Έμ„œ νλ¦„λŒ€λ‘œ */
    position: relative;  /* μ›λž˜ μœ„μΉ˜ κΈ°μ€€μœΌλ‘œ 이동 */
    position: absolute;  /* 쑰상 μš”μ†Œ κΈ°μ€€μœΌλ‘œ 배치 */
    position: fixed;     /* 뷰포트 κΈ°μ€€μœΌλ‘œ κ³ μ • */
    position: sticky;    /* μŠ€ν¬λ‘€μ— 따라 κ³ μ • */
}

relative

μ›λž˜ μœ„μΉ˜λ₯Ό κΈ°μ€€μœΌλ‘œ μ΄λ™ν•©λ‹ˆλ‹€. μ›λž˜ 곡간은 μœ μ§€λ©λ‹ˆλ‹€.

.box {
    position: relative;
    top: 20px;     /* μ›λž˜ μœ„μΉ˜μ—μ„œ μ•„λž˜λ‘œ 20px */
    left: 30px;    /* μ›λž˜ μœ„μΉ˜μ—μ„œ 였λ₯Έμͺ½μœΌλ‘œ 30px */
}

absolute

κ°€μž₯ κ°€κΉŒμš΄ positioned(static이 μ•„λ‹Œ) 쑰상을 κΈ°μ€€μœΌλ‘œ λ°°μΉ˜λ©λ‹ˆλ‹€.

.parent {
    position: relative;  /* 기쀀점 μ—­ν•  */
}

.child {
    position: absolute;
    top: 0;
    right: 0;  /* λΆ€λͺ¨μ˜ 였λ₯Έμͺ½ μœ„ λͺ¨μ„œλ¦¬μ— 배치 */
}
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ parent      [X] β”‚  ← .child (absolute)
β”‚                 β”‚
β”‚                 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

fixed

뷰포트(ν™”λ©΄)λ₯Ό κΈ°μ€€μœΌλ‘œ κ³ μ •λ©λ‹ˆλ‹€. μŠ€ν¬λ‘€ν•΄λ„ 움직이지 μ•ŠμŠ΅λ‹ˆλ‹€.

.header {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    height: 60px;
}

/* κ³ μ • 헀더 μ•„λž˜ 곡간 확보 */
body {
    padding-top: 60px;
}

sticky

슀크둀 μœ„μΉ˜μ— 따라 relative와 fixed 사이λ₯Ό μ „ν™˜ν•©λ‹ˆλ‹€.

.sticky-header {
    position: sticky;
    top: 0;  /* 상단에 λ‹ΏμœΌλ©΄ κ³ μ • */
    background: white;
    z-index: 100;
}
슀크둀 μ „:          슀크둀 ν›„:
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  header  β”‚       β”‚  sticky  β”‚ ← 상단에 κ³ μ •
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€       β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  sticky  β”‚       β”‚ content  β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€       β”‚          β”‚
β”‚ content  β”‚       β”‚          β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

z-index

μš”μ†Œμ˜ μŒ“μž„ μˆœμ„œλ₯Ό μ§€μ •ν•©λ‹ˆλ‹€. λ†’μ„μˆ˜λ‘ μœ„μ— ν‘œμ‹œλ©λ‹ˆλ‹€.

.modal-backdrop {
    position: fixed;
    z-index: 100;
}

.modal {
    position: fixed;
    z-index: 101;  /* backdrop μœ„μ— ν‘œμ‹œ */
}

.tooltip {
    position: absolute;
    z-index: 200;  /* λͺ¨λ‹¬ μœ„μ—λ„ ν‘œμ‹œ */
}

μœ„μΉ˜ μ§€μ • 속성

.element {
    top: 10px;      /* μœ„μ—μ„œλΆ€ν„° 거리 */
    right: 10px;    /* 였λ₯Έμͺ½μ—μ„œλΆ€ν„° 거리 */
    bottom: 10px;   /* μ•„λž˜μ—μ„œλΆ€ν„° 거리 */
    left: 10px;     /* μ™Όμͺ½μ—μ„œλΆ€ν„° 거리 */

    /* κ°€μš΄λ° 배치 */
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);

    /* 꽉 μ±„μš°κΈ° */
    inset: 0;  /* top/right/bottom/left λͺ¨λ‘ 0 */
}

μ‹€μ „ λ ˆμ΄μ•„μ›ƒ 예제

κΈ°λ³Έ νŽ˜μ΄μ§€ λ ˆμ΄μ•„μ›ƒ

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>λ ˆμ΄μ•„μ›ƒ 예제</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            display: grid;
            grid-template-rows: auto 1fr auto;
            min-height: 100vh;
        }

        /* 헀더 */
        header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 1rem 2rem;
            background: #333;
            color: white;
        }

        nav ul {
            display: flex;
            gap: 2rem;
            list-style: none;
        }

        nav a {
            color: white;
            text-decoration: none;
        }

        /* 메인 */
        main {
            display: grid;
            grid-template-columns: 250px 1fr;
            gap: 2rem;
            padding: 2rem;
            max-width: 1200px;
            margin: 0 auto;
            width: 100%;
        }

        aside {
            background: #f5f5f5;
            padding: 1rem;
            border-radius: 8px;
        }

        .content {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
            gap: 1.5rem;
        }

        .card {
            background: white;
            border: 1px solid #ddd;
            border-radius: 8px;
            padding: 1.5rem;
            display: flex;
            flex-direction: column;
        }

        .card-body {
            flex: 1;
        }

        /* ν‘Έν„° */
        footer {
            background: #333;
            color: white;
            text-align: center;
            padding: 1rem;
        }
    </style>
</head>
<body>
    <header>
        <div class="logo">Logo</div>
        <nav>
            <ul>
                <li><a href="#">Home</a></li>
                <li><a href="#">About</a></li>
                <li><a href="#">Services</a></li>
                <li><a href="#">Contact</a></li>
            </ul>
        </nav>
    </header>

    <main>
        <aside>
            <h3>μ‚¬μ΄λ“œλ°”</h3>
            <ul>
                <li>메뉴 1</li>
                <li>메뉴 2</li>
                <li>메뉴 3</li>
            </ul>
        </aside>

        <section class="content">
            <article class="card">
                <h2>μΉ΄λ“œ 1</h2>
                <div class="card-body">
                    <p>μΉ΄λ“œ λ‚΄μš©μž…λ‹ˆλ‹€.</p>
                </div>
                <button>더 보기</button>
            </article>
            <article class="card">
                <h2>μΉ΄λ“œ 2</h2>
                <div class="card-body">
                    <p>μΉ΄λ“œ λ‚΄μš©μž…λ‹ˆλ‹€.</p>
                </div>
                <button>더 보기</button>
            </article>
            <article class="card">
                <h2>μΉ΄λ“œ 3</h2>
                <div class="card-body">
                    <p>μΉ΄λ“œ λ‚΄μš©μž…λ‹ˆλ‹€.</p>
                </div>
                <button>더 보기</button>
            </article>
        </section>
    </main>

    <footer>
        <p>&copy; 2024 My Website</p>
    </footer>
</body>
</html>

λͺ¨λ‹¬ λ ˆμ΄μ•„μ›ƒ

.modal-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.5);
    display: flex;
    justify-content: center;
    align-items: center;
    z-index: 1000;
}

.modal {
    background: white;
    padding: 2rem;
    border-radius: 12px;
    max-width: 500px;
    width: 90%;
    max-height: 90vh;
    overflow-y: auto;
    position: relative;
}

.modal-close {
    position: absolute;
    top: 1rem;
    right: 1rem;
}

κ³ μ • μ‚¬μ΄λ“œλ°” + 슀크둀 μ½˜ν…μΈ 

.app {
    display: grid;
    grid-template-columns: 250px 1fr;
    height: 100vh;
}

.sidebar {
    background: #2c3e50;
    overflow-y: auto;
}

.main-content {
    overflow-y: auto;
    padding: 2rem;
}

μ—°μŠ΅ 문제

문제 1: Flexbox둜 λ„€λΉ„κ²Œμ΄μ…˜ λ§Œλ“€κΈ°

λ‘œκ³ λŠ” μ™Όμͺ½, λ©”λ‰΄λŠ” 쀑앙, λ²„νŠΌμ€ 였λ₯Έμͺ½μ— λ°°μΉ˜ν•˜μ„Έμš”.

[Logo]      [Menu1] [Menu2] [Menu3]      [Login]
μ •λ‹΅ 보기
.navbar {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 1rem 2rem;
}

.nav-menu {
    display: flex;
    gap: 2rem;
}

문제 2: Grid둜 사진 가러리 λ§Œλ“€κΈ°

4μ—΄ κ·Έλ¦¬λ“œμ—μ„œ 첫 번째 μ΄λ―Έμ§€λ§Œ 2x2 크기둜 λ§Œλ“œμ„Έμš”.

μ •λ‹΅ 보기
.gallery {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 10px;
}

.gallery-item:first-child {
    grid-column: span 2;
    grid-row: span 2;
}

문제 3: μ™„λ²½ν•œ 쀑앙 μ •λ ¬

divλ₯Ό ν™”λ©΄ 정쀑앙에 λ°°μΉ˜ν•˜μ„Έμš” (3κ°€μ§€ 방법).

μ •λ‹΅ 보기
/* 방법 1: Flexbox */
.container {
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100vh;
}

/* 방법 2: Grid */
.container {
    display: grid;
    place-items: center;
    height: 100vh;
}

/* 방법 3: Position + Transform */
.container {
    position: relative;
    height: 100vh;
}
.box {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
}

λ‹€μŒ 단계

  • 05_CSS_Responsive.md - λ―Έλ””μ–΄ 쿼리와 λ°˜μ‘ν˜• λ””μžμΈ

참고 자료

to navigate between lessons