ラック
Home > ブログ > 記事 > 2016年1月 > iPhone・iPadのSafariでbackground-imageが一部しか表示されない

iPhone・iPadのSafariでbackground-imageが一部しか表示されない

カテゴリ:

アイキャッチ画像をドーン!と画面全体に表示させるタイプのトップページ、よく見かけるようになりましたね。

あれにフェードイン・フェードアウトによるスライドショーを追加してみたくなりました。

で、いざページを作成してみたところ…ちょっと不可解なバグに遭遇したのでメモしておきます。

 

結論だけ先に述べると、結局原因が特定できなかったので「ユーザーエージェント判定してiPhoneあるいはiPadの場合のみjQueryでbackground-sizeとbackground-positionの指定を書き換える」というバッドノウハウになりました。

 

症状

タイトルにもありますが、症状としては「iPhone(またはiPad)のSafariでページを表示した際に、background-imageが一部分しか表示されない」というもの。

一部分というのを具体的に言うと、テンキーのように画面を9分割した場合、ちょうど“8”の部分…つまり、画像の中央上端のみが拡大表示されている状態(詳しくは下図)。


こちらがAndroidの表示。背景画像がきちんと表示されています。画像がやや汚いのはフェードで画像が切り替わる途中のため。

 


で、こちらが問題のiPhoneでの表示。真っ青…というよりは背景画像の青空の部分だけが表示されている状態。

 

そして、この症状はWindowsのIE11、Edge、Firefox、Chrome、VivaldiやAndroidスマホのChromeでは発生せず。ついでにMacPCでも発生せず。

…つまり、iPhoneやiPadの「Mobile Safari」限定の症状という、デバッグには少しばかり厄介な状況だったのです。

この症状はiPhone5もiPhone6プラスでも発生しました。

 

なお、背景画像はこんな記述をしていました(最低限のみの抜粋)。

HTML

<div id="eyeCatch" class="text-center">

	<!-- フェードスライドショー用要素 -->
	<ul>
		<li id="fade1" class="text-hide">画像1</li>
		<li id="fade2" class="text-hide">画像2</li>
		<li id="fade3" class="text-hide">画像3</li>
	</ul>
	<!-- /フェードスライドショー用要素 -->

	<div id="eyeCatchText">
		<h1>サイト名</h1>
	</div>
</div>

 

CSS

#eyeCatch {
	width: 100%;
	height: auto;
	background: #fff;
	overflow: hidden;
	z-index: 1;
}
#eyeCatch li {
	width: 100%;
	height: auto;
	z-index: 2;
	background: no-repeat center center fixed;
	-webkit-background-size: cover;
	-moz-background-size: cover;
	-ms-background-size: cover;
	-o-background-size: cover;
	background-size: cover;
}
#eyeCatch #fade1 {
	background-image: url("../img/img1.jpg");
}
#eyeCatch #fade2 {
	background-image: url("../img/img2.jpg");
}
#eyeCatch #fade3 {
	background-image: url("../img/img3.jpg");
}
#eyeCatch #eyeCatchText {
	float: left;
	position: absolute;
	top: 0;
	left: 0;
	width: 100%;
	height: 100%;
	text-align: center;
	z-index: 3;
	display: table;
}
#eyeCatch h1 {
	display: table-cell;
	vertical-align: middle;
	color: #feeeed;
	z-index: 3;
	text-shadow: 1px 1px 0 #fa8d94;
	font-size: 56px;
}

※この他にもbootstrap3を使用。

 

jQuery

$(function() {
	var height = $(window).height();
	var $eyeCatch = $("#eyeCatch");
	$eyeCatch.css({ height: height });

	//フェードスライドショー
	var fadeSpeed = 2000, switchDelay = 7000;
	$eyeCatch.each(function(){
		var targetObj = $(this);
		var findUl = targetObj.find('ul');
		var findLi = targetObj.find('li');
		var findLiFirst = targetObj.find('li:first');

		findLi.css({display:'inline-block',opacity:'0',zIndex:'1'});
		findLiFirst.css({zIndex:'2'}).stop().animate({opacity:'1'},fadeSpeed);

		setInterval(function(){
			findUl.find('li:first-child').animate({opacity:'0'},fadeSpeed).next('li').css({zIndex:'2'}).animate({opacity:'1'},fadeSpeed).end().appendTo(findUl).css({zIndex:'1'});
		},switchDelay);
	});
});

