HTML 최소화란 무엇인가?
HTML 최소화는 브라우저의 렌더링 방식을 변경하지 않고 HTML 문서의 크기를 줄이는 과정입니다. HTML 압축기는 개발자의 가독성을 위해서만 존재하는 문자들을 제거합니다: 태그 사이의 공백, 주석, 선택적 닫힘 태그, 그리고 중복된 속성 값. 출력 결과는 소스와 기능적으로 동일하지만 바이트 크기가 더 작아, 사용자에게 더 빠른 다운로드와 빠른 최초 렌더링 시간을 제공합니다.
브라우저는 HTML을 DOM 트리로 파싱하는 과정에서 대부분의 공백을 버립니다. 두 div 태그 사이의 연속된 공백과 줄 바꿈은 렌더링된 페이지에 시각적 영향을 전혀 미치지 않습니다. 주석 또한 파서에 의해 무시됩니다. 최소화는 이러한 규칙을 활용하여 파서가 어차피 버릴 내용을 제거하므로, 네트워크를 통해 전송될 필요가 없습니다.
HTML 최소화로 인한 절약 효과는 문서마다 다릅니다. 주석이 많은 템플릿, 깊은 들여쓰기가 있는 서버 렌더링 페이지, 인라인 스타일이 있는 CMS 출력물은 최소화만으로도 15-30%의 크기 감소를 볼 수 있습니다. 소규모 문서의 경우 절대적인 절약량은 크지 않지만, 트래픽이 많은 사이트에서는 수백만 건의 요청에 걸쳐 페이지 로드당 몇 킬로바이트라도 실질적인 대역폭 절약으로 이어집니다.
이 HTML 압축기를 사용하는 이유
HTML을 붙여넣으면 즉시 압축된 결과를 얻을 수 있습니다. 설치할 빌드 도구도, 설정 파일도, 계정도 필요 없습니다.
HTML 압축기 활용 사례
HTML 최소화가 제거하는 것
완전한 기능의 HTML 압축기는 공백 제거 이상의 여러 변환을 적용합니다. 아래 표는 가장 일반적인 기법들을 가장 안전한 것(항상 무손실)부터 가장 공격적인 것(무분별하게 적용하면 엣지 케이스를 깰 수 있음)까지 순서대로 나열합니다.
| 기법 | 적용 전 | 적용 후 |
|---|---|---|
| Whitespace between tags | <div> <p> text </p> </div> | <div><p>text</p></div> |
| HTML comments | <!-- TODO: fix later --> | (removed entirely) |
| Redundant attribute quotes | class="main" | class=main |
| Boolean attribute values | disabled="disabled" | disabled |
| Empty attribute values | id="" | (attribute removed) |
| Optional closing tags | </li>, </td>, </p> | (removed when safe) |
| Type on script/style | type="text/javascript" | (removed — default) |
| Protocol in URLs | https://cdn.example.com | //cdn.example.com |
최소화 대 Gzip 압축
개발자들은 서버가 이미 Gzip 또는 Brotli 압축을 적용하고 있을 때 최소화가 여전히 필요한지 묻는 경우가 있습니다. 간단한 답변: 네, 그리고 두 방법은 함께 사용할 때 가장 효과적입니다.
최소화는 Gzip이 처리하는 입력을 줄여주므로 압축된 출력도 더 작아집니다. Google의 PageSpeed 가이드라인은 두 방법 모두 적용할 것을 권장합니다. 일반적인 페이지에서 최소화는 원시 크기의 15-25%를 절약하고 Gzip은 결과를 추가로 60-80% 압축합니다. 결합하면 전체 전송 크기가 원본의 압축되지 않은 문서의 10-20%까지 떨어질 수 있습니다.
코드 예제
아래는 네 가지 환경에서 HTML 최소화의 작동 예제입니다. 각 예제는 주석을 제거하고 공백을 축소합니다.
import { minify } from 'html-minifier-terser'
const html = `
<div class="card">
<!-- user profile -->
<p> Hello, world! </p>
</div>
`
const result = await minify(html, {
collapseWhitespace: true,
removeComments: true,
removeRedundantAttributes: true,
removeEmptyAttributes: true,
})
// → '<div class="card"><p>Hello, world!</p></div>'import htmlmin html = """ <div class="card"> <!-- user profile --> <p> Hello, world! </p> </div> """ result = htmlmin.minify(html, remove_comments=True, remove_empty_space=True) # → '<div class="card"><p>Hello, world!</p></div>'
package main
import (
"fmt"
"github.com/tdewolff/minify/v2"
"github.com/tdewolff/minify/v2/html"
)
func main() {
m := minify.New()
m.AddFunc("text/html", html.Minify)
input := `<div class="card">
<!-- user profile -->
<p> Hello, world! </p>
</div>`
result, _ := m.String("text/html", input)
fmt.Println(result)
// → <div class=card><p>Hello, world!</div>
}# Install globally npm install -g html-minifier-terser # Minify a file html-minifier-terser --collapse-whitespace --remove-comments input.html -o output.html # Pipe from stdin cat index.html | html-minifier-terser --collapse-whitespace --remove-comments # With all common optimizations html-minifier-terser \ --collapse-whitespace \ --remove-comments \ --remove-redundant-attributes \ --remove-empty-attributes \ --minify-css true \ --minify-js true \ input.html -o output.min.html