onloadでiframeに追加したsandbox属性が無視される。
対処法:ChromiumベースのブラウザやIEでは iframe を含むページが先頭から表示されない場合がある。(iframe で開くページのURLに「#~」があると起こる)の続きのようなもの。
そもそもの発端
「iframe を含むページが先頭から表示されない場合がある。(「#~」との関係)」
そこ対処法でiframeにsandbox属性を追加することにしたが、iframeの中を切り替える必要が生じて、そのうちの一つがGoogleカレンダーで、Googleカレンダーを埋め込みたいが、sandbox属性が邪魔をする。
test3-1-0.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>バグ?</title>
</head>
<body>
<div style="height:200px;">
バナー、ヘッダなど。
</div>
<div style="height:250px;">
<h4>↓↓↓iframe↓↓↓</h4>
<iframe src="test00-0.html#y500" name="test00" id="test00" title="test00" sandbox="allow-popups allow-popups-to-escape-sandbox allow-scripts"></iframe>
</div>
<div style="height:1000px;">
<a href="test3-1-0.html">このページへのリンク</a><br>
iframe内切替<br>
[<a href="test00-0.html#y500" target="test00">test00-0.html#y500</a>]<br>
[<a href="test00-0.html" target="test00">test00-0.html</a>]<br>
[<a href="https://calendar.google.com/calendar/embed?src=ja.japanese%23holiday%40group.v.calendar.google.com&ctz=Asia%2FTokyo&mode=AGENDA" target="test00">Googleカレンダー</a>]<br>
</div>
</body>
</html>
そこで、Javascriptを用いて、sandbox属性を消したり追加したりすることにした。
test3-1-2-0.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>バグ?</title>
<script>
<!--
function sandbox(n){ // iframeのsandboxを切り替える
var elem = document.getElementById("test00")
if(n == 0){
elem.removeAttribute("sandbox");
}else{
elem.sandbox="allow-popups allow-popups-to-escape-sandbox";
};
}
-->
</script>
</head>
<body onload="sandbox(1)">
<div style="height:200px;">
バナー、ヘッダなど。
</div>
<div style="height:250px;">
<h4>↓↓↓iframe↓↓↓</h4>
<iframe src="test00-0.html#y500" name="test00" id="test00" title="test00"></iframe>
</div>
<div style="height:1000px;">
<a href="test3-1-0.html">このページへのリンク</a><br>
iframe内切替<br>
[<a href="test00-0.html#y500" target="test00" onclick='sandbox(1);'>test00-0.html#y500</a>]<br>
[<a href="test00-0.html" target="test00">test00-0.html</a>]<br>
[<a href="https://calendar.google.com/calendar/embed?src=ja.japanese%23holiday%40group.v.calendar.google.com&ctz=Asia%2FTokyo&mode=AGENDA" target="test00" onclick='sandbox(0);'>Googleカレンダー</a>]<br>
</div>
</body>
</html>
iframeには最初はsandbox属性を付けず、bodyタグのonloadで追加することにした。
しかし、ページを開いた直後はsandbox属性が無視されている。
開いた直後に先頭から表示されなかったり、[test00-0.html#y500]をクリックすれば再現する。
ただし、[test00-0.html]や[Googleカレンダー]をクリックした後であれば問題ない。
ページを開いた後にsandbox属性がiframeに追加されていることは、EdgeのF12で確認できる。
これはEdgeの問題ではなく、onloadの仕様の可能性がある。
勝手にスクロールするバグはEdgeでしか再現できないが、sandboxが機能すればGoogleカレンダーが表示できない問題はFirefoxで再現でき、逆にGoogleカレンダーが表示できた場合はsandboxが機能してないことを表す。
test3-1-2-00.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>バグ?</title>
<script>
<!--
function sandbox(n){ // iframeのsandboxを切り替える
var elem = document.getElementById("test00")
if(n == 0){
elem.removeAttribute("sandbox");
}else{
elem.sandbox="allow-popups allow-popups-to-escape-sandbox";
};
}
-->
</script>
</head>
<body onload="sandbox(1)">
<div style="height:200px;">
バナー、ヘッダなど。
</div>
<div style="height:250px;">
<h4>↓↓↓iframe↓↓↓</h4>
<iframe src="https://calendar.google.com/calendar/embed?src=ja.japanese%23holiday%40group.v.calendar.google.com&ctz=Asia%2FTokyo&mode=AGENDA" name="test00" id="test00" title="test00"></iframe>
</div>
<div style="height:1000px;">
<a href="test3-1-0.html">このページへのリンク</a><br>
iframe内切替<br>
[<a href="test00-0.html#y500" target="test00" onclick='sandbox(1);'>test00-0.html#y500</a>]<br>
[<a href="test00-0.html" target="test00">test00-0.html</a>]<br>
[<a href="https://calendar.google.com/calendar/embed?src=ja.japanese%23holiday%40group.v.calendar.google.com&ctz=Asia%2FTokyo&mode=AGENDA" target="test00" onclick='sandbox(0);'>Googleカレンダー</a>]<br>
</div>
</body>
</html>
FirefoxでGoogleカレンダーが表示されてしまった。
ネットでDOMContentLoadedを使うべきだという情報を見たので使ってみた。
test3-1-2-01.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>バグ?</title>
<script>
<!--
function sandbox(n){ // iframeのsandboxを切り替える
var elem = document.getElementById("test00")
if(n == 0){
elem.removeAttribute("sandbox");
}else{
elem.sandbox="allow-popups allow-popups-to-escape-sandbox";
};
}
document.addEventListener('DOMContentLoaded', function(){sandbox(1);});
-->
</script>
</head>
<body>
<div style="height:200px;">
バナー、ヘッダなど。
</div>
<div style="height:250px;">
<h4>↓↓↓iframe↓↓↓</h4>
<iframe src="https://calendar.google.com/calendar/embed?src=ja.japanese%23holiday%40group.v.calendar.google.com&ctz=Asia%2FTokyo&mode=AGENDA" name="test00" id="test00" title="test00"></iframe>
</div>
<div style="height:1000px;">
<a href="test3-1-0.html">このページへのリンク</a><br>
iframe内切替<br>
[<a href="test00-0.html#y500" target="test00" onclick='sandbox(1);'>test00-0.html#y500</a>]<br>
[<a href="test00-0.html" target="test00">test00-0.html</a>]<br>
[<a href="https://calendar.google.com/calendar/embed?src=ja.japanese%23holiday%40group.v.calendar.google.com&ctz=Asia%2FTokyo&mode=AGENDA" target="test00" onclick='sandbox(0);'>Googleカレンダー</a>]<br>
</div>
</body>
</html>
始めて表示した時、Firefoxでは対処できたように見えた。しかし、次のソースでは対処できていなかった。
test3-1-2-1.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>バグ?</title>
<script>
<!--
function sandbox(n){ // iframeのsandboxを切り替える
var elem = document.getElementById("test00")
if(n == 0){
elem.removeAttribute("sandbox");
}else{
elem.sandbox="allow-popups allow-popups-to-escape-sandbox";
};
}
document.addEventListener('DOMContentLoaded', function(){sandbox(1);});
-->
</script>
</head>
<body>
<div style="height:200px;">
バナー、ヘッダなど。
</div>
<div style="height:250px;">
<h4>↓↓↓iframe↓↓↓</h4>
<iframe src="test00-0.html#y500" name="test00" id="test00" title="test00" sandbox=""></iframe>
</div>
<div style="height:1000px;">
<a href="test3-1-0.html">このページへのリンク</a><br>
iframe内切替<br>
[<a href="test00-0.html#y500" target="test00" onclick='sandbox(1);'>test00-0.html#y500</a>]<br>
[<a href="test00-0.html" target="test00">test00-0.html</a>]<br>
[<a href="https://calendar.google.com/calendar/embed?src=ja.japanese%23holiday%40group.v.calendar.google.com&ctz=Asia%2FTokyo&mode=AGENDA" target="test00" onclick='sandbox(0);'>Googleカレンダー</a>]<br>
</div>
</body>
</html>
予めiframeにsandbox=""が入ってる。
sandbox="allow-popups allow-popups-to-escape-sandbox"
としないと、iframeの中のリンクをクリックしても反応しない。
もしも、DOMContentLoadedでiframeの中のsandboxが書き換えられていれば、iframeの中のリンクをクリックしたら新しいタブで開くはずである。
しかし、開かなかった。すなわち、sandboxの書き換えが無視された。Firefoxでも対処できなかった。
このソースのページを開いた後、対処できていたようなページ test3-1-2-01.html をFirefoxの同じタブで開いたらGoogleカレンダーが表示された。すなわち、追加されたsandboxが無視された。
しかし、そのタブをリロードしたら、Googleカレンダーが表示されなくなった。すなわち、追加されたsandboxが機能した。
ところで、上記の test3-1-2-01.html と test3-1-2-1.html では対処できていなかった。
すなわち、DOMContentLoadedでも対処できなかった。ただし、使い方を間違っていたら分からないが、たぶんダメだろう。
結論としては、最初からiframeに
sandbox="allow-popups allow-popups-to-escape-sandbox"
を入れておいた方が良い。
bodyタグのonloadで追加しようとしたのが間違い。
ちなみに、
test00-0.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>iframe内</title>
</head>
<body>
<p style="height:500px;">iframe内</p>
<p style="height:500px;" id="y500">
<span>iframe内500px</span><br>
<a href="test00-0.html" target="_blank">test00-0.html</a>
</p>
</body>
</html>
追記(2023/10/18):
新たな情報が入った。bingにこの問題の原因を尋ねて次のサイトを紹介してもらった。
iframeのsandbox属性の動的設定 #JavaScript - Qiita
https://qiita.com/P488/items/a75386b46efb8a3bee6c
sandbox属性は属性を変更するだけでは反映されません。sandbox属性の変更を反映させるには、フレームを再読み込みする必要があります。
<iframe src="frame"></iframe>
const iframe = document.getElementById('frame'); iframe.sandbox.add("allow-top-navigation"); // この段階では反映されない。 iframe.contentWindow.location.reload(); // ここで反映される。
この情報を踏まえて、コードを次のように変更した。
test3-1-2-2.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>バグ?</title>
<script>
<!--
function sandbox(n){ // iframeのsandboxを切り替える
var elem = document.getElementById("test00")
if(n == 0){
elem.removeAttribute("sandbox");
}else{
elem.sandbox="allow-popups allow-popups-to-escape-sandbox";
};
elem.contentWindow.location.reload();
}
-->
</script>
</head>
<body onload="sandbox(1)">
<div style="height:200px;">
バナー、ヘッダなど。
</div>
<div style="height:250px;">
<h4>↓↓↓iframe↓↓↓</h4>
<iframe src="test00-0.html#y500" name="test00" id="test00" title="test00"></iframe>
</div>
<div style="height:1000px;">
<a href="test3-1-0.html">このページへのリンク</a><br>
iframe内切替<br>
[<a href="test00-0.html#y500" target="test00" onclick='sandbox(1);'>test00-0.html#y500</a>]<br>
[<a href="test00-0.html" target="test00">test00-0.html</a>]<br>
[<a href="https://calendar.google.com/calendar/embed?src=ja.japanese%23holiday%40group.v.calendar.google.com&ctz=Asia%2FTokyo&mode=AGENDA" target="test00" onclick='sandbox(0);'>Googleカレンダー</a>]<br>
</div>
</body>
</html>
その結果、Edgeでページを開いた直後はsandbox属性が無視されて、iframeの所までスクロールしてしまったが、リンクをクリックする際にはsandbox属性が機能していた。また、読み込んだ後、リロードすれば同じタブでも追加したsandbox属性は機能していた。
まだ、開いた直後に無視されてしまうようなので改善が必要だが、参考になった。
コメント
コメントを投稿