※やんごとなき事情により、li要素にimgタグで埋め込むのではなく、背景画像として指定しています。

たぶんimgタグで記述すればこんなバグには遭遇しなかったのではないかと思うのですが試していません(本来やりたいことがやりづらくなるので)。

 

経緯

手持ちのWindowsPCとAndroidで確認して大丈夫だったのですが、ついでに~と思ってiPadで確認したらびっくり。画像が表示されておらず真っ白な画面になっていました。

…よくよく見てみると正確には画面は真っ白ではなく、下の方に画像の上端が少しだけ映っていました。約1/3程度でしょうか。

そこで、この正体不明な余白を埋めるため、position:absoluteとleft:0、top:0で背景画像を割り当てている要素の位置を固定しました。

すると今度は、冒頭で述べた症状。なぜか画面全体に対して画像が上端部分しか表示されていないという状態になったのでした。

 

この時点で記述はこんな感じ。

CSS

#eyeCatch {
	width: 100%;
	height: auto;
	background: #fff;
	overflow: hidden;
	z-index: 1;
}
#eyeCatch li {
	float: left; /* 追加 */
	position: absolute; /* 追加 */
	top: 0; /* 追加 */
	left: 0; /* 追加 */
	width: 100%;
	height: auto;
	z-index: 2;
	background: no-repeat center center fixed
	-webkit-background-size: cover;
	-moz-background-size: cover;
	-ms-background-size: cover;
	-o-background-size: cover;
	background-size: cover;
}
#eyeCatch #fade1 {
	background-image: url("../img/img1.jpg");
}
#eyeCatch #fade2 {
	background-image: url("../img/img2.jpg") no-repeat center center fixed;
}
#eyeCatch #fade3 {
	background-image: url("../img/img3.jpg") no-repeat center center fixed;
}
#eyeCatch #eyeCatchText {
	float: left;
	position: absolute;
	top: 0;
	left: 0;
	width: 100%;
	height: 100%;
	text-align: center;
	z-index: 3;
	display: table;
}
#eyeCatch h1 {
	display: table-cell;
	vertical-align: middle;
	color: #feeeed;
	z-index: 3;
	text-shadow: 1px 1px 0 #fa8d94;
	font-size: 56px;
}

li要素に指定を加えました。ここで、トラップカード・冒頭で述べた症状が発動!

 

対処過程

ここからが長かった。土日は手元にiPhoneもiPadもない環境にいたので「修正→手元で確認」ができない。

インターネットの力を借りてiPhoneユーザに確認してもらい、また修正…という非常に時間のかかるデバッグをやっていました。

結果的に原因が一向に分からず土日が消えました。かなしみ。

そして悲しみの途中経過。色々書き加えてカオスになってきました。

CSS

#eyeCatch {
	width: 100%;
	height: 100vh; /* 高さ指定をjQueryではなくcssで指定 */
	background: #fff;
	overflow: hidden;
	z-index: 1;
}
#eyeCatch ul {
	position: relative;
	width: 100%;
	height: 100vh; /* ulも高さ指定。floatしてるから意味ないと思うけど */
	list-style-type: none; /* list-styleのマーカーが原因? */
	list-style-position: outside;
	margin-left: 0; /* マージン消えろ */
	margin-top: 0;
	padding-left: 0; /* パディング消えろ */
	padding-top: 0;
}
#eyeCatch li {
	float: left;
	position: absolute;
	top: 0;
	left: 0;
	width: 100%;
	height: 100vh;
	background-repeat: no-repeat; /* 個別に記述してはどうか */
	background-position: center center;
	background-attachment: fixed;
	background-size: cover;
	background-clip: border-box;
	background-origin: border-box;
	z-index: 2;
}
#eyeCatch #fade1 {
	background-image: url("../img/img1.jpg");
	-webkit-background-size: cover; /* sizeは他の指定より後ろ */
	-moz-background-size: cover;
	-ms-background-size: cover;
	-o-background-size: cover;
	background-size: cover;
}
#eyeCatch #fade2 {
	background-image: url("../img/img2.jpg");
	-webkit-background-size: cover;
	-moz-background-size: cover;
	-ms-background-size: cover;
	-o-background-size: cover;
	background-size: cover;
}
#eyeCatch #fade3 {
	background-image: url("../img/img3.jpg");
	-webkit-background-size: cover;
	-moz-background-size: cover;
	-ms-background-size: cover;
	-o-background-size: cover;
	background-size: cover;
}
#eyeCatch #eyeCatchText {
	float: left;
	position: absolute;
	top: 0;
	left: 0;
	width: 100%;
	height: 100%;
	text-align: center;
	z-index: 3;
	display: table;
}
#eyeCatch h1 {
	display: table-cell;
	vertical-align: middle;
	color: #feeeed;
	z-index: 3;
	text-shadow: 1px 1px 0 #fa8d94;
	font-size: 56px;
}

 

