π λ μ΄μμμ κ°μ λ‘ λ°μμν€λ CSS μμ± λ¨μ©: λλ λκΈ°λ μ λλ©μ΄μ κ³Ό μ±λ₯ μ ν
Summary
μ¦μ λ μ΄μμ μ¬κ³μ°κ³Ό νμΈνΈ μμ
μ μΉ μ±λ₯μ μ νμν€κ³ UIλ₯Ό λ²λ²
κ±°λ¦¬κ² λ§λλλ€. transform
κ³Ό opacity
κ°μ μμ±μ μ¬μ©νμ¬ λ μ΄μμκ³Ό νμΈνΈλ₯Ό 건λλ°κ³ GPU κ°μμ νμ©νλ κ²μ΄ λΆλλ¬μ΄ μ λλ©μ΄μ
κ³Ό μ΅μ μ μ±λ₯μ μν ν΅μ¬μ
λλ€.
Why Wrong?
CSS μ λλ©μ΄μ
μ΄λ λμ μΈ UI λ³νλ₯Ό ꡬνν λ left
, top
, width
, height
, margin
, padding
λ± λ μ΄μμμ μ¬κ³μ°νκ³ νμΈνΈλ₯Ό μ λ°νλ μμ±μ κ³Όλνκ² μ¬μ©νλ©΄ λΈλΌμ°μ μ λ λλ§ νμ΄νλΌμΈμμ Layout(λ μ΄μμ) λ° Paint(νμΈνΈ) λ¨κ³λ₯Ό κ°μ λ‘ λ°μμν΅λλ€. μ΄ λ λ¨κ³λ λ§€μ° λΉμ©μ΄ λ§μ΄ λλ μμ
μΌλ‘, νΉν μ λλ©μ΄μ
μ΄λ μ€ν¬λ‘€ μ΄λ²€νΈμ κ°μ΄ λΉλ²ν λ³νκ° μΌμ΄λ λλ§λ€ λ°λ³΅λλ©΄ λ©μΈ μ€λ λλ₯Ό λΈλ‘νμ¬ UIκ° λ²λ²
κ±°λ¦¬κ³ 'λλ λκΈ°λ' λ―ν μ¬μ©μ κ²½νμ μ΄λν©λλ€. μ΄λ **λ μ΄μμ μ€λμ±(Layout Thrashing)**μΌλ‘ μ΄μ΄μ Έ μ λ°μ μΈ μΉ μ ν리μΌμ΄μ
μ μ±λ₯μ μ¬κ°νκ² μ νμν΅λλ€. λΈλΌμ°μ λ CSS μμ± λ³κ²½ μ Style(μ€νμΌ κ³μ°) β Layout(λ μ΄μμ κ³μ°) β Paint(νμΈνΈ) β Composite(ν©μ±)μ κ³Όμ μ κ±°μΉλλ°, left
λ width
μ κ°μ μμ± λ³κ²½μ λ μ΄μμμ μν₯μ λ―Έμ³ μμ Layout λ° Paint λ¨κ³λ₯Ό λ°λμ κ±°μΉκ² λ§λλλ€. λ°λ©΄, transform
μ΄λ opacity
μ κ°μ μμ±λ€μ λ μ΄μμμ μν₯μ μ£Όμ§ μμ Layout λ° Paint λ¨κ³λ₯Ό 건λλ°κ³ GPU κ°μμ νμ©ν μ μλ Composite λ¨κ³μμ μ²λ¦¬λ©λλ€.
How to Fix?
λΈλΌμ°μ μ λ λλ§ νμ΄νλΌμΈμ μ΄ν΄νκ³ , μ λλ©μ΄μ
μ΄λ λμ μΈ μμΉ/ν¬κΈ° λ³νμλ λΉμ©μ΄ μ κ² λλ CSS μμ±μ μ°μ μ μΌλ‘ μ¬μ©ν΄μΌ ν©λλ€. νΉν transform
(μ: translateX
, translateY
, scale
, rotate
) λ° opacity
μμ±μ λ μ΄μμκ³Ό νμΈνΈ λ¨κ³λ₯Ό 건λλ°κ³ GPU κ°μμ νμ©ν μ μλ Composite(ν©μ±) λ¨κ³μμ μ²λ¦¬λ©λλ€. μ΄λ₯Ό ν΅ν΄ λ©μΈ μ€λ λμ λΆνλ₯Ό μ€μ΄κ³ λ λΆλλ½κ³ μ±λ₯ μΉνμ μΈ μ λλ©μ΄μ
κ³Ό UI λ³νλ₯Ό ꡬνν μ μμ΅λλ€. λν, will-change
μμ±μ μ¬μ©νμ¬ λΈλΌμ°μ μκ² νΉμ μμμ μμ±μ΄ λ³κ²½λ κ²μμ 미리 μλ €μ£Όμ΄ μ΅μ νλ₯Ό μ λν μ μμ§λ§, λ¨μ©μ μ€νλ € μ±λ₯μ μ νμν¬ μ μμΌλ―λ‘ νμν κ³³μλ§ μ μ€νκ² μ¬μ©ν΄μΌ ν©λλ€.
Before Code (Bad)
/* Bad: 'left'μ 'top'μ λ μ΄μμ μ¬κ³μ°μ μ λ°ν©λλ€. */
.moving-box {
position: absolute;
left: 0;
top: 0;
transition: left 0.3s ease, top 0.3s ease;
}
.moving-box.animate {
left: 100px;
top: 50px;
}
/* Bad: 'width'μ 'height' λ³κ²½λ λ μ΄μμ μ¬κ³μ°μ μ λ°ν©λλ€. */
.resizing-element {
width: 100px;
height: 100px;
transition: width 0.3s ease, height 0.3s ease;
}
.resizing-element.enlarge {
width: 200px;
height: 200px;
}
After Code (Good)
/* Good: 'transform'μ λ μ΄μμ μ¬κ³μ° μμ΄ Composite λ¨κ³μμ μ²λ¦¬λ©λλ€. */
.moving-box {
transform: translate(0, 0);
transition: transform 0.3s ease;
}
.moving-box.animate {
transform: translate(100px, 50px);
}
/* Good: 'transform'μ scaleμ μ¬μ©νμ¬ ν¬κΈ° λ³νλ₯Ό μ΅μ νν©λλ€. */
.resizing-element {
transform: scale(1);
transition: transform 0.3s ease;
}
.resizing-element.enlarge {
transform: scale(2);
}
/* Good: μ λλ©μ΄μ
μ΄ μΌμ΄λ μμ±μ will-changeλ₯Ό μ μ©νμ¬ λΈλΌμ°μ μ ννΈλ₯Ό μ€λλ€. */
/* μ£Όμ: λ¨μ© μ μ€νλ € μ±λ₯ μ νλ₯Ό μ λ°ν μ μμΌλ―λ‘ νμν κ³³μλ§ μ μ€νκ² μ¬μ©ν©λλ€. */
.moving-box,
.resizing-element {
will-change: transform;
}