◆ base タグで相対パスの基準になるパスを設定できる
◆ iframe と組み合わせたらここのブロックだけ 相対パスの基準を変えたいってことができる

前にこんな記事を書きました

説明がしづらいので 分かる人多いですし特に問題ないのでマークダウンってことにします

問題点

マークダウンをエディタで書いてプレビューすると画像ファイルやリンクが相対パスだったら .md ファイルからの相対パスになると思います

次に HTML でのビュワーを作ります
ビュワーでは 適当な変換するライブラリを使って HTML に変換して ビュワーのトップページに innerHTML を埋め込む感じで表示します

こうすると a タグや img タグなどの URL を指定するところに相対パスを書いていた場合 .md ファイルからの相対パスとして書かれているのに 実際はビュワーのトップページからのパスとしてブラウザが処理してしまいます
なので 相対パスを使っていると URL 部分が全部ちゃんと動きません


前回は innerHTML を置き換えて DOM の構築した直後に querySelector で URL あるタグを取り出してプロパティの書き換えで対応していました
画像の場合でもロードする前なので 特に問題はなかったのですが なんかいい方法じゃないなぁと思ってました
img タグだと src 属性で a タグだと href 属性で と自分で全部指定する必要があります
マークダウンだとなさそうですが video や audio などのタグだって URL を書くことは可能です

base タグ

あまり知られていないタグだと思います (というか私も今回たまたま知って「コレ使える!!」と思ったわけですけど)

機能は 相対パスの基準のパスを設定します

つまりこのタグで .md のパスを書いておけば 勝手に a タグも img タグもなってほしいパスになってるんです
こんな便利タグがあったなんて!!

ですが 問題点もあります
この div 以下だけ相対パス変える っていうのはできないです
全体が変わります

一応 base タグが作られる前に読み込まれたタグは本来の 表示している HTML からの相対パスで解決されます

iframe と組み合わせる

全体の基準の URL が変わると ビュワー全体の制御用の JavaScript や 全体のデザインの CSS や画像のパスがビュワーのトップページからの相対パスじゃなくなってしまい困ります

どうにかできないかなー と考えていたら iframe が思い浮かびました

iframe は src 指定していないと about:blank になっていて window.open で about:blank を開いた時と同じで JavaScript で操作可能です

ビュワーの中でマークダウンのテキストを表示する部分を iframe にしておいて マークダウンを開いた時に base タグの href 属性を変更してから innerHTML を設定します
var framedoc = frames[0]
function init(){
framedoc.head.innerHTML = `
<link rel="stylesheet" href="style.css">
<base id="base" href="/">
`
}

function loadDoc(docpath){
var base = new URL(docpath, location.href)
framedoc.querySelector("base").href = base
fetch(docpath).then(e => e.text()).then(doc => {
var html = convertDoc(doc)
framedoc.body.innerHTML = html
})
}

init は最初に実行しておきます
base タグより前にマークダウン用の CSS を読み込んでおきます

loadDocでマークダウンの読み込みです
convertDoc はマークダウンから HTML の変換です

まとめ

base タグを iframe と組み合わせると ここのまとまりだけ相対パスの基準を変えたいってときにはとても便利です

相対パスの基準を変えたいときは たいていそこだけ別のまとまりになるはずですから 別フレームになっているせいで CSS や JavaScript が別になってしまうというのもプラスになることが多いんじゃないかと思います