IE8以下におけるiframeの境界線(frameborder)問題

IE8以下でiframe要素が生成するインラインフレームの境界線を非表示にするにはCSSのborder関連プロパティで代替できないため、HTML上で直接frameborder="0"の指定が必須なのは既知のことでしょうが、いざJavaScriptから動的に境界線の非表示を操作しようとすると思わぬどはまりをしたので、同じようなことをしようとした人が今後いたときのために備忘録を残しておきます。

先に結論から書くと、IE8以下ではiframe要素が生成するインラインフレームの境界線を動的に操作することはできません。この点を踏まえた上で様々なアプローチを試みた結果を記します。

問題点

まず、IE8以下では、ボーダー領域とは別の領域でインラインフレームの境界線をレンダリングしているためCSSのborder関連プロパティでは代替できないようになっており、この境界線を非表示にできるのが唯一frameborder属性を用いてframeborder="0"を指定した場合だけです。

しかしHTML5では、frameborder属性が廃止となったため、HTML5のドキュメント上でframeborder属性を用いることは、Valid(正当)ではありません。もちろんブラウザをはじめとしたソフトウェアの多くは寛容に作られているので、Invalidであっても、処理できなくなったり、表示されなくなるなどのクリティカルな問題が発生するわけではありませんが、このframeborder属性を指定していることのみがInvalidの要因となるのであれば、制作者としては残念な気持ちになります。

IE8以下にのみframeborder属性の付与を試みる

先の問題点を踏まえて、問題となるIE8以下にのみframeborder属性を付与してみます。

<iframe src="sample.html" id="sample"></iframe>
<script>
if( !window.addEventListener ) {
	var iframe = document.getElementById("sample");
	iframe.frameBorder = 0; //または iframe.setAttribute("frameBorder","0"); でも可
}
</script>

最初にwindow.addEventListeneをサポートしているかを条件にIE8以下を対象にします。

JavaScriptではHTMLオブジェクトがframe要素またはiframe要素の場合、frameBorderプロパティの指定が可能です。これはsetAttributeプロパティで設定しても同様です。ただし、setAttributeプロパティを用いる場合は、IE8以下独自の問題でframeBorderとBだけ大文字で記述する必要があるようです。IE8ではsetAttribute('frameborder','0')と記述しても自動的にBだけ大文字に変換する不思議な仕組みになっています。

上記の結果は、開発ツール上ではframeBorder="0"が付与されていることが確認できますが、残念ながら境界線は非表示にはなりませんでした。

インラインフレーム自体の生成をJavaScriptで試みる

IE8以下にのみframeborder属性の付与を試みる方法では、境界線を非表示にすることができなかったのですが、次の2通りのコードを書き分けることで、先ほどの結果がなぜ非表示にならなかったのかの原因が判明しました。

<div id="here"></div>
<script>
if( !window.addEventListener ) {
	var iframe = document.createElement("iframe");
	iframe.src = "sample.html";
	iframe.id = "sample";
	iframe.frameBorder = 0;
	document.getElementById("here").appendChild(iframe);
}
</script>

この結果は、期待通り境界線が非表示になりました。次に試しにドキュメント上にインラインフレームを追加した後からframeborder属性の付与を試みると、生成されたインラインフレームがframeBorder="0"をもっていても境界線は表示されたままになります。

<div id="here"></div>
<script>
if( !window.addEventListener ) {
	var iframe = document.createElement("iframe");
	iframe.src = "sample.html";
	iframe.id = "sample";
	document.getElementById("here").appendChild(iframe);
	iframe.frameBorder = 0; //ドキュメント追加後に指定
}
</script>

これらの結果から言えることは、IE8以下ではどうやら既にドキュメント上に存在しているインラインフレームにframeborder属性を付与しても境界線を動的に操作することはできないようです。

一度削除してから再度インラインフレームを生成する

IE8のためだけにインラインフレーム自体の生成をJavaScriptに依存させてしまうのは他のブラウザにまで余計な処理をさせることになり不本意なので、IE8以下にだけ既にHTML上に存在しているインラインフレームを削除してから、再度境界線が非表示にできるようにインラインフレームの生成を試みてみます。

<iframe src="sample.html" id="sample"></iframe>
<script>
if( !window.addEventListener ) {
	var iframe = document.getElementById("sample");
	var parent = iframe.parentNode;
	parent.removeChild(iframe);
	iframe = document.createElement("iframe");
	iframe.src = "sample.html";
	iframe.id = "sample";
	iframe.frameBorder = 0;
	parent.appendChild(iframe);
}
</script>

この結果は、期待通り境界線が非表示になりましたが、今度はインラインフレーム内のドキュメントにスタイルシートが正常に適用されないという別の問題が発生してしまいました。一体どうなっているのやら、本当に変なブラウザです。

コンディショナルコメントに頼る

最後にIE9以下が独自にサポートしているIEコンディショナルコメントに頼ってみました。IE8以下以外のブラウザでは直接iframe要素を記述してインラインフレームを生成し、IE8以下ではインラインフレーム自体の生成をJavaScriptに依存させることにしました。

<div id="here"><!--[if (gt IE 8)|!(IE)]><!--><iframe src="sample.html" id="sample"></iframe><!--<![endif]--></div>
<script>
if( !window.addEventListener ) {
	var iframe = document.createElement("iframe");
	iframe.src = "sample.html";
	iframe.id = "sample";
	iframe.frameBorder = 0;
	document.getElementById("here").appendChild(iframe);
}
</script>

これであれば他のブラウザに影響を与えることなく、IE8でも期待通りインラインフレームの境界線を非表示にすることができました。でも、ただ文法上でValidにするために、独自のIEコンディショナルコメントを含めたりするのは本末転倒でここまでする意味が感じられないですよね。

結論

IE8以下でiframe要素が生成するインラインフレームの境界線を非表示にする良い代替方法はありません。また、どこまでValid、Invalidに拘ったところで、よくあるソーシャルボタンなどもインラインフレームで埋め込まれるので、それら外部のWebアプリケーションもIE8以下で境界線を消すためにframeborder="0"が指定されており、HTML5のドキュメントであれば自ずとInvalidということになります。iframe要素のframeborder属性以外にも外部のWebアプリケーションを埋め込むと強制的にInvalidになる要因は後をたちませんから、Validを追求することにも無理があると結論付けざるをえないでしょう。

Updated / Published