본문으로 건너뛰기

transform으로 옮기고 키우기

HTML·CSS 목차움직임과 다크 모드레슨 87 / 93

목차

transform은 요소의 그려진 모습을 옮기거나(translateY()) 키우는(scale()) CSS 속성입니다. 배치가 끝난 뒤 그리기에서만 하는 일이라, 요소의 원래 자리와 이웃 요소의 자리는 그대로입니다.

레시피 카드에 마우스를 올리면 살짝 떠오르게 하려 합니다. 바깥 여백으로 카드를 올리면 아래 카드까지 따라 올라가고, 너비를 늘려 키우면 옆 글이 밀려 읽던 목록이 흔들립니다. transform은 배치를 건드리지 않고 그려진 모습만 바꿔, 가리킨 카드만 움직이고 나머지는 그 자리에 둡니다. 이 레슨은 그려진 자리 · 크기와 배치 자리 · 크기가 어떻게 갈리는지를 봅니다.

그림 준비 중

1translateY()는 그려진 모습만 옮긴다

일반 흐름과 position · 기준 상자와 absolute에서 세운 규칙에 문장을 잇습니다.

브라우저 규칙 8. transform은 배치가 끝난 뒤 그려진 모습만 옮깁니다 — 자리는 그대로입니다.

240 × 100 카드를 위로 4px 옮깁니다. 아래 문단은 카드 바로 밑에 붙어 있습니다.

<div class="card">김치볶음밥</div>
<p>다음 문단</p>
.card {
  box-sizing: border-box;
  width: 240px;
  height: 100px;
  border: 1px solid #d2d2d7;
  transform: translateY(-4px);
}

p {
  margin: 0;
}
결과 화면
잰 값개발자 도구에서 본 값
  • .card의 위 자리4px
  • .card의 배치 위 자리8px
  • p의 위 자리108px

카드는 페이지 위에서 4px에 그려졌지만, 배치 위 자리는 transform이 없을 때와 같은 8px(body의 바깥 여백)입니다. 아래 문단도 카드의 원래 자리를 보고 놓여 108px 그대로입니다 — 카드가 올라가 생긴 4px 틈을 채우러 올라오지 않습니다.

translateY() 안의 값그려지는 쪽
음수(-4px)원래 자리보다 위
0원래 자리
양수(4px)원래 자리보다 아래

가로로 옮기는 것은 translateX()입니다 — 양수면 오른쪽, 음수면 왼쪽입니다. transform은 블록 · 인라인 블록 상자에 먹고, 링크 a처럼 글을 담는 인라인에는 먹지 않습니다 — 링크를 옮기려면 display: inline-block⁠을 함께 줍니다.

2scale()은 그려진 크기만 키운다

scale() 안의 숫자는 배율입니다. scale(1.02)는 가로 · 세로를 각각 1.02배로 그리고, 단위를 붙이지 않습니다. 따로 정하지 않으면 상자의 가운데를 기준으로 커집니다.

<div class="card">김치볶음밥</div>
<p>다음 문단</p>
.card {
  box-sizing: border-box;
  width: 240px;
  height: 100px;
  border: 1px solid #d2d2d7;
  transform: scale(1.02);
}

p {
  margin: 0;
}
결과 화면
잰 값개발자 도구에서 본 값
  • .card의 너비244.8px
  • .card의 배치 너비240px
  • p의 위 자리108px

'너비'는 그려진 너비라 240 × 1.02 = 244.8입니다. '배치 너비'는 배치에 쓴 너비라 240 그대로이고, 아래 문단도 그대로입니다. 카드는 위아래로 1px씩 커져 문단 위를 조금 덮었습니다. scale(1)은 원래 크기의 1배라 아무것도 바뀌지 않습니다.

3옮기기와 키우기를 한 줄에

옮기기와 키우기를 함께 하려면 한 선언에 빈칸으로 이어 적습니다. 줄이 넘치면 함수마다 한 줄에 씁니다. 앞 레슨의 전환을 붙이면 카드가 0.18초 동안 떠오르며 커집니다.

<div class="card">김치볶음밥</div>
<div>다음 글</div>
.card {
  box-sizing: border-box;
  width: 240px;
  height: 100px;
  border: 1px solid #d2d2d7;
  transition:
    transform 180ms ease;
}

