【ITニュース解説】My HTML-to-Markdown API learned that every framework invents its own idea of a heading
2026年10月21日に「Dev.to」が公開したITニュース「My HTML-to-Markdown API learned that every framework invents its own idea of a heading」について初心者にもわかりやすく解説しています。
ITニュース概要
HTMLをMarkdownに変換する際、Tailwind CSSなどのフレームワークが`div`タグにCSSで視覚的な見出しを作るため、タグだけでは構造を判別できない。このため、見た目の見出しを正しく変換するには、CSSクラス名から見出しを推測する特別な処理が必要となる。これは、HTMLの見た目とMarkdownの文書構造が一致しない翻訳の課題だ。
ITニュース解説
Webサイトの情報を特定の形式から別の形式へ変換するツールは、システム開発において様々な場面で活用される。今回取り上げるのは、HTML形式で書かれたWebページの内容を、よりシンプルで構造化されたMarkdown形式へ変換するツールを開発した際の実体験から得られた教訓だ。
開発者は当初、このHTML-to-Markdown変換ツールを作るのは比較的簡単な作業だと考えていた。HTML文書の構造を読み解き(これをDOMを辿ると表現する)、例えばHTMLで「見出し1」を意味する<h1>タグを見つけたらMarkdownの#に、<h2>タグなら##に置き換えていけば良い、とシンプルな設計を想像していた。HTMLのタグにはそれぞれ意味があり、見出しタグはその意味通りに文書の階層構造を示しているはず、という前提があったからだ。
しかし、最初の実世界でのテストで、その前提が覆されることになった。あるWebサイト(Next.jsという技術を使って作られたドキュメントサイト)を変換したところ、出力されたMarkdownは、ただの太字のテキストが羅列されたもので、見出しの構造が全く失われていたのだ。
この問題の原因は、Tailwind CSSというCSSフレームワークが使われていたことだった。現代のWebサイト開発では、見た目を効率的に整えるためにCSSフレームワークが広く利用されている。Tailwind CSSはその一つで、従来の<h1>や<h2>といった「見出しタグ」を使う代わりに、<div class="text-2xl font-bold mb-4">のように、汎用的なdivタグに直接見た目を定義するCSSクラス(例:文字サイズを大きくするtext-2xl、太字にするfont-bold、下部に余白を設けるmb-4など)を適用して、視覚的に見出しを表現することが頻繁に行われる。これにより、HTMLの構造そのものには見出しタグが存在しなくても、ユーザーがブラウザで見たときにはきちんと見出しとして認識できるページが作成されていたのだ。
開発者が作った変換ツールは、HTMLの「意味的な(セマンティックな)タグ」だけを見ていたため、divタグに適用されたCSSクラスからそれが「見出し」であることを判断できなかった。結果として、見た目は完璧なドキュメントページであっても、ツールはただのdiv要素として扱い、見出しとしての構造を抽出できなかったのである。
この問題に対して開発者は、「HTMLの解析方法をもっと賢くする」という方向ではなく、「見出しとは、もはやHTMLタグのような意味的な概念ではなく、視覚的な概念である」という現実を受け入れる方向へと発想を転換した。そこで導入されたのが「ヒューリスティック」な手法だ。これは、完全に正確ではないかもしれないが、経験則に基づいて「おそらく正しいだろう」と判断するアプローチを指す。具体的には、HTMLの構造を解析する前に、Webページ上のすべての要素のCSSクラス名が、一般的な見出しのパターン(例えば、text-xl、font-bold、font-semibold、余白を示すmb-など)に一致するかどうかを事前にスキャンし、これらのパターンに合致する要素を「見出し」として昇格させるようにしたのだ。この方法は完璧ではないし、時に間違った結果を生む可能性もはらんでいたが、Tailwind CSSを使っているサイトの約80%で期待通りに機能することが判明した。
しかし、これで全てが解決したわけではなかった。次にテストしたのはBootstrapという別のCSSフレームワークが使われているサイトだった。このサイトでは、<h1 class="h3">というHTMLが使われていた。これは本来「見出し1」を意味する<h1>タグを使っているにもかかわらず、class="h3"というBootstrapのクラスによって、視覚的には「見出し3」程度の小さなサブ見出しとして表示されていたのだ。開発者の導入したヒューリスティックは、「意味的なタグ」である<h1>を信頼してMarkdownで#(見出し1)に変換してしまったため、ページの実際の見た目とは異なる、不適切な出力となってしまった。
この問題に対処するため、開発者はさらに「逆チェック」の機能を追加する必要に迫られた。それは、もし本来の意味的な見出しタグ(h1からh6まで)が使われているにもかかわらず、CSSクラス(Bootstrapのh3クラスなど)によって視覚的にその階層が下げられている場合、出力するMarkdownの見出しレベルもそれに合わせて降格させる、という処理だった。
これらの経験から開発者が得た最も重要な教訓は、HTMLからMarkdownへの変換は、単なるHTMLの構文解析問題ではなく、「2つの異なる概念体系(オントロジー)の間の翻訳問題」である、という点だ。HTMLの作成者は、多くの場合「ブラウザでの見た目」つまり「視覚的な階層」を意識してマークアップを行う。一方、Markdownの利用者は、「文書の論理的な構造」つまり「文書の階層」を期待する。この二つの考え方が、たまたま一致することはあるが、常に一致するわけではない。そして、Tailwind CSSやBootstrapといった各CSSフレームワークは、「何が見出しのように見えるか」という独自の「方言」を持っているため、この問題はさらに複雑になる。
最終的に、開発者はこの視覚的ヒューリスティックを、デフォルトではオフの「オプトイン(利用者が選択して有効にする)機能」として提供することにした。なぜなら、このヒューリスティックは完璧ではなく、誤った結果を生むこともあるため、予期しない変換でユーザーを困惑させたくなかったからだ。もしWebサイトがユーティリティCSSフレームワーク(Tailwind CSSなど)で構築されたマーケティングサイトやドキュメントページを対象とする場合はこの機能をオンにし、より意味的な構造を持つHTMLをCMS(コンテンツ管理システム)から取り込む場合はオフにする、といった使い分けをユーザーに促している。
この一連の経験は、Web開発における多様な技術と、それらがもたらす複雑さを浮き彫りにしている。システムエンジニアとして、単に技術仕様を理解するだけでなく、現実世界の多様な実装パターンや、ユーザーが何を期待しているかという視点も持ち合わせることが、効果的な問題解決には不可欠だということを示唆している。