-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathhtml-minifier.html
More file actions
666 lines (641 loc) · 51.6 KB
/
Copy pathhtml-minifier.html
File metadata and controls
666 lines (641 loc) · 51.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>HTML Minifier & Beautifier Online | FreeDevTool</title>
<meta name="description" content="Free HTML minifier & beautifier — strip comments, collapse whitespace, preserve pre/script/style. 10–40% smaller. Browser-only, no upload.">
<meta name="robots" content="index, follow">
<meta name="author" content="Anees Ur Rehman">
<script type="application/ld+json">{"@context":"https://schema.org","@type":"WebPage","datePublished":"2026-05-02","dateModified":"2026-05-19","inLanguage":"en-US","isPartOf":{"@type":"WebSite","name":"FreeDevTool","url":"https://freedevtool.org"}}</script>
<script type="application/ld+json">{"@context":"https://schema.org","@type":"Person","name":"Anees Ur Rehman","url":"https://freedevtool.org/about","jobTitle":"Full-stack developer","worksFor":{"@type":"Organization","name":"FreeDevTool","url":"https://freedevtool.org"}}</script>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "HowTo",
"name": "How to minify or beautify HTML online",
"description": "Strip comments and whitespace from HTML for production, or beautify minified HTML for inspection. Browser-only, preserves pre/script/style blocks.",
"step": [
{"@type":"HowToStep","name":"Paste HTML","text":"Paste source HTML into the input pane. Parsing happens locally; nothing uploads."},
{"@type":"HowToStep","name":"Choose direction","text":"Click Minify to compress for production, or Beautify to format minified HTML for reading."},
{"@type":"HowToStep","name":"Review the size diff","text":"Original size, minified size, and gzip estimate display in real time. Confirm reduction is meaningful before deploy."},
{"@type":"HowToStep","name":"Copy or download","text":"Copy formatted HTML to clipboard for paste into your build pipeline, or download as a .html file."}
]
}
</script>
<link rel="canonical" href="https://freedevtool.org/html-minifier">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="preload" href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&family=DM+Sans:wght@300;400;500;600&display=swap" as="style">
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&family=DM+Sans:wght@300;400;500;600&display=swap">
<link rel="preload" href="style.css?v=20260502-cards" as="style">
<link rel="stylesheet" href="style.css?v=20260502-cards">
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
<link rel="apple-touch-icon" href="/favicon.svg">
<meta property="og:image" content="https://freedevtool.org/og-image.svg">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="og:image:alt" content="FreeDevTool — 50+ free, fast, privacy-first developer tools">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:image" content="https://freedevtool.org/og-image.svg">
<meta name="twitter:title" content="HTML Minifier & Beautifier Online — Free Tool">
<meta name="twitter:description" content="Minify or beautify HTML. Strip comments, collapse whitespace, preserve pre/script/style. See live byte-savings stats. Free, browser-only, no upload.">
<script async src="https://www.googletagmanager.com/gtag/js?id=G-3L0CMH3X36"></script>
<script>window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments)}gtag('js',new Date());gtag('config','G-3L0CMH3X36');</script>
<meta property="og:title" content="HTML Minifier Online — Free Minify & Beautify Tool">
<meta property="og:description" content="Minify or beautify HTML online. Strip comments, collapse whitespace, preserve pre/script/style. Free, no sign-up.">
<meta property="og:type" content="website">
<meta property="og:url" content="https://freedevtool.org/html-minifier">
<script type="application/ld+json">
{"@context":"https://schema.org","@type":"WebApplication","name":"HTML Minifier Online","url":"https://freedevtool.org/html-minifier","description":"Minify and beautify HTML online. Strip comments, collapse whitespace, preserve pre/script/style content.","applicationCategory":"DeveloperApplication","operatingSystem":"Any","offers":{"@type":"Offer","price":"0","priceCurrency":"USD"}}
</script>
<script type="application/ld+json">
{"@context":"https://schema.org","@type":"FAQPage","mainEntity":[{"@type":"Question","name":"What does an HTML minifier do?","acceptedAnswer":{"@type":"Answer","text":"An HTML minifier reduces the file size of an HTML document by removing unnecessary characters without changing the rendered output. Typical operations include stripping HTML comments, collapsing multiple whitespace characters into a single space, removing whitespace between adjacent tags, and trimming leading/trailing whitespace in attributes. The result is smaller payloads, faster network transfer, and lower bandwidth bills."}},{"@type":"Question","name":"Is it safe to minify HTML automatically?","acceptedAnswer":{"@type":"Answer","text":"Generally yes, provided the minifier preserves the contents of whitespace-sensitive tags such as pre, textarea, script, and style. Our tool leaves those blocks untouched. However, whitespace inside inline elements can matter visually (for example a space between two links), so always test the minified output against the original in a browser before deploying."}},{"@type":"Question","name":"How much smaller does minified HTML get?","acceptedAnswer":{"@type":"Answer","text":"Typical savings range from 10% to 40% depending on how much whitespace and commenting exists in the source. Hand-written templates with lots of indentation and developer comments compress more; generated markup that was already compact compresses less. Enabling gzip or Brotli on the server provides additional compression on top of minification."}},{"@type":"Question","name":"Does minifying HTML improve SEO or Core Web Vitals?","acceptedAnswer":{"@type":"Answer","text":"Minification reduces transfer size which improves Largest Contentful Paint (LCP) and Time to First Byte (TTFB), both ranking signals in Google's Core Web Vitals. Smaller HTML also parses faster on low-powered devices, helping First Input Delay (FID) and Interaction to Next Paint (INP). The SEO impact is indirect but real."}},{"@type":"Question","name":"Should I minify HTML in development or production only?","acceptedAnswer":{"@type":"Answer","text":"Only minify production builds. During development, readable HTML is critical for debugging in DevTools, viewing source, and diffing in version control. Most static site generators and bundlers (Next.js, Astro, Eleventy) minify automatically at build time so you get both worlds."}},{"@type":"Question","name":"Can HTML minification break inline JavaScript?","acceptedAnswer":{"@type":"Answer","text":"Yes if you use aggressive mode. Collapsing whitespace inside script tags can break template literals that depend on newlines, or scripts that rely on multi-line string assignment. Safe-mode preserves script and style tag content untouched."}},{"@type":"Question","name":"Should HTML minification preserve CSS comments?","acceptedAnswer":{"@type":"Answer","text":"Generally no — CSS comments are stripped by default. The exception is license/legal comments. Most minifiers preserve these. If you have intentional CSS hacks expressed as comments, use safe-mode or mark them with the legal-comment prefix."}},{"@type":"Question","name":"Does HTML minification affect SEO?","acceptedAnswer":{"@type":"Answer","text":"Minified HTML is a Core Web Vitals signal because it reduces page weight and parse time. Google has confirmed page-speed factors into rankings. No penalty for unminified HTML, but the indirect benefit of faster pages is well documented."}}]}
</script>
<style>
.hm-grid{display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-bottom:16px}
.hm-col label{display:block;font-size:11px;font-family:var(--mono);color:var(--text3);text-transform:uppercase;letter-spacing:1px;margin-bottom:6px}
.hm-col textarea{width:100%;min-height:320px;padding:14px;background:var(--bg);border:1px solid var(--border);border-radius:var(--radius);color:var(--text);font-family:var(--mono);font-size:13px;line-height:1.5;resize:vertical;box-sizing:border-box}
.hm-col textarea:focus{border-color:var(--accent);outline:none;box-shadow:0 0 0 3px rgba(0,208,132,.08)}
.hm-actions{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:16px}
.hm-actions button{padding:10px 18px;font-size:13px;font-family:var(--mono);background:var(--bg4);border:1px solid var(--border);border-radius:var(--radius);color:var(--text);cursor:pointer;transition:all .2s}
.hm-actions button:hover{border-color:var(--accent);color:var(--accent)}
.hm-actions button.primary{background:var(--accent);color:#000;border-color:var(--accent);font-weight:600}
.hm-actions button.primary:hover{opacity:.9;color:#000}
.hm-stats{display:grid;grid-template-columns:repeat(3,1fr);gap:2px;background:var(--border);border-radius:var(--radius);overflow:hidden;margin-top:16px}
.hm-stat{padding:12px 14px;background:var(--bg);text-align:center}
.hm-stat-label{font-size:10px;font-family:var(--mono);color:var(--text3);text-transform:uppercase;letter-spacing:1px;margin-bottom:4px}
.hm-stat-val{font-family:var(--mono);font-size:15px;color:var(--text);font-weight:500}
.hm-stat-val.good{color:var(--accent)}
.hm-out-head{display:flex;justify-content:space-between;align-items:center;margin-bottom:6px}
.hm-copy{padding:4px 10px;font-size:11px;font-family:var(--mono);background:var(--bg4);border:1px solid var(--border);border-radius:4px;color:var(--text2);cursor:pointer}
.hm-copy:hover{border-color:var(--accent);color:var(--accent)}
@media(max-width:800px){.hm-grid{grid-template-columns:1fr}.hm-col textarea{min-height:220px}.hm-stats{grid-template-columns:1fr}}
</style>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{
"@type": "ListItem",
"position": 1,
"name": "Home",
"item": "https://freedevtool.org/"
},
{
"@type": "ListItem",
"position": 2,
"name": "All Tools",
"item": "https://freedevtool.org/all-tools"
},
{
"@type": "ListItem",
"position": 3,
"name": "HTML Minifier & Beautifier",
"item": "https://freedevtool.org/html-minifier"
}
]
}
</script>
<script src="/ga4-events.js" defer></script>
</head>
<body>
<nav>
<a class="nav-logo" href="/" aria-label="FreeDevTool home"><svg class="logo-mark" width="22" height="22" viewBox="0 0 24 24" aria-hidden="true" fill="none"><rect x="1" y="1" width="22" height="22" rx="6" fill="currentColor" opacity=".12"/><path d="M9.5 8.5L6 12l3.5 3.5M14.5 8.5L18 12l-3.5 3.5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>FreeDevTool</a>
<div class="nav-links">
<div class="nav-dropdown" id="tools-dropdown">
<a href="all-tools" onclick="event.preventDefault();this.parentElement.classList.toggle('open')" aria-haspopup="true">Tools <svg class="chev" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="6 9 12 15 18 9"/></svg></a>
<div class="nav-dropdown-menu">
<a href="encoding-tools">
<div class="dd-icon">b64</div>
<div class="dd-info"><div class="dd-name">Encoding & Conversion</div><div class="dd-count">11 tools · Base64, YAML, px→rem</div></div>
</a>
<a href="generation-tools">
<div class="dd-icon">{ }</div>
<div class="dd-info"><div class="dd-name">Generation & Formatting</div><div class="dd-count">16 tools · JSON, SQL, gradients</div></div>
</a>
<a href="security-tools">
<div class="dd-icon">#</div>
<div class="dd-info"><div class="dd-name">Security & Hashing</div><div class="dd-count">3 tools · JWT, MD5, SHA</div></div>
</a>
<a href="text-tools">
<div class="dd-icon">.*</div>
<div class="dd-info"><div class="dd-name">Code & Text Tools</div><div class="dd-count">9 tools · Regex, diff, tokens</div></div>
</a>
<a href="devops-tools">
<div class="dd-icon">JS</div>
<div class="dd-info"><div class="dd-name">Optimization & DevOps</div><div class="dd-count">7 tools · Minifiers, cURL, git</div></div>
</a>
<a href="network-tools">
<div class="dd-icon">IP</div>
<div class="dd-info"><div class="dd-name">Network & Time</div><div class="dd-count">4 tools · IP, DNS, timestamps</div></div>
</a>
<a href="seo-tools">
<div class="dd-icon">SEO</div>
<div class="dd-info"><div class="dd-name">SEO & Meta Tools</div><div class="dd-count">3 tools · OG, meta, slug</div></div>
</a>
<div class="nav-dropdown-divider"></div>
<a class="dd-all" href="all-tools">
<div class="dd-icon">All</div>
<div class="dd-info"><div class="dd-name">Browse all 50 tools</div><div class="dd-count">Searchable catalog & categories</div></div>
</a>
</div>
</div>
<a href="/guides">Guides</a>
<a href="about">About</a>
<a href="privacy">Privacy</a>
</div>
</nav>
<div class="wrapper">
<section class="tool-header">
<a class="tool-back" href="/" aria-label="Back to home">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 18l-6-6 6-6"/></svg>
Back
</a>
<span class="tool-badge">HTML</span>
<h1>HTML Minifier & Beautifier</h1>
<p>Looking for a reliable HTML minifier online? Paste any HTML document below and this free tool will strip comments, collapse redundant whitespace, and shrink your markup without breaking layout. Switch to Beautify mode to re-indent minified or tangled source into clean, readable code with a 2-space indent. Content inside pre, textarea, script, and style tags is preserved byte-for-byte so code samples and inline scripts remain intact. Everything runs locally in your browser — no upload, no sign-up, no tracking. See live byte-savings stats the moment you minify so you know exactly how much you shaved off.</p>
<div class="last-updated">Last updated: May 2026 · Written by <a href="/about">Anees Ur Rehman</a>, full-stack developer</div>
</section>
<div class="tool-card">
<div class="card-dots"><span></span><span></span><span></span></div>
<div class="tool-body">
<div class="hm-actions">
<button class="primary" onclick="doMinify()">Minify</button>
<button onclick="doBeautify()">Beautify / Pretty Print</button>
<button onclick="loadSample()">Sample</button>
<button onclick="clearAll()">Clear</button>
</div>
<div class="hm-grid">
<div class="hm-col">
<label for="hm-input">Input HTML</label>
<textarea id="hm-input" placeholder="Paste your HTML here..." spellcheck="false"></textarea>
</div>
<div class="hm-col">
<div class="hm-out-head">
<label for="hm-output" style="margin-bottom:0">Output</label>
<button class="hm-copy" onclick="copyOut()">Copy</button>
</div>
<textarea id="hm-output" readonly spellcheck="false" placeholder="Result appears here..."></textarea>
</div>
</div>
<div class="hm-stats">
<div class="hm-stat"><div class="hm-stat-label">Original</div><div class="hm-stat-val" id="hm-orig">0 B</div></div>
<div class="hm-stat"><div class="hm-stat-label">Output</div><div class="hm-stat-val" id="hm-out">0 B</div></div>
<div class="hm-stat"><div class="hm-stat-label">Savings</div><div class="hm-stat-val good" id="hm-save">—</div></div>
</div>
</div>
</div>
<div id="toast" style="position:fixed;bottom:30px;left:50%;transform:translateX(-50%);background:var(--accent);color:#000;padding:8px 20px;border-radius:var(--radius);font-size:13px;font-weight:600;opacity:0;transition:opacity .3s;pointer-events:none;z-index:999">Copied!</div>
<p class="aeo-lead" style="font-size:16px;line-height:1.7;color:var(--text);max-width:760px;margin:24px auto 18px;padding:0 4px">
<strong>HTML minification</strong> collapses whitespace, strips comments, and shortens optional tags to reduce payload size — typical savings are 15-20% on production HTML. This <strong>free HTML minifier</strong> offers safe-mode (preserves inline scripts and conditional comments) and aggressive-mode (drops everything inessential). Always verify minified output works before shipping.
</p>
<section id="examples" style="max-width:760px;margin:24px auto 32px">
<h2 style="font-size:18px;margin-bottom:14px">Examples</h2>
<div style="background:var(--bg3);border:1px solid var(--border);border-radius:var(--radius);padding:16px;margin-bottom:12px">
<strong style="display:block;color:var(--accent);font-family:var(--mono);font-size:11px;text-transform:uppercase;letter-spacing:1px;margin-bottom:6px">Realistic compression ratios§§A typical Bootstrap landing page: 47 KB → 41 KB (13% smaller).§§A Tailwind-based app shell: 32 KB → 27 KB (16% smaller).§§HTML minification typically saves 10-20% — less than CSS or JS because HTML has less whitespace to remove.</strong>
</div>
<div style="background:var(--bg3);border:1px solid var(--border);border-radius:var(--radius);padding:16px;margin-bottom:12px">
<strong style="display:block;color:var(--accent);font-family:var(--mono);font-size:11px;text-transform:uppercase;letter-spacing:1px;margin-bottom:6px">Safe-mode preserves inline scripts§§<script>const x = `multi\nline`</script> — aggressive minification can collapse the template literal newline, breaking the string. Safe-mode preserves whitespace inside script and style tags.</strong>
</div>
<div style="background:var(--bg3);border:1px solid var(--border);border-radius:var(--radius);padding:16px;margin-bottom:12px">
<strong style="display:block;color:var(--accent);font-family:var(--mono);font-size:11px;text-transform:uppercase;letter-spacing:1px;margin-bottom:6px">Conditional comments§§<!--[if IE]>...<![endif]--> Internet Explorer specific markup. Safe-mode preserves these; aggressive mode drops them. Mostly irrelevant in 2026.</strong>
</div>
</section>
<aside class="founder-note" style="max-width:760px;margin:24px auto 32px;padding:20px 24px;background:rgba(0,208,132,0.05);border-left:3px solid var(--accent);border-radius:6px;font-size:14px;line-height:1.7;color:var(--text2)"><div style="font-family:var(--mono);font-size:11px;color:var(--accent);letter-spacing:1.5px;text-transform:uppercase;margin-bottom:10px;font-weight:600">💡 Why I built this</div><p style="margin:0 0 12px">I built this after watching an HTML minifier helpfully optimize an inline script that depended on whitespace inside a template literal. The minified version broke the page silently in production. This minifier offers safe-mode (preserves inline JS and CSS untouched) and aggressive-mode (everything goes). Aggressive savings are real (usually 15-20% smaller), but verify your output does not break inline scripts before shipping.</p><p style="margin:0;font-size:13px;color:var(--text3)">— <a href="/about" style="color:var(--accent);text-decoration:none">Anees Ur Rehman</a>, full-stack developer</p></aside>
<section class="article-section">
<h2>HTML minification, performance, and what to ship in 2026</h2>
<p>HTML is the only resource a browser is guaranteed to need before it can render anything. Every byte you save in HTML lands directly on Largest Contentful Paint (LCP), Time to First Byte (TTFB), and the network bill — there is no "skip this until later" option for the first HTML response the way there is for code-split JS or below-the-fold CSS. Minification is the cheapest performance win available, and yet most teams either skip it (because their bundler does it for them and they never check) or do it badly (with a tool that mangles inline scripts). This guide covers what minification actually does, how it interacts with gzip and Brotli, what it does and does not buy you on Core Web Vitals, and the gotchas that show up in production HTML.</p>
<h3>What HTML minification removes — line by line</h3>
<table class="ref-table">
<thead><tr><th>Operation</th><th>Typical bytes saved</th><th>Risk</th></tr></thead>
<tbody>
<tr><td>Strip HTML comments</td><td>1–5%</td><td>Conditional comments (<code><!--[if IE]></code>) must be preserved.</td></tr>
<tr><td>Collapse whitespace between tags</td><td>5–15%</td><td>Whitespace between inline elements (links, spans) can be visible. Test before/after.</td></tr>
<tr><td>Collapse multiple spaces inside text</td><td>2–5%</td><td>Safe outside <code><pre></code> and <code><textarea></code>.</td></tr>
<tr><td>Trim attribute whitespace</td><td><1%</td><td>Safe.</td></tr>
<tr><td>Remove optional closing tags (<code></li></code>, <code></p></code>)</td><td>2–5%</td><td>HTML5-valid but often surprises tools later in the pipeline.</td></tr>
<tr><td>Remove optional <code>type</code> attributes (<code>type="text/javascript"</code>, <code>type="text/css"</code>)</td><td><1%</td><td>Safe; both are HTML5 defaults.</td></tr>
<tr><td>Collapse boolean attributes (<code>checked="checked"</code> → <code>checked</code>)</td><td><1%</td><td>Safe.</td></tr>
</tbody>
</table>
<p>Combined, minifying typical hand-written HTML cuts 15–35% of bytes. Server-rendered HTML from frameworks already strips most of this, so savings are smaller but still meaningful for SSR pages with developer comments and indentation.</p>
<h3>Minification vs gzip vs Brotli — they stack</h3>
<p>Minification removes <em>structural</em> redundancy (whitespace, comments). Gzip and Brotli remove <em>statistical</em> redundancy (repeated byte sequences). Both layers contribute, and removing one does not replace the other. Real numbers from a typical content-heavy HTML page:</p>
<table class="ref-table">
<thead><tr><th>Pipeline</th><th>Bytes</th><th>vs raw</th></tr></thead>
<tbody>
<tr><td>Raw HTML</td><td>120 KB</td><td>baseline</td></tr>
<tr><td>Minified</td><td>85 KB</td><td>−29%</td></tr>
<tr><td>Raw + gzip</td><td>22 KB</td><td>−82%</td></tr>
<tr><td>Minified + gzip</td><td>20 KB</td><td>−83%</td></tr>
<tr><td>Minified + Brotli</td><td>17 KB</td><td>−86%</td></tr>
</tbody>
</table>
<p>The marginal value of minification on top of gzip is small (1–3 KB on a 120 KB page) but real. The big win is on uncompressed responses, on connections without gzip support (rare in 2026), and on the parser-cost side: the browser's HTML parser still has to walk every byte before tokenization, and fewer bytes = less main-thread work.</p>
<h3>Core Web Vitals — what minification actually improves</h3>
<ul>
<li><strong>TTFB (Time to First Byte):</strong> tiny direct improvement — same network RTT, slightly less data. Indirect win if your origin can ship the response from cache faster.</li>
<li><strong>LCP (Largest Contentful Paint):</strong> meaningful win when LCP is gated on parsing the HTML to discover the LCP image. Smaller HTML = parser reaches the <code><img></code> sooner.</li>
<li><strong>FCP (First Contentful Paint):</strong> direct improvement from less HTML to download and parse before the browser can paint.</li>
<li><strong>INP (Interaction to Next Paint):</strong> smaller HTML reduces main-thread work during initial load, which makes early interactions less janky.</li>
<li><strong>CLS (Cumulative Layout Shift):</strong> no direct effect — CLS is a layout problem, not a payload problem.</li>
</ul>
<p>Google has confirmed that LCP, INP, and CLS are ranking signals via the Core Web Vitals report in Search Console. The gain from minifying HTML in isolation is typically 50–200 ms on LCP for content-heavy pages — small but cumulatively important when paired with image optimization, font subsetting, and JS code-splitting.</p>
<h3>What this minifier preserves (and why those decisions matter)</h3>
<ol>
<li><strong><code><pre></code> and <code><textarea></code>:</strong> whitespace is semantic. Code samples, ASCII art, and form pre-population all break if you collapse it.</li>
<li><strong><code><script></code> and <code><style></code>:</strong> the contents have their own grammar. JavaScript template literals and CSS calc() expressions can both contain whitespace that matters. Minify them with a real JS / CSS minifier if you want; HTML minification is the wrong layer.</li>
<li><strong>Conditional comments (<code><!--[if IE]></code>):</strong> still used by some legacy enterprise email rendering. Stripping them is dangerous when you do not control the consumer.</li>
<li><strong>Inline event handlers and inline JSON-in-script blocks:</strong> the tool does not touch any character inside attribute values or script blocks.</li>
</ol>
<h3>Common HTML-minification mistakes</h3>
<ul>
<li><strong>Minifying templates instead of output.</strong> Minifying a Jinja2 template with whitespace control inside <code>{%-</code> tags can corrupt rendering. Minify the rendered HTML, not the template source.</li>
<li><strong>Stripping conditional comments.</strong> Older email clients and some embedded browsers still parse them. If you are shipping email HTML or kiosk content, leave them in.</li>
<li><strong>Collapsing whitespace between inline elements without testing.</strong> <code><a>A</a> <a>B</a></code> renders with a space; <code><a>A</a><a>B</a></code> does not. Diff the visual output before deploying.</li>
<li><strong>Forgetting to recompress.</strong> If you serve static HTML, regenerate the gzip / Brotli precompressed copies after minifying. CDNs that compress on the fly do this automatically.</li>
<li><strong>Minifying view-source for SEO content.</strong> Google cares about rendered text, not source bytes. Removing the <code><meta name="description"></code> "to save bytes" is a self-inflicted ranking hit.</li>
<li><strong>Treating a minifier as a security tool.</strong> Stripping comments does <em>not</em> remove framework version strings or sensitive HTML inside the page. Use a separate post-processing step for redaction.</li>
</ul>
<h3>HTML minification in modern build pipelines</h3>
<table class="ref-table">
<thead><tr><th>Stack</th><th>How HTML gets minified</th></tr></thead>
<tbody>
<tr><td>Next.js</td><td>Built-in via Terser HTML; controlled by <code>next.config.js</code>.</td></tr>
<tr><td>Astro</td><td>Built-in via <code>astro:compress</code>; on by default in production.</td></tr>
<tr><td>Eleventy</td><td>Add <code>html-minifier-terser</code> as a transform.</td></tr>
<tr><td>Hugo</td><td><code>hugo --minify</code> uses tdewolff/minify in Go.</td></tr>
<tr><td>Jekyll</td><td>Plugin <code>jekyll-minifier</code>.</td></tr>
<tr><td>Webpack / Vite</td><td>HTML is usually minified by <code>html-webpack-plugin</code> or <code>vite-plugin-html</code>, both wrapping <code>html-minifier-terser</code>.</td></tr>
<tr><td>Cloudflare / Fastly / Akamai</td><td>HTML auto-minify is a CDN setting — turn it on for marketing pages, leave it off for SSR app shells (it can race with hydration).</td></tr>
</tbody>
</table>
<aside class="article-aside">
<strong>Authoritative references:</strong>
<ul>
<li><a href="https://web.dev/articles/vitals" rel="noopener" target="_blank">web.dev — Core Web Vitals overview</a></li>
<li><a href="https://web.dev/articles/optimize-lcp" rel="noopener" target="_blank">web.dev — Optimize Largest Contentful Paint</a></li>
<li><a href="https://html.spec.whatwg.org/multipage/syntax.html#optional-tags" rel="noopener" target="_blank">WHATWG HTML — Optional tags reference</a></li>
<li><a href="https://github.com/terser/html-minifier-terser" rel="noopener" target="_blank">html-minifier-terser — the de-facto JS implementation</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding" rel="noopener" target="_blank">MDN — Content-Encoding header (gzip / Brotli)</a></li>
</ul>
</aside>
</section>
<section class="faq-section">
<h2>Best HTML minifier for 2026 — what to compare</h2>
<p>Search results for "html minifier online", "minify html", and "html beautifier" return many tools but most fail on real-world HTML: they break <code><pre></code> code blocks, mangle inline JavaScript, strip semantically-meaningful whitespace inside <code><textarea></code>, or upload your source HTML to a server. Here's how the most-used HTML minifiers compare in 2026:</p>
<table class="ref-table">
<thead><tr><th>Tool</th><th>Browser-only</th><th>Preserves pre/script/style</th><th>Beautify direction</th><th>Cost</th></tr></thead>
<tbody>
<tr><td>FreeDevTool HTML Minifier</td><td>Yes</td><td>Yes (whitespace-sensitive blocks intact)</td><td>Yes</td><td>Free</td></tr>
<tr><td>htmlminifier.com</td><td>Server-side</td><td>Configurable</td><td>No</td><td>Free, ad-funded</td></tr>
<tr><td>willpeavy.com/tools/minifier</td><td>Server-side</td><td>Yes</td><td>No</td><td>Free</td></tr>
<tr><td>npm <code>html-minifier-terser</code></td><td>Local install</td><td>Full configurability</td><td>Yes (separate flag)</td><td>Free, OSS</td></tr>
<tr><td>Astro / Next.js / Eleventy build minify</td><td>Build-time</td><td>Yes</td><td>N/A</td><td>Free (built-in)</td></tr>
</tbody>
</table>
<h3>How do I minify HTML online without uploading my source?</h3>
<p>Paste any HTML into the input pane on this page. The minifier runs entirely in the browser — DOMParser parses the input, an AST walker collapses whitespace and strips comments, then serializes the output. Your source HTML never leaves the page. Verify in DevTools Network tab: zero outgoing requests during minify. This matters because production HTML often contains internal API endpoints, customer email patterns, feature-flag remnants, or developer comments that shouldn't be exposed via a third-party minifier service.</p>
<h3>What's the difference between minifying HTML, CSS, and JavaScript?</h3>
<table class="ref-table">
<thead><tr><th>Operation</th><th>HTML</th><th>CSS</th><th>JavaScript</th></tr></thead>
<tbody>
<tr><td>Whitespace removal</td><td>Outside whitespace-sensitive blocks</td><td>All non-essential</td><td>All except in strings/templates</td></tr>
<tr><td>Comment removal</td><td><code><!-- --></code></td><td><code>/* */</code></td><td><code>//</code> and <code>/* */</code></td></tr>
<tr><td>Identifier shortening</td><td>None safe (would break IDs/refs)</td><td>None safe (would break selectors)</td><td>Local var renaming (mangling)</td></tr>
<tr><td>Dead-code elimination</td><td>None (all markup serves output)</td><td>Optional (PurgeCSS)</td><td>Tree-shaking (esbuild/Rollup)</td></tr>
<tr><td>Typical reduction</td><td>10–40%</td><td>20–50%</td><td>30–60%</td></tr>
<tr><td>Tool</td><td><a href="/html-minifier">HTML Minifier</a></td><td><a href="/css-minifier">CSS Minifier</a></td><td><a href="/js-minifier">JS Minifier</a></td></tr>
</tbody>
</table>
<p>Decision rule: ALL three should run on production builds. Run them in order: minify CSS first (then inline if small), then minify JS (with tree-shaking), then minify HTML last (which references the minified asset names). Modern build tools (Vite, Next.js, Astro, Eleventy) handle all three automatically.</p>
<h3>HTML minifier alternative to htmlminifier.com — 4 reasons developers switched</h3>
<ol>
<li><strong>Browser-only, no server upload.</strong> htmlminifier.com POSTs your HTML to a server. Production templates with inline data, API references, or developer comments shouldn't leave your browser.</li>
<li><strong>Bidirectional minify + beautify.</strong> Most online tools only minify; this page also beautifies third-party minified HTML for inspection (debugging legacy email templates, third-party widget HTML, etc.).</li>
<li><strong>Preserves pre/script/style/textarea.</strong> Whitespace-sensitive blocks stay byte-identical — critical for code samples, JSON-LD scripts, and form initial values.</li>
<li><strong>Live size diff with gzip estimate.</strong> Original / minified / gzip-estimated bytes shown in real time, so you can confirm whether the minify is worth it before deploying.</li>
</ol>
<p>Pair the HTML minifier with the <a href="/css-minifier">CSS Minifier</a> and <a href="/js-minifier">JS Minifier</a> for the full minification trio, the <a href="/byte-converter">Byte Converter</a> to translate bundle savings to mobile-3G download time, and the <a href="/devops-tools">DevOps Tools hub</a> for the broader optimization toolkit.</p>
<h2>Frequently Asked Questions</h2>
<div class="faq-item"><div class="faq-q" onclick="toggleFaq(this)">What does an HTML minifier do?<svg class="chevron" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><polyline points="6 9 12 15 18 9"/></svg></div><div class="faq-a">An HTML minifier reduces the file size of an HTML document by removing unnecessary characters without changing how the page renders. Typical operations include stripping HTML comments, collapsing multiple whitespace characters into a single space, removing whitespace between adjacent tags, and trimming leading/trailing whitespace inside attribute values. The result is smaller payloads, faster network transfer, and lower bandwidth bills on high-traffic sites. A good minifier also leaves anything semantically meaningful — like the contents of <code><pre></code> or <code><script></code> blocks — completely untouched.</div></div>
<div class="faq-item"><div class="faq-q" onclick="toggleFaq(this)">Is it safe to minify HTML automatically?<svg class="chevron" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><polyline points="6 9 12 15 18 9"/></svg></div><div class="faq-a">Generally yes, provided the minifier preserves the contents of whitespace-sensitive tags such as <code><pre></code>, <code><textarea></code>, <code><script></code>, and <code><style></code>. This tool leaves those blocks untouched. However, whitespace between inline elements can sometimes matter visually (for example, a space between two adjacent links), so always diff the minified output against the original in a browser before deploying to production. Conditional comments for legacy IE like <code><!--[if IE]></code> are also preserved.</div></div>
<div class="faq-item"><div class="faq-q" onclick="toggleFaq(this)">How much smaller does minified HTML get?<svg class="chevron" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><polyline points="6 9 12 15 18 9"/></svg></div><div class="faq-a">Typical savings range from 10% to 40% depending on how much whitespace and commenting exists in the source. Hand-written templates with lots of indentation and developer comments compress more; generated markup that was already compact compresses less. Enabling gzip or Brotli on the server provides additional compression on top of minification — combined, you can often ship a page in 70–85% fewer bytes than the raw source. For a page above the LCP fold, those savings translate directly into faster perceived load.</div></div>
<div class="faq-item"><div class="faq-q" onclick="toggleFaq(this)">Does minifying HTML improve SEO or Core Web Vitals?<svg class="chevron" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><polyline points="6 9 12 15 18 9"/></svg></div><div class="faq-a">Minification reduces transfer size, which improves Largest Contentful Paint (LCP) and Time to First Byte (TTFB), both ranking signals tracked in Google's Core Web Vitals report. Smaller HTML also parses faster on low-powered mobile devices, helping First Input Delay (FID) and the newer Interaction to Next Paint (INP) metric. The SEO impact is indirect but real: Google has stated that speed is a ranking factor, and the Chrome UX Report feeds real-user metrics back into Search Console.</div></div>
<div class="faq-item"><div class="faq-q" onclick="toggleFaq(this)">Should I minify HTML in development or only in production?<svg class="chevron" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><polyline points="6 9 12 15 18 9"/></svg></div><div class="faq-a">Only minify production builds. During development, readable HTML is critical for debugging in DevTools, viewing source, and diffing in version control. Most modern static site generators and bundlers — including Next.js, Astro, Eleventy, and Gatsby — minify at build time automatically so you get readable dev output and compact production output without any manual step. Use this tool when you're working with a legacy pipeline or need to minify a one-off snippet.</div></div>
<div class="faq-item"><div class="faq-q" onclick="toggleFaq(this)">What about inline CSS and JavaScript?<svg class="chevron" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><polyline points="6 9 12 15 18 9"/></svg></div><div class="faq-a">This tool preserves the contents of <code><script></code> and <code><style></code> blocks verbatim so your inline logic keeps working exactly as written. If you also want to minify those, run the extracted CSS through our CSS Minifier and the JavaScript through our JS Minifier, then paste the results back into your HTML. Splitting the concerns this way gives you safer, more predictable output than a single tool that tries to do everything at once.</div></div>
</section>
<section class="related-section">
<h2>Related Tools</h2>
<div class="related-grid">
<a class="related-card" href="css-minifier"><div class="related-icon">{ }</div><div class="related-card-info"><div class="related-card-name">CSS Minifier</div><div class="related-card-desc">Compress stylesheets</div></div></a>
<a class="related-card" href="js-minifier"><div class="related-icon">JS</div><div class="related-card-info"><div class="related-card-name">JS Minifier</div><div class="related-card-desc">Shrink JavaScript files</div></div></a>
<a class="related-card" href="html-entity"><div class="related-icon">&</div><div class="related-card-info"><div class="related-card-name">HTML Entity Encoder</div><div class="related-card-desc">Encode/decode entities</div></div></a>
</div>
</section>
<section class="all-tools-section" aria-label="Browse all FreeDevTool developer tools">
<h2>Browse all 50 free developer tools</h2>
<p class="atc-sub">All tools run in your browser, no signup required, nothing sent to a server.</p>
<div class="all-tools-grid">
<div class="atc-cat">
<div class="atc-cat-head">
<div class="atc-cat-icon">b64</div>
<div class="atc-cat-title"><h3>Encoding & Conversion</h3><span class="atc-cat-count">11 tools</span></div>
</div>
<ul class="atc-list">
<li><a href="/base64-encoder">Base64 Encoder / Decoder</a></li>
<li><a href="/base64-image">Image to Base64</a></li>
<li><a href="/byte-converter">Byte Converter (KB / MB / GB)</a></li>
<li><a href="/case-converter">Case Converter</a></li>
<li><a href="/hex-to-rgb">Hex to RGB / HSL</a></li>
<li><a href="/html-entity">HTML Entity Encoder</a></li>
<li><a href="/json-to-csv">JSON to CSV Converter</a></li>
<li><a href="/px-to-rem">PX to REM Converter</a></li>
<li><a href="/string-escape">String Escape / Unescape</a></li>
<li><a href="/url-encoder">URL Encoder / Decoder</a></li>
<li><a href="/yaml-to-json">YAML to JSON Converter</a></li>
</ul>
</div>
<div class="atc-cat">
<div class="atc-cat-head">
<div class="atc-cat-icon">{ }</div>
<div class="atc-cat-title"><h3>Formatting & Generators</h3><span class="atc-cat-count">13 tools</span></div>
</div>
<ul class="atc-list">
<li><a href="/color-name">Color Name from Hex</a></li>
<li><a href="/color-picker">Color Palette Picker</a></li>
<li><a href="/css-box-shadow">CSS Box Shadow</a></li>
<li><a href="/css-gradient">CSS Gradient Generator</a></li>
<li><a href="/json-formatter">JSON Formatter / Validator</a></li>
<li><a href="/lorem-ipsum">Lorem Ipsum Generator</a></li>
<li><a href="/markdown-preview">Markdown Preview</a></li>
<li><a href="/password-generator">Password Generator</a></li>
<li><a href="/qr-generator">QR Code Generator</a></li>
<li><a href="/sql-formatter">SQL Formatter</a></li>
<li><a href="/uuid-generator">UUID Generator</a></li>
<li><a href="/word-to-markdown">Word to Markdown</a></li>
<li><a href="/xml-formatter">XML Formatter</a></li>
</ul>
</div>
<div class="atc-cat">
<div class="atc-cat-head">
<div class="atc-cat-icon">JS</div>
<div class="atc-cat-title"><h3>Minifiers & DevOps</h3><span class="atc-cat-count">6 tools</span></div>
</div>
<ul class="atc-list">
<li><a href="/chmod-calculator">chmod Calculator</a></li>
<li><a href="/cron-parser">Cron Expression Parser</a></li>
<li><a href="/css-minifier">CSS Minifier</a></li>
<li><a href="/html-minifier">HTML Minifier</a></li>
<li><a href="/js-minifier">JavaScript Minifier</a></li>
<li><a href="/http-status">HTTP Status Codes</a></li>
</ul>
</div>
<div class="atc-cat">
<div class="atc-cat-head">
<div class="atc-cat-icon">#</div>
<div class="atc-cat-title"><h3>Security & Hashing</h3><span class="atc-cat-count">3 tools</span></div>
</div>
<ul class="atc-list">
<li><a href="/hash-generator">Hash Generator (MD5, SHA)</a></li>
<li><a href="/jwt-decoder">JWT Decoder</a></li>
<li><a href="/jwt-generator">JWT Generator</a></li>
</ul>
</div>
<div class="atc-cat">
<div class="atc-cat-head">
<div class="atc-cat-icon">.*</div>
<div class="atc-cat-title"><h3>Code & Text</h3><span class="atc-cat-count">8 tools</span></div>
</div>
<ul class="atc-list">
<li><a href="/ai-token-counter">AI Token Counter</a></li>
<li><a href="/char-counter">Character & Word Counter</a></li>
<li><a href="/git-cheatsheet">Git Commands Cheatsheet</a></li>
<li><a href="/number-base">Number Base Converter</a></li>
<li><a href="/regex-explainer">Regex Explainer</a></li>
<li><a href="/regex-tester">Regex Tester</a></li>
<li><a href="/text-diff">Text Diff Checker</a></li>
<li><a href="/wcag-contrast">WCAG Contrast Checker</a></li>
</ul>
</div>
<div class="atc-cat">
<div class="atc-cat-head">
<div class="atc-cat-icon">IP</div>
<div class="atc-cat-title"><h3>Network & APIs</h3><span class="atc-cat-count">3 tools</span></div>
</div>
<ul class="atc-list">
<li><a href="/dns-lookup">DNS Lookup</a></li>
<li><a href="/http-request-builder">HTTP Request Builder</a></li>
<li><a href="/ip-lookup">IP Address Lookup</a></li>
</ul>
</div>
<div class="atc-cat">
<div class="atc-cat-head">
<div class="atc-cat-icon">⏱</div>
<div class="atc-cat-title"><h3>Time & Dates</h3><span class="atc-cat-count">3 tools</span></div>
</div>
<ul class="atc-list">
<li><a href="/relative-time">Relative Time Calculator</a></li>
<li><a href="/timestamp-diff">Timestamp Diff</a></li>
<li><a href="/unix-timestamp-converter">Unix Timestamp Converter</a></li>
</ul>
</div>
<div class="atc-cat">
<div class="atc-cat-head">
<div class="atc-cat-icon">SEO</div>
<div class="atc-cat-title"><h3>SEO & Meta</h3><span class="atc-cat-count">3 tools</span></div>
</div>
<ul class="atc-list">
<li><a href="/meta-tag-generator">Meta Tag Generator</a></li>
<li><a href="/og-preview">Open Graph Preview</a></li>
<li><a href="/slug-generator">URL Slug Generator</a></li>
</ul>
</div>
</div>
</section>
</div>
<footer>
<div>© 2026 FreeDevTool. Built for developers, by developers.</div>
<div class="footer-links"><a href="/all-tools">All Tools</a><a href="/about">About</a><a href="/privacy">Privacy Policy</a><a href="/terms">Terms of Use</a></div>
</footer>
<script>
const SAMPLE_HTML=`<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title> Demo Page </title>
<!-- This is a developer comment that can be stripped -->
<!--[if IE]><link rel="stylesheet" href="ie.css"><![endif]-->
<style>
body { font-family: sans-serif; margin: 0; }
.hero { padding: 40px; }
</style>
<script src="/ga4-events.js" defer></script>
</head>
<body>
<header class="hero">
<h1> Hello, World! </h1>
<p>Welcome to the demo.</p>
</header>
<pre>
This whitespace
must be preserved
</pre>
<script>
// inline JS stays untouched
console.log("hi");
<\/script>
</body>
</html>`;
function byteLen(s){return new Blob([s]).size}
function fmtBytes(n){
if(n<1024)return n+' B';
if(n<1024*1024)return (n/1024).toFixed(2)+' KB';
return (n/1024/1024).toFixed(2)+' MB';
}
// Minifier: preserves <pre>, <textarea>, <script>, <style>, and conditional comments
function minifyHTML(src){
const placeholders=[];
const stash=(match)=>{placeholders.push(match);return '\u0001PH'+(placeholders.length-1)+'\u0001'};
// 1. Stash preserved blocks
let out=src.replace(/<pre\b[^>]*>[\s\S]*?<\/pre>/gi,stash);
out=out.replace(/<textarea\b[^>]*>[\s\S]*?<\/textarea>/gi,stash);
out=out.replace(/<script\b[^>]*>[\s\S]*?<\/script>/gi,stash);
out=out.replace(/<style\b[^>]*>[\s\S]*?<\/style>/gi,stash);
// 2. Stash conditional comments
out=out.replace(/<!--\[if[\s\S]*?<!\[endif\]-->/gi,stash);
// 3. Remove regular comments
out=out.replace(/<!--[\s\S]*?-->/g,'');
// 4. Collapse whitespace between tags
out=out.replace(/>\s+</g,'><');
// 5. Collapse consecutive whitespace inside text/attrs
out=out.replace(/\s{2,}/g,' ');
// 6. Trim whitespace around attribute equals (a = "b" -> a="b")
out=out.replace(/\s*=\s*"/g,'="');
out=out.replace(/\s*=\s*'/g,"='");
// 7. Trim leading/trailing whitespace
out=out.trim();
// 8. Restore placeholders
out=out.replace(/\u0001PH(\d+)\u0001/g,(_,i)=>placeholders[+i]);
return out;
}
// Beautify: tokenize tags and re-indent
function beautifyHTML(src){
// First, collapse the source so indentation is deterministic
const mini=minifyHTML(src);
const voidTags=new Set(['area','base','br','col','embed','hr','img','input','link','meta','param','source','track','wbr']);
const preserveTags=new Set(['pre','textarea','script','style']);
const tokens=[];
let i=0;
while(i<mini.length){
if(mini[i]==='<'){
// Preserved block? emit as single token
const tagMatch=mini.slice(i).match(/^<([a-zA-Z][a-zA-Z0-9]*)\b/);
if(tagMatch && preserveTags.has(tagMatch[1].toLowerCase())){
const tag=tagMatch[1].toLowerCase();
const closeRe=new RegExp('</'+tag+'\\s*>','i');
const rest=mini.slice(i);
const m=rest.match(closeRe);
if(m){
const end=i+m.index+m[0].length;
tokens.push({type:'preserved',text:mini.slice(i,end)});
i=end;continue;
}
}
// Conditional comment
if(mini.slice(i,i+5)==='<!--['){
const end=mini.indexOf('<![endif]-->',i);
if(end>-1){tokens.push({type:'text',text:mini.slice(i,end+12)});i=end+12;continue}
}
// Comment
if(mini.slice(i,i+4)==='<!--'){
const end=mini.indexOf('-->',i);
if(end>-1){tokens.push({type:'text',text:mini.slice(i,end+3)});i=end+3;continue}
}
// Doctype
if(mini.slice(i,i+9).toLowerCase()==='<!doctype'){
const end=mini.indexOf('>',i);
tokens.push({type:'doctype',text:mini.slice(i,end+1)});
i=end+1;continue;
}
// Normal tag
const end=mini.indexOf('>',i);
if(end===-1){tokens.push({type:'text',text:mini.slice(i)});break}
const raw=mini.slice(i,end+1);
const isClose=raw.startsWith('</');
const isSelf=raw.endsWith('/>');
const nameMatch=raw.match(/^<\/?([a-zA-Z][a-zA-Z0-9]*)/);
const name=nameMatch?nameMatch[1].toLowerCase():'';
const isVoid=voidTags.has(name);
tokens.push({type:isClose?'close':(isSelf||isVoid?'self':'open'),text:raw,name});
i=end+1;
} else {
const end=mini.indexOf('<',i);
const text=end===-1?mini.slice(i):mini.slice(i,end);
if(text.trim())tokens.push({type:'text',text:text.trim()});
i=end===-1?mini.length:end;
}
}
let depth=0;
const pad=()=>' '.repeat(Math.max(0,depth));
const lines=[];
for(const t of tokens){
if(t.type==='close'){depth=Math.max(0,depth-1);lines.push(pad()+t.text)}
else if(t.type==='open'){lines.push(pad()+t.text);depth++}
else if(t.type==='self'||t.type==='doctype'||t.type==='text'||t.type==='preserved'){lines.push(pad()+t.text)}
}
return lines.join('\n');
}
function updateStats(orig,out){
const ob=byteLen(orig),nb=byteLen(out);
document.getElementById('hm-orig').textContent=fmtBytes(ob);
document.getElementById('hm-out').textContent=fmtBytes(nb);
if(ob===0){document.getElementById('hm-save').textContent='—';return}
const saved=ob-nb;
const pct=((saved/ob)*100).toFixed(1);
const el=document.getElementById('hm-save');
if(saved>=0){el.textContent=fmtBytes(saved)+' ('+pct+'%)';el.classList.add('good')}
else{el.textContent='+'+fmtBytes(-saved)+' ('+(-pct)+'%)';el.classList.remove('good')}
}
function doMinify(){
const input=document.getElementById('hm-input').value;
if(!input.trim()){toast('Paste some HTML first');return}
const out=minifyHTML(input);
document.getElementById('hm-output').value=out;
updateStats(input,out);
}
function doBeautify(){
const input=document.getElementById('hm-input').value;
if(!input.trim()){toast('Paste some HTML first');return}
const out=beautifyHTML(input);
document.getElementById('hm-output').value=out;
updateStats(input,out);
}
function loadSample(){
document.getElementById('hm-input').value=SAMPLE_HTML;
doMinify();
}
function clearAll(){
document.getElementById('hm-input').value='';
document.getElementById('hm-output').value='';
document.getElementById('hm-orig').textContent='0 B';
document.getElementById('hm-out').textContent='0 B';
document.getElementById('hm-save').textContent='—';
}
function copyOut(){
const v=document.getElementById('hm-output').value;
if(!v){toast('Nothing to copy');return}
navigator.clipboard.writeText(v);
toast('Copied!');
}
function toast(msg){
const t=document.getElementById('toast');
t.textContent=msg;t.style.opacity='1';
setTimeout(()=>t.style.opacity='0',1500);
}
function toggleFaq(el){el.parentElement.classList.toggle('open');}
</script>
</body>
</html>