.card:hover {
  transform:
    translateY(-4px)
    scale(1.02);
}
결과 화면
잰 값개발자 도구에서 본 값
  • .card의 위 자리3px
  • .card의 너비244.8px
  • .card + div의 위 자리108px

카드는 4px 올라가고 가운데에서 1px 더 커져 3px에 그려집니다. transform이 이어 그리기에 알맞은 까닭도 여기 있습니다 — 배치가 그대로라, 0.18초 동안 브라우저가 이웃을 다시 놓을 일이 없습니다.

예제

레시피 카드 떠오르기

레시피 목록의 카드에 마우스를 올리면 위로 4px 떠오르게 합니다. 아래 잰 값은 첫 카드에 마우스를 올리고 전환이 끝난 뒤의 값입니다.

<div class="recipe-card">
  김치볶음밥
</div>
<div class="recipe-card">
  계란말이
</div>
.recipe-card {
  box-sizing: border-box;
  width: 240px;
  height: 100px;
  margin-bottom: 16px;
  border: 1px solid #d2d2d7;
  transition:
    transform 180ms ease;
}

.recipe-card:hover {
  transform: translateY(-4px);
}
결과 화면
잰 값개발자 도구에서 본 값
  • .recipe-card의 위 자리4px
  • .recipe-card의 배치 위 자리8px
  • .recipe-card + .recipe-card의 위 자리124px

첫 카드만 4px 떠오르고, 둘째 카드는 8 + 100 + 16 = 124px 그대로입니다. 결과 화면의 카드에 마우스를 올렸다 떼며 봅니다.

자주 틀리는 곳

틀린 생각: transform으로 옮기면 자리도 옮겨져 이웃이 비켜 준다.

<div class="card">김치볶음밥</div>
<p>다음 문단</p>
.card {
  box-sizing: border-box;
  height: 100px;
  border: 1px solid #d2d2d7;
  background-color: #ffffff;
  transform: translateY(30px);
}

p {
  margin: 0;
}
결과 화면
잰 값개발자 도구에서 본 값
  • p의 위 자리108px
  • p의 맨 위 요소div.card

카드를 30px 내렸더니 아래 문단 위에 겹쳤습니다. 문단은 108px 그대로이고, 문단 가운데 자리에는 카드가 맨 위에 그려졌습니다. 자리가 옮겨졌다면 문단이 30px 비켜났을 것입니다.

맞는 규칙: transform은 그려진 모습만 옮깁니다. 이웃은 원래 자리를 보고 놓여 비켜 주지 않으니, 옮긴 쪽에 다른 내용이 있으면 겹칩니다(브라우저 규칙 8).

틀린 생각: transform을 두 줄로 쓰면 둘이 합쳐진다.

<div class="card">김치볶음밥</div>
.card {
  width: 240px;
  height: 100px;
  transform: translateY(-4px);
  transform: scale(1.02);
}
결과 화면
잰 값개발자 도구에서 본 값
  • .card의 위 자리7px

카드는 올라가지 않고 커지기만 했습니다(8 − 1 = 7). 두 선언은 한 속성 transform을 두고 겨뤄 나중 것이 이깁니다(브라우저 규칙 5).

맞는 규칙: 함께 할 일은 3절처럼 한 선언에 빈칸으로 잇습니다.

틀린 생각: 카드를 올리는 데는 margin-top이나 top을 써도 같다.

<div class="card">김치볶음밥</div>
<p>다음 문단</p>
.card {
  box-sizing: border-box;
  width: 240px;
  height: 100px;
  border: 1px solid #d2d2d7;
  margin-top: -4px;
}

p {
  margin: 0;
}
결과 화면
잰 값개발자 도구에서 본 값
  • .card의 위 자리4px
  • p의 위 자리104px

바깥 여백은 배치의 일이라 카드와 함께 아래 문단도 4px 따라 올라갔습니다. 목록이라면 아래 카드가 모두 움직입니다. top: -4px은 position이 처음 값 static이면 아무 일도 하지 않고, position: relative와 함께 쓰면 이웃은 그대로지만 배치에서 자리를 옮긴 것이라 배치 위 자리가 바뀝니다(14단원 일반 흐름과 position).

