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&amp;ctz=Asia%2FTokyo&amp;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&amp;ctz=Asia%2FTokyo&amp;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&amp;ctz=Asia%2FTokyo&amp;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&amp;ctz=Asia%2FTokyo&amp;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&amp;ctz=Asia%2FTokyo&amp;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&amp;ctz=Asia%2FTokyo&amp;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&amp;ctz=Asia%2FTokyo&amp;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&amp;ctz=Asia%2FTokyo&amp;mode=AGENDA" target="test00" onclick='sandbox(0);'>Googleカレンダー</a>]<br>
</div>
</body>
</html> 

その結果、Edgeでページを開いた直後はsandbox属性が無視されて、iframeの所までスクロールしてしまったが、リンクをクリックする際にはsandbox属性が機能していた。また、読み込んだ後、リロードすれば同じタブでも追加したsandbox属性は機能していた。
まだ、開いた直後に無視されてしまうようなので改善が必要だが、参考になった。

 

コメント