jQuery

$(function() {
//	var height = $(window).height(); //vhにしたので用済み
	var $eyeCatch = $("#eyeCatch");
//	$eyeCatch.css({ height: height }); //vhにしたので用済み

	//フェードスライドショー
	var fadeSpeed = 2000, switchDelay = 7000;
	$eyeCatch.each(function(){
		var targetObj = $(this);
		var findUl = targetObj.find('ul');
		var findLi = targetObj.find('li');
		var findLiFirst = targetObj.find('li:first');

		findLi.css({display:'inline-block',opacity:'0',zIndex:'1'});
		findLiFirst.css({zIndex:'2'}).stop().animate({opacity:'1'},fadeSpeed);

		setInterval(function(){
			findUl.find('li:first-child').animate({opacity:'0'},fadeSpeed).next('li').css({zIndex:'2'}).animate({opacity:'1'},fadeSpeed).end().appendTo(findUl).css({zIndex:'1'});
		},switchDelay);
	});
});

この他にも

  • ul, liではなくdiv, divにしたらどうか(list-style絡みを疑った) → 効果なし
  • liではなくて親のdiv#eyeCatchに直接background-imageを指定 → やはり上端しか表示されない
  • background-sizeをcoverではなくcontainやpx、%指定に変えてみる → containにしたら真っ白になった。サイズを変更すると位置は変わるものの根本的に変化なし
  • 画像のサイズを原寸から50%や30%に縮小してみる → 拡大表示されて荒い画像になっただけ。background-size: containとかにしても同じ。
  • liのfloat: leftを無効化

など試してみましたが解決に至らず。これは本格的に迷宮入りしそうな感じです。

かといってまさか「iPhone悉く見なかったことにする、iPad悉く聞かなかったことにする!」…というわけにも行かず。ましてiPhone4とかではなく最近の機種で発現している状態ですし。古いIEやAndroid標準ブラウザならいざ知らず。

 

ただ、色々実験を繰り返すうちになんとなく原因の輪郭が見えてきました。