맞는 규칙: 마우스를 올렸을 때처럼 잠깐 보이는 움직임은 transform으로 합니다. 배치를 다시 하지 않아 이웃이 흔들리지 않습니다.

확인 문제

1. 예제에서 .recipe-card:hover의 값을 scale(1.05)로 바꿉니다. 마우스를 올린 첫 카드의 너비와 배치 너비는 각각 몇 px일까요? 숫자만 쓰세요.

힌트

2절에서 '너비'와 '배치 너비'가 각각 무엇을 재는지 찾아보세요.

정답

너비 252 · 배치 너비 240입니다.

<div class="recipe-card">
  김치볶음밥
</div>
.recipe-card {
  box-sizing: border-box;
  width: 240px;
  height: 100px;
  border: 1px solid #d2d2d7;
}

.recipe-card:hover {
  transform: scale(1.05);
}
결과 화면
잰 값개발자 도구에서 본 값
  • .recipe-card의 너비252px
  • .recipe-card의 배치 너비240px
  • 그려진 너비는 240 × 1.05 = 252입니다. 배치에 쓴 너비는 transform과 상관없이 240입니다.
  • 배치 너비도 252라고 썼다면 scale()이 상자 크기를 바꾼다고 본 것입니다.

2. 목록 링크에 마우스를 올리면 오른쪽으로 4px 옮겨 그리려 합니다. ____ 자리를 채우세요.

a:hover {
  transform: ____;
}
힌트

1절 표 아래 줄에서 가로로 옮기는 함수와 부호를 찾아보세요.

정답

translateX(4px)입니다.

<a href="list.html">목록</a>
a {
  display: inline-block;
}

a:hover {
  transform: translateX(4px);
}
결과 화면
잰 값개발자 도구에서 본 값
  • a의 왼쪽 자리12px
  • a의 배치 왼쪽 자리8px
  • 오른쪽은 양수입니다. translateX(-4px)은 왼쪽으로 옮깁니다.
  • 결과 화면에서 해 보려면 a에 display: inline-block⁠을 줍니다 — 인라인 상자에는 transform이 먹지 않습니다.

3. 동아리 공지 페이지입니다. 띠를 1.25배로 그렸을 때 아래 문단의 위 자리는 몇 px일까요?

<div class="band">신입 모집</div>
<p>모집은 금요일까지</p>
.band {
  width: 120px;
  height: 40px;
  margin-left: 40px;
  background-color: #fff3c4;
  transform: scale(1.25);
}

p {
  margin: 0;
}
  • ① 48px
  • ② 53px
  • ③ 58px
힌트

transform이 없을 때 문단이 놓이는 자리를 먼저 셈해 보세요 — body의 바깥 여백은 8px입니다.

힌트 둘

scale()이 바꾸는 것이 배치인지 그려진 모습인지 2절에서 찾아보세요.

정답

①입니다.

결과 화면
잰 값개발자 도구에서 본 값
  • p의 위 자리48px
  • .band의 높이50px
  • 문단은 띠의 원래 자리(8 + 40 = 48)를 보고 놓입니다. 띠는 50px 높이로 그려져 가운데에서 위아래로 5px씩 커지고, 문단 위 5px을 덮습니다.
  • ②는 커진 만큼 반을, ③은 커진 만큼 다 문단을 민다고 본 것입니다.

컴퓨터에서 해 보기(선택) — 점수에 들지 않습니다. 폰으로만 보고 있다면 건너뛰세요. 예제의 HTML과 CSS를 index.html과 style.css로 저장하고 link로 이어 엽니다(문서 뼈대의 body 안에 예제 HTML을 넣습니다). .recipe-card:hover의 값을 scale(1.1)로 바꿔 저장하고 새로고침합니다. 첫 카드에 마우스를 올려 둘째 카드가 밀리는지, 두 카드가 겹치는지 봅니다. 개발자 도구에서 첫 카드를 고르고 Computed 창의 width도 봅니다.

끝까지 내려오면 저절로 표시됩니다. 이 기기에만 저장합니다.

HTML·CSS 목차로