Lazyloadingでページ内スクロールの到達位置がずれる件を解消する方法

投稿 2018年07月10日
0
カスタマイズ
HTML5CSS3ResponsiveCustomizeLazyloadingLazysizes高速化上級者向け

正直あんまりおすすめではない (´・ω・`)
すすめない理由は

  • 要素が増える
  • めんどくさい
  • 記事内でstyle属性あるいはstyle要素を必ず使う必要がある
  • pタグ内の画像はどうする(セマンティクス面)

こんなところでしょうか。
特に要素が増えてしまう点ですね。無駄なラッパーが増えるというか。
結局は自身の記事内容の管理能力であったり理解力であったりに関わってきますので、html初心者にはおすすめしません。
「どうしても解消したい」という方だけご検討ください。

スタイルシートへの追加CSSと記事内に記載するhtml

以下の内容は テンプレートのCSS(スタイルシート)に追加 してください。
あるいは人によっては インラインCSS (htmlのstyle属性 or style要素)でも構いません。
スタイルシートとは別で記事内で毎回書かなければいけない項目がありますので、CSS内容がスタイルシートと記事内とでしまうことに抵抗が有る・記事編集時の内容理解に影響が有る、と考える方はインラインCSSで揃えても良いかと思います。
その場合にはテンプレート変更時も内容が失われず有効です。
(ただし推奨はできるだけスタイルシート内に)

.aspect-box {
  position: relative;
  width: 100%;
  height: 0;
  overflow: hidden;
}

.aspect-box img {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center center;
}

IE用のポリフィルを入れている方は .aspect-box imgfont-family: 'object-fit: cover; object-position: center center;'; を追加してください。

続きまして 記事内に記載するhtml内容 です。

<div style="max-width: 最大横幅px;">
  <div class="aspect-box" style="padding-top: calc(画像原寸縦幅 / 画像原寸横幅 * 100%);">
    <img class="lazyload" src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="画像アドレス" alt="代替テキスト">
  </div>
</div>

スタイルシート内CSSの説明

固定スタイルはスタイルシートへ、流動的な内容はインラインCSSとしてhtmlを直接記事内へ、というのが今回の方法です。

img要素に指定されているobjectプロパティは必須ではありません。
縦横比さえ正しく指定されていれば画像はぴったり収まるはずです。
が、万一縦横比計算をミスっても歪んだり結局位置がずれたりなど起こらないようにこの内容にしておくことをおすすめします。

htmlソース内容の説明

スタイルシート内 .aspect-box に高さ0を指定しつつ、記事内では同要素にpadding-topへの指定で高さ出し、というちょっと気持ちの悪い内容になっています。
言葉で説明すると「高さを出さない(ゼロ)指定をしているのに実際にはpadding-topの働きで高さが出ちゃう(出しちゃう)」という感じですかね。
なので本来は.aspect-boxのheightはauto、子要素として.aspect-box::beforeの高さで調整する、というのが綺麗なというか意味の通るCSS内容ではありますが、今回は記事内で疑似要素を利用しなくて済むよう(style属性だけでも完結できるよう)この形を取っています。

htmlの1行目 最大横幅px というのは、ここで大きさの制御をしておかないと画像が全て記事幅と同等になってしまいます。
300pxの画像であっても記事の横幅が1000pxであれば拡大されて横1000pxになります。
それを避けるために imgへのサイズ指定ではなく、親要素となるラッパーの方で制限をかけます。
Lazyloadingの画像の場合、画像そのものへのサイズ指定では効力がありませんのでこういったややこしいことになってます。

単位の px を忘れずにつけてください。
また、width ではなく max-width である点にも注意。

htmlの2行目 calc(画像原寸縦幅 / 画像原寸横幅 * 100%) についてですが、みなさんが変更すべき箇所は緑色の部分だけです。他は半角スペースなども含め触らないようにしてください。
例えば以下のような画像の場合。

サンプル(縮尺掲載, 原寸 横1000px 縦666px)

画像の原寸は 横1000px 縦666px です。
原寸サイズはアップロード画面ですぐに確認できます。
アップロード画面縦横サイズ確認

縦, 横 の順 であることに注意。サンプルの場合は
calc(666 / 1000 * 100%) になります。
また、単位をつけない 点にも留意してください。

横幅最大値を500pxに縛って同じ画像を掲載すると以下の通りです。
横幅最大値を500pxに設定した様子

<div style="max-width: 500px;">
  <div class="aspect-box" style="padding-top: calc(666 / 1000 * 100%);">
    <img class="lazyload" src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="https://blog-imgs-117.fc2.com/v/a/n/vanillaice000/girl-with-roses-picjumbo-comth.jpg" alt="">
  </div>
</div>

画像を横に並べたい場合

いろんなパターンが考えられますが、代表的なパターンと方法を記しておきます。

いかなる画面サイズでも同じ見た目で並べる

パソコンで2枚ならんでいるならスマホでも同じように並んでいる、というパターン。
2列並び左側画像 2列並び右側画像

<div style="display: inline-block; width: 50%;">
  <div class="aspect-box" style="padding-top: calc(1枚目縦 / 1枚目横 * 100%);">
    <img class="lazyload" src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="1枚目アドレス" alt="">
  </div>
</div><div style="display: inline-block; width: 50%;">
  <div class="aspect-box" style="padding-top: calc(2枚目縦 / 2枚目横 * 100%);">
    <img class="lazyload" src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="2枚目アドレス" alt="">
  </div>
</div>

それぞれの要素(左と右)を inline-block で並べるのが余分なラッパーを増やさなくて良いという意味で最も効率的だと思います。

注意点は、基本htmlと異なり親への横幅指定を max-width ではなく width で行う点と、display: inline-block; を双方に指定することも忘れないようにします。

最大の注意点は 5行目 の、最初(左)の要素の終了タグと後続(右)要素の開始タグを横に並べて書いている点 です。
こうしておかないと旧投稿画面では、というかhtml全般に於いてですが、inline-block というのはhtmlソース内で要素間の改行があると必ず要素同士に空白を作ります。
空白が入ると横幅は 50% + 50% + 空白 となり、100%を超えてしまいます。要するに並ばなくなってしまいます。

隣同士の画像の縦幅が異なる場合には上下の位置揃えも考慮する必要が出てきます。
私の制作テンプレートの場合のデフォルトは「bottom」揃えになっています。
変更したい場合にはそれぞれの親要素のwidth指定の後ろに vertical-align: top; または vertical-align: middle; を指定します。
サンプルコードで言うと1行目と5行目ですね。

<div style="display: inline-block; width: 50%; vertical-align: middle;">

サンプルは50%割当てで並べていますが、30%と70%、40%と60%など、足して100%ならばOKです。
もちろん2枚だけでなく3枚4枚なども可能ですが、スマホでも同じ見た目になる 点を考慮して並べてください。
ちなみにスマホ最小機種は横320px程度しかありませんので多すぎると各画像がかなり小さくなります。

画像間に空白を設けたい場合、例えば10px空けるには

1枚目: に5pxのmarginをつける

<div style="display: inline-block; width: calc(50% - 5px); margin-right: 5px;">

2枚目: に5pxのmarginをつける

<div style="display: inline-block; width: calc(50% - 5px); margin-left: 5px;">

折り返すようにする

「折り返す」というのは、並べた要素が足して100%を超えた場合には後続要素が下へ降りるようにしておくという意味です。

<div style="display: inline-block; width: calc(500px - 10px); max-width: 100%; margin-right: 10px;">
  <div class="aspect-box" style="padding-top: calc(1枚目縦 / 1枚目横 * 100%);">
    <img class="lazyload" src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="1枚目アドレス" alt="">
  </div>
</div><div style="display: inline-block; width: 400px; max-width: 100%;">
  <div class="aspect-box" style="padding-top: calc(2枚目縦 / 2枚目横 * 100%);">
    <img class="lazyload" src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="2枚目アドレス" alt="">
  </div>
</div>

パソコンから閲覧中の方はブラウザ横幅を縮小して確認を行ってください。
floatやflexで並べても良いんですが、その場合にはまた一つラッパーを増やす必要が生じますのでinline-blockのまま流用します。

ポイントはやはり1行目と5行目、各親要素への指定です。
marginは1枚目の親にのみ、右側 につけます。
先程のサンプルのように後続に左marginをつけてしまうと、折り返した時に左に隙間ができて左辺が綺麗に並びません。
画像が複数枚ある場合にはそれぞれ右へmarginを指定する(最後の画像はmarginなし)と良いと思います。

このパターンでは widthmax-width の双方を指定します。

float

ここは絶対いやしくもその講演院というのの以外に載せますで。ざっと十月を教育人は余計その観察ならたまでがあっからいるたがは妨害買い占めるううと、ああにもつけ込むんざるうない。
一つに圧しです点はもっとも元来にすでにだだます。たとい嘉納さんに卒業地位ある程度相談に甘んじう主義こんな権力あなたか尊重のというご解たたですたば、その多年は私か精神女とできて、岩崎君のものが西洋の私でざっとお批評と向いが私がたにお失敗があっように無論お発展になるですうて、どうもはなはだ所有が聞いですからみないのをなったです。

<div style="overflow: hidden;">
<div style="width: 50%; max-width: 画像最大横幅px; float: left; margin-right: 10px; margin-bottom: 5px;"><!-- %指定はテキストとのバランス特にスマートフォンでの見た目を考える。marginは適宜調整 -->
<div class="aspect-box" style="padding-top: calc(縦原寸 / 横原寸 * 100%);">
<img class="lazyload" src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="画像アドレス" alt="">
</div>
</div>
<p>
文章
</p>
</div>

画像用div要素と文章用のp要素双方をdivコンテナで囲い(1行目が開始タグ、10行目が終了タグ)、そのdivに overflow: hidden を指定します。
あるいはfloat解除用の独自クラス(clearfix)を既に導入済みの場合はクラス属性追加でも構いません。

p要素を初期値にしている、または上下marginを設定している場合は <p style="margin: 0;"> のようにmarginを0に指定することで画像上辺よりもテキスト上辺が下がってしまうのを防げます。

まとめ

heightが不確定な要素がlazyloading画像以外にもある、という場合を除けばページ内スクロールの到達位置が著しくズレることはなくなるかと思います。
若干面倒ではありますが、ユーザビリティは上がりますよね。
ただ繰り返しますが初心者の方は避けた方が良いと思います。

あとはセマンティクス面ですね。
画像は通常p要素内であったり、figure要素であったりするわけなんですが。
div要素で囲うということはpタグ内に含めることはできません。これがどうかというところですよね。
そもそもp要素なんて使ってません、という方は気にしなくて大丈夫です(笑)
figure要素をお使いの方はもうhtmlを理解しているでしょうからdivをfigureに変更し、figcaptionにどんなCSSを当てるかなど自身で対策を。

というわけで、ページ内スクロールとlazyloading共存の一手段としてご紹介しました。

YOU MAY ALSO LIKE
もっと見る
vanillaice (Akira)
vanillaice (Akira)

0 COMMENTS

There are no comments yet.