他のブラウザは表示領域(この場合はdiv#eyeCatch)の高さに合わせて画像が収まるように表示される(スマホでポートレートの場合は左右がカットされますが)のに対し、Mobile Safariはこの高さの制約が効いていない模様。

表示させる画像のサイズを変更しても症状に変化がなかったことから、どうやら「div#eyeCatchではない他の要素の高さ(div#eyeCatchよりもかなり大きい)を100%として、それに合わせるように画像を描画している」ような感じではないかという推測に至りました。

さらに、「background-position: center center」という指定をしているため、画像は左右でいえば中央部分(テンキーの8, 5, 2の列)が表示された、と。

その上で、高さが上記のようにおかしなことになっているため、background-size: coverだと上端のみ、containやpxや%指定だと謎の高さを持った領域の中央に画像が配置されるため、div#eyeCatchよりも下に配置され、結果的にdiv#eyeCatchの中は真っ白になったものと思われます。

おそらく、最初の画像の上端3/1程度しか表示されないのも、原因は同じではないでしょうか…。

このときの感覚としては、bodyあるいはhtml全体の高さを100%として計算しているような感じに見えました。

 

対処過程2

さて、原因がぼんやり見えてきたのは良いのですが、問題はMobile Safariにどうやって「liの高さはdiv#eyeCatchと同じなんじゃよ!それにきっちり収まるように画像を表示せんかい!」と鞭打って覚え込ませて叩き込むか、です。

そこでbackground-sizeやbackground-position辺りに狙いを絞り込んで、時折jQueryで変化球を打ち込んでみるものの豆腐に鎹糠に釘。あるいは暖簾に腕押し。いや、ここはどちらかというと瓢箪鯰の方が良いか。

確かに形は変わるのですが、今度は他のブラウザで表示がおかしくなります。

本当はbackground-size: cover一本勝負一本足打法で行きたいのですが…Mobile Safariが言うことを聞いてくれません。

1/13にMicrosoftによる古いIEのサポートが終了したのを受けてvhも使えるだろう、と投入したりもしたのですがそれでもダメ。

 

最終対処

にっちもさっちも行かなくなったので最終手段。

ここらで「Mobile Safariの場合のみCSSの指定を変える」という力押し、トドメのとっておきのダメ押しを使うことにしました。

できればもっとスマートに対応したかったので上記のように色々あがいてみたのですが…。

CSS

#eyeCatch {
	width: 100%;
	height: 100vh;
	background: #fff;
	overflow: hidden;
	z-index: 1;
}
#eyeCatch li {
	position: absolute;
	top: 0;
	left: 0;
	width: 100%;
	height: 100vh;
	background: no-repeat center center fixed;
	-webkit-background-size: cover;
	-moz-background-size: cover;
	-ms-background-size: cover;
	-o-background-size: cover;
	background-size: cover;
	z-index: 2;
}
#eyeCatch #fade1 {
	background-image: url("../img/img1.jpg");
}
#eyeCatch #fade2 {
	background-image: url("../img/img2.jpg");
}
#eyeCatch #fade3 {
	background-image: url("../img/img3.jpg");
}
#eyeCatch #eyeCatchText {
	float: left;
	position: absolute;
	top: 0;
	left: 0;
	width: 100%;
	height: 100%;
	text-align: center;
	z-index: 3;
	display: table;
}
#eyeCatch h1 {
	display: table-cell;
	vertical-align: middle;
	color: #feeeed;
	z-index: 3;
	text-shadow: 1px 1px 0 #fa8d94;
	font-size: 56px;
}

 

jQuery

$(function() {
	var height = $(window).height();
	var $eyeCatch = $("#eyeCatch");

	//iPhone・iPad背景画像バグ対処
	var device = navigator.userAgent;
	if (device.indexOf('iPhone') !== -1 || device.indexOf('iPad') !== -1) {
		//iPhoneかiPadならば
		$("#eyeCatch li").css({ "background-position": "top center",
					"background-size": "auto " + height + "px" });
	}

	//フェードスライドショー
	var fadeSpeed = 2000, switchDelay = 7000;
	$eyeCatch.each(function(){
		var targetObj = $(this);
		var findUl = targetObj.find('ul');
		var findLi = targetObj.find('li');
		var findLiFirst = targetObj.find('li:first');

		findLi.css({display:'inline-block',opacity:'0',zIndex:'1'});
		findLiFirst.css({zIndex:'2'}).stop().animate({opacity:'1'},fadeSpeed);

		setInterval(function(){
			findUl.find('li:first-child').animate({opacity:'0'},fadeSpeed).next('li').css({zIndex:'2'}).animate({opacity:'1'},fadeSpeed).end().appendTo(findUl).css({zIndex:'1'});
		},switchDelay);
	});
});

CSSはすっきりとした記述に戻して、jQueryにユーザーエージェント判定で「iPhoneまたはiPadだったらbackground-positionは“top center(上端・中央)”、background-sizeは“幅はauto、高さは$(window).height()で取得した値に固定する”」という書き換えを行うことにしました。

これで、表示は直りましたが、すっきりしない…。

 

以上、バッドノウハウでした。

タグ: Safari

 



関連する記事一覧