HTML Tidyは、崩れたHTMLの閉じタグを補い、入れ子の誤りを直したうえでインデントを揃えるコマンドラインのHTML整形ツールです。この記事では、基本コマンドと既定値、警告メッセージの読み方、CMSの本文断片やWeb Componentsを崩さない設定、GitHub Actionsでの合否判定、OS別のインストールで入る版までを扱います。出力例はすべて2026年10月に手元で実行した結果で、主にHomebrew版5.8.0を使い、Ubuntu 24.04と26.04の版はDockerで確かめました。
まとめ:HTML Tidyの要点
tidy -i index.htmlで字下げ付きの整形結果を標準出力に出し、-mでその場上書き、-oで別ファイルに出力します。既定は字下げなし・改行幅68文字です。- 閉じタグの補完と入れ子の組み替えは自動で行います。
alt属性の欠落のように内容を伴う誤りは警告だけで、書き足しはしません。 - 終了コードは0が問題なし、1が警告、2がエラーです。既定の設定では、エラーのある文書は整形結果を出さず、
-mを付けても元ファイルを書き換えません。存在しないファイルを渡しても0が返る点には注意が要ります。 - CMSに貼る本文断片は
--show-body-only yes、アイコン用の空タグは--drop-empty-elements no、<my-widget>のようなカスタム要素は--custom-tagsを付けないと崩れます。値は要素の置き場所で選び、段落の中で使う要素は inline、ブロックとして置く要素は blocklevel です。 - macOS標準の
/usr/bin/tidyは2006年のApple版でHTML5を扱えません。GitHub Actionsのubuntu-latestでaptから入るのは5.6.0です。 - 安定版は2021年7月の5.8.0で止まっています。既存HTMLの点検と修復には今も使えますが、新しい仕様への追随は期待できません。
HTML Tidyとは(整形・修正・検証を1本で行うCLIツール)
HTML Tidyは、W3CのDave Raggett氏が作ったHTMLの整形・修正ツールです。公式サイトの沿革によると、保守はSourceForgeの有志に引き継がれてC言語のライブラリ(libtidy)になり、2011年にW3CのメンバーがGitHubへフォークしてHTML5に対応しました。2015年に発足したHTACG(HTML Tidy Advocacy Community Group)がW3Cからプロジェクトを引き継ぎ、現在の名前はtidy-html5です。ライセンスは、目的を問わず無償で利用・複製・改変・再配布を認める寛容な条件で、出所を偽らないこと、改変版はそれと明示すること、著作権表示を削らないことの3つが条件です。HTMLの源流についてはSGMLの読み方とXML・HTMLとの違いで解説しています。
1つのコマンドで、インデントと改行位置を揃える整形、閉じタグの補完や入れ子の誤りを直す修正、仕様に照らした警告の3つを済ませられるのが特徴です。誤りを指摘するだけのLinterとも、体裁だけを揃えるフォーマッタとも違い、壊れたマークアップを直すところまで自動で進みます。
整形前後の違いを最小の例で確かめます。閉じタグのない <p> を含む1行のHTMLを tidy -q -i に通した結果です。
// 入力(in.html)
<html><body><p>Hello<br>World</body></html>
// tidy -q -i in.html の出力
<!DOCTYPE html>
<html>
<head>
<meta name="generator" content=
"HTML Tidy for HTML5 for Apple macOS version 5.8.0">
<title></title>
</head>
<body>
<p>Hello<br>
World</p>
</body>
</html>
</p> の補完に加えて、DOCTYPE・<head>・空の <title> まで書き足されます。標準エラーには「missing <!DOCTYPE> declaration」「inserting missing ‘title’ element」の2件の警告が出て、終了コードは1でした。挿入された <meta name="generator"> は --tidy-mark no で消せます。generator行が途中で折り返されているのは、改行幅の既定値が68文字だからです。
HTML Tidyの使い方(基本コマンドとオプション)
基本コマンド(その場整形と別ファイル出力)
tidy -i index.html # 整形結果を標準出力へ(元ファイルは変えない)
tidy -i -m index.html # その場で上書き
tidy -i -o clean.html src.html # 別ファイルに出力
tidy -q -e index.html # 整形せず警告とエラーだけを表示
警告は標準エラーに出るため、tidy -i index.html > out.html とリダイレクトすれば整形結果と警告を分けられます。-q は「Tidy found 1 warning」のような要約や案内文に加えて「Info:」行も省き、WarningとErrorの行だけを残します。
-m で上書きするときの安全弁も確かめました。カスタム要素を含みエラーになる文書に tidy -q -m を実行すると、終了コード2で止まり、元ファイルは1バイトも変わりませんでした。ただし、エラーがあっても出力させる --force-output yes を付けると、同じ文書でも終了コード2のまま元ファイルが書き換わります。警告だけの文書(終了コード1)も書き換えられるので、まとめて上書きする前にGitなどで元に戻せる状態にしておきます。
よく使うオプション(インデント・改行幅・文字コード)
既定値は tidy -show-config で、オプションの意味は5.8.0のクイックリファレンスで確認できます。tidy -help-config の冒頭に出る「wrap: 72」は設定ファイルの書き方の例で、既定値ではありません。クイックリファレンスと -show-config の値はどちらも68です。
| オプション | 既定値 | 指定したときの動き |
|---|---|---|
-i(indent) |
no | ブロック要素を字下げ |
indent-spaces |
2 | 字下げの幅 |
-w(wrap) |
68 | -w 0 で折り返さない |
--tidy-mark |
yes | no でgeneratorメタを入れない |
--char-encoding |
utf8 | 入出力の文字コード |
--show-body-only |
no | yes でbody内だけを出力 |
--drop-empty-elements |
yes | no で空要素を残す |
--custom-tags |
no | カスタム要素を受け入れる |
文字コードの既定はUTF-8なので、UTF-8の日本語HTMLは指定なしでも化けません。Shift_JISのファイルは -shiftjis を付けるか、事前にUTF-8へ変換します。
設定ファイルtidy.confによる整形ルールの固定
オプションは「名前: 値」の形で設定ファイルにまとめ、-config で読み込めます。リポジトリに置けば、手元とCIで同じルールを使えます。同じ項目を設定ファイルとコマンドラインの両方で指定した場合は、後に書いた方が勝ちます。-wrap 20 -config tidy.conf では設定ファイルの値が、-config tidy.conf -wrap 20 では20が使われました。
# tidy.conf
indent: yes
wrap: 0
tidy-mark: no
drop-empty-elements: no
custom-tags: blocklevel
tidy -config tidy.conf -m index.html
htmlタグの修正で出る警告と直し方(実測メッセージ)
HTML Tidyの警告は、どの行のどの列で何を直したかを示します。<div> と <li> の閉じ忘れ、<b><i>強調</b></i> という入れ子の交差、alt のない画像を仕込んだファイルを tidy -q -e -utf8 に通した結果です。
line 8 column 7 - Warning: replacing unexpected b with </b>
line 8 column 16 - Warning: inserting implicit <i>
line 5 column 1 - Warning: missing </div>
line 6 column 1 - Warning: <img> lacks "alt" attribute
line 8 column 16 - Warning: trimming empty <i>
同じファイルを tidy -q -i -utf8 --tidy-mark no で整形すると、本文部分は次のようになりました。
<body>
<div class="box">
<img src="logo.png">
<ul>
<li>項目1</li>
<li>項目2</li>
</ul>
<p><b><i>強調</i></b></p>
</div>
</body>
<li> の閉じタグはHTMLの仕様上省略できるため、警告なしで補われます。交差していた強調タグは正しい入れ子に組み替えられ、</div> は文書の末尾に補われました。この「どこで閉じるか」はTidyの推測です。missing </div> が出たときは、意図した位置で閉じているかを必ず目で確かめてください。alt の欠落は警告だけで、整形後も <img src="logo.png"> のままです。代替テキストの中身は人が書くしかないので、HTML Tidyが直すのは構造の誤りまでと考えると使い分けを誤りません。
部分HTML・アイコン・カスタム要素で崩れる原因と回避設定
いまのHTMLにHTML Tidyを既定のまま通すと、3つの場面で出力が崩れます。CMSの本文欄に貼る断片、Font Awesomeのような空の <i> を使うアイコン、Web Componentsのカスタム要素です。次の断片で確かめました。
<div class="card"><h2>見出し</h2><p>本文<i class="fa fa-star"></i><span></span></p><my-widget data-x="1">中身</my-widget></div>
既定のまま実行すると、DOCTYPEと <title> の欠落を警告したうえで「Error: <my-widget> is not recognized!」となり、終了コード2で何も出力しません。さらに「trimming empty <i>」「trimming empty <span>」の警告どおり、空要素は削除の対象です。アイコンは中身が空のタグにCSSで描くため、削られると表示から消えます。
3つのオプションを足すと、断片のまま正しく整形されました。
tidy -q -i -utf8 --show-body-only yes --drop-empty-elements no --custom-tags blocklevel frag.html
<div class="card">
<h2>見出し</h2>
<p>本文<i class="fa fa-star"></i><span></span></p>
<my-widget data-x="1">中身</my-widget>
</div>
--show-body-only yes は <body> の中身だけを出力し、DOCTYPEや <head> を足しません。--custom-tags はハイフンを含む自律カスタム要素を受け入れる設定で、値は blocklevel・inline・empty・pre から選びます。この例の <my-widget> は <div> の直下にあるので blocklevel で問題ありません。一方、<p>前<my-tag>中</my-tag>後</p> を blocklevel で整形すると、段落が「前」で閉じられて「後」が段落の外に出てしまいました。inline なら元の1段落のまま残ります。それでも「<my-widget> is not approved by W3C」の警告は残り、終了コードは1になります。カスタム要素を使うサイトでは、CIの失敗条件を「2以上」にしてください。
テンプレートエンジンの構文({{ }} や {% %})を含むファイルや、JavaScriptが組み立てるDOMは、上の設定でも書き換えられる恐れがあるため対象から外します。HTML Tidyに向くのは、ビルド後の静的HTMLと、手書きで積み上がった既存ページです。
HTML TidyのCI実行(終了コードとGitHub Actions)
終了コード0・1・2の判定基準
問題のない文書、DOCTYPEと <title> が無いだけの断片、カスタム要素を含む断片の3つを tidy -q -e に通すと、終了コードはそれぞれ0、1、2でした。2のときは「This document has errors that must be fixed before using HTML Tidy to generate a tidied up version.」と出て、整形結果を出力しません。属性値の引用符が無いといった「Info:」の指摘は警告に数えられず、それだけなら0のままです。構文エラーだけを止めたいなら2以上、DOCTYPEやtitleの欠落まで止めたいなら1以上を失敗にします。DOCTYPEや <title> の無い断片、カスタム要素を使うページは警告だけで1になるので、1以上を失敗にするのはそうした警告を整理してからにします。もう1つ、存在しないファイル名を渡したときは「is not a file!」と表示するだけで終了コードは0でした。ファイル名の受け渡しを誤ると、何も検査せずに成功扱いになります。
–muteで警告を隠したときの終了コード
特定の警告を黙らせるには、まず --mute-id yes でメッセージIDを表示させます。「missing <!DOCTYPE> declaration (MISSING_DOCTYPE)」のように行末へIDが付くので、それを --mute MISSING_DOCTYPE,MISSING_TITLE_ELEMENT のように並べます。注意したいのは、--mute で消えるのは表示だけという点です。DOCTYPEが欠けているだけのファイルで MISSING_DOCTYPE をmuteすると、画面には何も出ないのに終了コードは1のままでした。--show-warnings no でも同じです。「表示が消えたからCIも通る」とはならないので、許容する警告がある運用では終了コードを2以上で判定してください。
GitHub Actionsのワークフロー例と set -e の落とし穴
GitHub Actionsのワークフロー構文によると、run の既定シェルは set -e 付きで、shell: bash の実体は bash --noprofile --norc -eo pipefail {0} です。ファイルごとに tidy を呼ぶループをそのまま書くと、終了コード1か2を返したファイルでステップ全体が止まり、残りのファイルを検査しません。Ubuntu 26.04のコンテナで同じシェル設定を再現したところ、素朴なループは1本目のエラーで終了コード2のまま抜けました。|| rc=$? で終了コードを受け止めると、全ファイルを検査したうえで、2以上だったファイルを一覧にして失敗させられます。ファイル一覧は $(git ls-files) で受けないでください。「a b.html」は「a」と「b.html」に分かれ、日本語名は「\346\227…」のような引用表記で渡されるため、存在しないファイル扱いで終了コード0になります。下の例のようにNUL区切りで配列に読み込むと、どちらも1つのファイルとして検査されました。
name: html-tidy
on: [push, pull_request]
jobs:
tidy:
runs-on: ubuntu-26.04 # ubuntu-latest(24.04) の apt では 5.6.0 が入る
steps:
- uses: actions/checkout@v7
- run: sudo apt-get update && sudo apt-get install -y tidy
- run: tidy -v
- name: lint html
shell: bash
run: |
fail=0
mapfile -d '' files < <(git ls-files -z '*.html')
for f in "${files[@]}"; do
rc=0
tidy -q -e --show-filename yes -config tidy.conf "$f" || rc=$?
if [ "$rc" -ge 2 ]; then
echo "NG ($rc): $f"
fail=1
fi
done
exit "$fail"
actions/runner-imagesの一覧では、2026年10月時点で ubuntu-latest は ubuntu-24.04 を指します。Ubuntu 24.04のaptで入るtidyは5.6.0、26.04は5.8.0でした。今回試したファイルでは両者の警告と終了コードは一致しましたが、手元と版が違うまま運用すると差が出たときに原因を追いにくくなります。ランナーの版を明示し、tidy -v をログに残しておくのが確実です。パイプライン全体の組み方はCI/CDの仕組みとGitHub Actionsの設定例、ワークフローの基本はGitHub Actionsでできることと使い方で解説しています。既存のビルドやデプロイの流れへ品質チェックを組み込む設計から相談したい場合は、DevOps・CI/CD導入支援も利用できます。
HTML Tidyのインストール方法(OS別と配布版のバージョン差)
HTML Tidyは配布元ごとに入る版が違います。2026年10月17日に各リポジトリで確認した結果が次の表です。
| 環境 | コマンド・入手先 | 入る版 |
|---|---|---|
| macOS(Homebrew) | brew install tidy-html5 |
5.8.0 |
| macOS 標準 | /usr/bin/tidy |
2006年のApple版 |
| Ubuntu 24.04・Debian 12 | sudo apt install tidy |
5.6.0 |
| Ubuntu 26.04・Debian 13 | sudo apt install tidy |
5.8.0 |
| Windows(winget) | winget install HTACG.tidy |
5.8.0 |
| Windows(Scoop) | scoop install tidy |
5.8.0 |
| Windows(Chocolatey) | choco install html-tidy |
5.9.14(開発版系) |
| 各OSのバイナリ | binaries.html-tidy.org | 5.8.0 |
Ubuntuの版はLaunchpadのtidy-html5パッケージで、Debianの版はsources.debian.orgで確認しました。Chocolateyの5.9.14は、GitHubで「5.9.14-next」としてプレリリース扱いになっている開発ブランチ由来の版です。正式版と同じ挙動にそろえたい場合は、winget・Scoopか公式のバイナリ配布ページのexe・msi・zipを使います。導入後は tidy -v で「version 5.8.0」と表示されるかを確かめてください。
macOS標準のtidyが2006年版である問題
macOS 26.6.2の /usr/bin/tidy -v は「HTML Tidy for Mac OS X released on 31 October 2006 – Apple Inc. build 13670」と表示します。<main> と <article> を含むHTML5文書を通すと「Error: <main> is not recognized!」で終了コード2になり、出力は0バイトでした。同じ文書はHomebrew版5.8.0なら警告なしで終了コード0です。Homebrewを入れても PATH の順序によっては標準版が先に呼ばれるので、which -a tidy で /opt/homebrew/bin か /usr/local/bin の方が先にあることを確認します。
PHPのtidy拡張によるHTML修正(PHP 8.5で実測)
CLIを呼ばずに、プログラムの中でHTMLを修正することもできます。PHPのtidy拡張はPHP本体に同梱されており、--with-tidy 付きでビルドされたPHPならそのまま使えます。PHP 8.0向けに保守されていない拡張を本体から外す案(RFC、Draftのまま)ではTidyも候補に挙がりましたが、PHP 8.4と8.5のソースにも ext/tidy は残っています。PHP 8.5.8では tidy_get_release() が「2021/07/10」を返し、php -i のlibTidy Versionは5.8.0でした。
<?php
$html = '<div class="card"><p>本文<b><i>強調</b></i><span></span></div>';
$config = ['indent' => true, 'show-body-only' => true, 'wrap' => 0, 'drop-empty-elements' => false];
$tidy = new tidy();
$tidy->parseString($html, $config, 'utf8');
$tidy->cleanRepair();
echo $tidy;
<div class="card">
<p>
本文<b><i>強調</i></b><i></i><span></span>
</p>
</div>
設定はCLIと同じ名前を配列で渡します。getStatus() は終了コードと同じく0・1・2を返し、この例では警告ありの1でした。指摘の本文は errorBuffer プロパティで取れます。入れ子を組み替えた結果、元の </i> に対応する空の <i></i> が残る点には注意が要ります。drop-empty-elements を既定のyesに戻せば消えますが、その場合はアイコン用の空タグも消えます。ユーザー投稿のHTMLを保存前に整える用途で使うなら、XSS対策は別のサニタイザで行ってください。HTML Tidyは構造を直すだけで、危険な属性やスクリプトを取り除く機能ではありません。
インストール不要でHTMLを整形する方法(オンライン版とエディタ)
ブラウザで使えるHTML整形サイトは、貼り付けてボタンを押すだけで済むため、手元に環境が無いときに便利です。選ぶときに確かめたいのは、整形をブラウザの中で行うのか、HTMLをサーバーへ送って処理するのかです。js-beautifyのようにブラウザ内で完結する実装もありますが、送信する方式のサイトもあり、画面だけでは見分けにくいことがあります。社内システムの画面や個人情報を含むHTMLは、ローカルのHTML Tidyかエディタで処理してください。
日々の整形だけならエディタの機能で足ります。Visual Studio CodeのHTML整形はjs-beautifyを基にしており、「Format Document」はmacOSで ⇧⌥F、Windowsで Shift+Alt+F、Linuxで Ctrl+Shift+I です。折り返し幅は html.format.wrapLineLength で変えられます。エディタの整形は閉じタグの抜けを直さないため、壊れたHTMLの修復や一括点検にはHTML Tidyを使います。
HTML Tidyと他のHTML整形ツールの違い(Prettier・Lint・W3C Validator)
| ツール | 整形 | 構文修正 | 検証 | 対象 |
|---|---|---|---|---|
| HTML Tidy | ○ | ○ | ○ | HTML・XHTML・XML |
| Prettier | ○ | △ | × | HTML・CSS・JS など |
| ESLint・Stylelint | △ | △ | ○ | JS・CSS |
| W3C Validator | × | × | ○ | HTML |
PrettierはHTML・CSS・JavaScriptの体裁を一律に揃える整形ツールです。<div><span>a を渡すと閉じタグを補って出力しますが、修復の内容を行番号付きの警告として報告したり、構文の誤りを終了コードで知らせたりする機能はありません。ESLintやStylelintはJavaScriptやCSSの誤りとスタイル違反を見つけるLinterで、自動修正もルールに沿った範囲に限られます。validator.w3.orgのW3C Validatorは仕様への適合を判定しますが、コードは書き換えません。新規開発で日々のコードを整えるならPrettier(またはBiome)、古いHTML資産やCMSが出力した壊れたマークアップを直すならHTML Tidy、と役割で分けると選択に迷いません。両方を入れる場合、Prettierで整形したあとにHTML Tidyを -e で検査だけに使えば、整形結果が二重に変わることもありません。
HTML Tidyの開発状況と使うべきでない場面
GitHubのhtacg/tidy-html5をGitHub APIで確認すると、2026年10月17日時点で最新の正式版は2021年7月16日の5.8.0、既定ブランチnextの最終コミットは2022年1月25日、未解決はプルリクエストを含めて242件(issueだけで218件)でした。アーカイブはされていないものの、既定ブランチへのコミットは4年以上ありません。HTML5の主要な要素は5.8.0で扱えますが、新しく追加される要素や属性への追随は見込めません。
そのため、次のような使い方は避けてください。
- ReactやVueなどのコンポーネント、テンプレートエンジンのソースへの適用(構文を書き換えられる)
- 新しい仕様の検証役としての利用(仕様への適合確認はW3C Validatorを使う)
- ユーザー入力の無害化(構造を直すだけで、危険な属性は残る)
- 警告を整理する前の既存ページに、警告0件をCIの必須条件として課すこと(DOCTYPEの無い断片やカスタム要素は警告だけで落ちる)
反対に、ビルド後の静的HTMLの点検、移行前の旧サイトの一括修復、CMSが出力した本文断片の整形といった用途なら、閉じタグの補完・入れ子の組み替え・終了コードでの合否判定を1コマンドで済ませられる点が今も役に立ちます。
よくある質問
HTML Tidyは今も更新されていますか?
正式版は2021年7月16日の5.8.0が最新で、開発ブランチの最終コミットも2022年1月25日です。プロジェクトはアーカイブされていませんが、新しい仕様への対応は期待できません。既存HTMLの整形と修復には今も実用になります。
Macに最初から入っているtidyは使えますか?
HTML5の文書には使えません。/usr/bin/tidy は2006年のApple版で、<main> や <article> を含む文書はエラーになり何も出力しません。brew install tidy-html5 で5.8.0を入れ、tidy -v の表示が「HTML Tidy for Apple macOS version 5.8.0」になることを確認してから使います。
HTMLタグの閉じ忘れを自動で修正できますか?
できます。tidy -i -m ファイル名 で閉じタグを補い、交差した入れ子を組み替えて上書きします。ただし閉じる位置はTidyの推測なので、「missing </div>」と出た箇所は意図どおりか確認してください。alt の欠落のように内容が必要な誤りは警告だけです。
HTMLの一部分(断片)だけを整形できますか?
--show-body-only yes を付ければ、DOCTYPEや <head> を足さずに断片のまま出力します。アイコン用の空タグを残すなら --drop-empty-elements no、カスタム要素があるなら --custom-tags も併せて指定し、段落の中で使う要素は inline、ブロックとして置く要素は blocklevel を選びます。
PrettierとHTML Tidyはどちらを使うべきですか?
目的で選びます。HTML・CSS・JavaScriptの体裁を揃えるならPrettier、壊れたHTMLを直したり構文の誤りをCIで止めたりするならHTML Tidyです。併用するなら、整形はPrettier、検査はHTML Tidyの -e と役割を分けます。