簡體   English   中英

設置圖像的寬度/高度以避免圖像加載時重排

[英]Set width/height of image to avoid reflow on image load

當我在html中使用圖像標簽時,我嘗試在img標簽中指定它的寬度和高度,這樣瀏覽器甚至在圖像加載之前就會為它們保留空間,所以當它們完成加載時,頁面不會重排(元素不會四處移動)。 例如:

<img width="600" height="400" src="..."/>

現在的問題是我想創建一個更具“響應性”的版本,對於“單列案例”,我想這樣做:

<img style="max-width: 100%" src="..."/>

但是,如果我將它與明確指定的寬度和高度混合,例如:

<img style="max-width: 100%" width="600" height="400" src="..."/>

並且圖像比可用空間更寬,然后忽略縱橫比調整圖像大小。 我理解為什么會發生這種情況(因為我“固定”了圖像的高度),我想解決這個問題,但我不知道如何解決。

總結一下:我希望能夠指定max-width: 100% ,並以某種方式確保在加載圖像時內容不會重排。

更新 2: (2019 年 12 月)

Firefox 和 Chrome 現在默認處理這個問題。 只需像往常一樣添加widthheight屬性。 有關更多詳細信息,請參閱此博客文章


更新 1: (2018 年 7 月)

我發現了一個更聰明的替代版本: http ://cssmojo.com/aspect-ratio-using-custom-properties-and-calc/。 這仍然需要一個包裝器元素,並且需要 CSS 自定義屬性,但我認為它更優雅。 Codepen 示例在這里(感謝 Chris Coyier 的原創)。


原來的:

來自Jonathan Hollin 的這篇博文:將圖像的高度和寬度添加為內聯樣式的一部分。 這會為圖像保留空間,防止圖像加載時重排,但它也是響應式的。

HTML

<figure style="padding-bottom: calc((400/600)*100%)">
  <img src="/images/kitten.jpg" />
</figure>

CSS

figure {
  position: relative;
}

img {
  max-width: 100%;
  position: absolute;
}

figure可以替換為div或您選擇的任何其他容器。 該解決方案依賴於具有相當廣泛的瀏覽器支持的 CSS calc()。

工作 Codepen 可以在這里看到。

我也在尋找這個問題的答案。 使用max-widthwidth=height= ,瀏覽器有足夠的數據,它應該能夠為圖像留下適量的空間,但它似乎並沒有那樣工作。

我現在使用 jQuery 解決方案解決了這個問題。 它要求您為<img>標簽提供width=height=

CSS:

img { max-width: 100%; height: auto; }

HTML:

<img src="image.png" width="400" height="300" />

jQuery:

$('img').each(function() { 
    var aspect_ratio = $(this).attr('height') / $(this).attr('width') * 100;
    $(this).wrap('<div style="padding-bottom: ' + aspect_ratio + '%">');
});

這會自動應用以下技術:http: //andmag.se/2012/10/responsive-images-how-to-prevent-reflow/

對於僅 css 的解決方案,您可以將img包裝在一個容器中,其中padding-bottom百分比保留頁面上的空間,直到圖像加載,防止回流。

不幸的是,這種方法確實需要您通過計算(或讓 css 為您計算)基於圖像高度和寬度的padding-bottom百分比,在您的 css 中包含圖像縱橫比(但不需要內聯樣式)。

如果您的許多圖像可以分為幾個標准縱橫比,那么您可以為每個縱橫比創建一個類,以將適當的padding-bottom百分比應用於具有該縱橫比的所有圖像。 如果您不處理各種圖像縱橫比,這可能會為您節省一點時間和精力。

以下是具有 2:1 縱橫比的圖像的一些示例 html 和 css:

HTML

<div class="container">
  <img id="image" src="https://via.placeholder.com/300x150" />
</div>

CSS

.container {
  display: block;
  position: relative;
  padding-bottom: 50%; /* calc(100%/(300/150)); */
  height: 0;
}

.container img {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}

下面的代碼片段添加了一些額外的 html、css 和 javascript 來創建一些可視的頂部和底部參考點並模擬一個非常緩慢的加載圖像,因此您可以直觀地看到這種方法是如何防止回流的。

 const image = document.getElementById('image'); const source = 'https://via.placeholder.com/300x150'; const changeSource = () => image.src = source; setTimeout(changeSource, 3000);
 .container { display: block; position: relative; padding-bottom: 50%; /* calc(100%/(300/150)); */ height: 0; } .container img { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } .top, .bottom { background-color: green; width: 100%; height: 20px; }
 <div class="top"></div> <div class="container"> <img id="image" src="" /> </div> <div class="bottom"></div>

首先,我想寫下 2013 年 10 月的答案。這是不完整的復制,因此不正確。 不要使用它。 為什么? 我們可以在這個片段中看到它(將執行的片段滾動到底部):

 $('img').each(function() { var aspect_ratio = $(this).attr('height') / $(this).attr('width') * 100; $(this).wrap('<div style="padding-bottom: ' + aspect_ratio + '%">'); });
 img { max-width: 100%; height: auto; }
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <div style="width:300px;border:1px solid red"> <img width="400" height="300" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAZAAAAEsCAIAAABi1XKVAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAf3SURBVHhe7do9chtXGoVhb2Ryr0TllSjwLpx7CY6cusrZBFqAEydegPMpL2NEUhTvPf0HkBBxDDxVT6BXajbB7r5fNyB+992v//vef/z775Y8/FxvAmbLhYgwsLi377n3/x4evayxW2g9/PeRPn6bt2WZgcWnZd2w5qgYfPn76+ZenP//98/eLrwXeQ/a92p1W4ccfFl8OvIfs+/Tpx3EkxZuXp3eCAwMLriT7Lo0jaf0jqmmiGVhwJdn36M+Pfz8Po83Pp4ZtDgfW78+fdr348PH3xWYrz26fx+X4jZ5fT+zwhA/Rlnveeg2XNn3QPtl+2d/kOMxPzYNzjsPqTv76bf3HfPj7xR6ueS5uUfY9OmkYvVx22+vk8IOw+fFtXpPn2brit+fFs2/7v3WbY2LnuF34OJz2ceTRyNj5QbbkD3jtc3GTsu/SdA/cuE9+vb1v/FrDyatuuKzX7r0nW67/09fY9sx9s8s8YZ3h9cdh8+Z0zv/ADMYrp+Jc3KLs+7TyJu68u18sufjaXAAxE+Pi/vKvOQGfBuWwq/kZIVdIrsYcCltz+cKGn+JwZV7kOBw5vjmtv4wna7el5U5Kz8VNyL5bazNrsPu51XSBbm05PXpMj2njlw/X7nhZv2w/bDzsZNr55qidf8bpNXwrrx1YrzwOp9h/Sdun6dnB7af3XNyE7PuWt76FtQtrvOvu3u3Ha3RcKhtrb3gxwxBc3Xhjqa8Yt3yPNyOvHFivPA6nWd/ho3EYbT9iz89ZccB7z8VNyOZR3kUHeR2PY2j/Ap2WyjDa3rxQhy3PsvUweEHXHFg7J/FZHoGdWTYZZ8180ovPxU3IZkV8kLz54dHxrX5147cu1PmGf4bzPv15lesMrJOnRoyJk1/t5l2q+VzchGw2bL5Z2F05aXXjty5UA+tl48XdZZ+B9W+TfYeeL77tzyyeDCthvEaHlXO0h2nqXW5gTQ8U8+q9unceWDkvVs/I+g6P/mkyfPedt4Rl5+ImZN+fU6/RrYE13dJP3sPx2jtjoU4f1hzOhXf1vgNrfPDZPhc7Z3zzOXoyj8V5YBWfi5uQfX/GW+LOI9LOZtM1urlOprcq0x7evlDnnccSSl/3sL/ZZbzvwNrYw+joZE1HcnUn8x6Wh7H2XNyE7PszTqIneZlO9+3Plh83HLwTyUs8lu7bF+r894+WL3JeSOvbXNzVBtZiGOU5WtvmURzJaZSs7WQ5a0rPxU3Ivj/LgbVv4ylseQlueVkkW9/6aQUu/vXxC3MxvCzXHIvH1pbrG5z/Ar4czAseh3PP5hfzMD3vB1l7OLr6ubhZ2ffn6yX+efEcXe4Ht8HD1TIPu9V7/qPHNbDc28OaXCzUacHkw+COi6+Q7R9nx8OkuPBx2D8LG2d5cWaX+9+yNrAeXPNc3K7sO/Tlwnq5aNZuj+dcUmvX+tfnoNHW0nrFk8XsYAR8Iw1PWM+WR+BlJK18u623qyun8mk/wwP1wSG9zrm4WdnAsdMHFheVDRwzsK4kGzgyvvldfbPPt5IN7Jo+qjv8XQ0uKxt4tPVfAQO//frP/wEiNOVSBSWikgAAAABJRU5ErkJggg=="/> Some text </div>

我們可以看到文字離底部很遠 在這個例子中什么是不完整/不正確的? 我將用純 JavaScript 的正確示例來展示它(我們不需要為此下載 jQuery)。

純 JavaScript 的正確示例

請將執行的代碼段滾動到底部。

 var imgs = document.querySelectorAll('img'); for(var i = 0; i < imgs.length; i++) { var aspectRatio = imgs[i].getAttribute('height') / imgs[i].getAttribute('width') * 100; var div = document.createElement('div'); div.style.paddingBottom = aspectRatio + '%'; imgs[i].parentNode.insertBefore(div, imgs[i]); div.appendChild(imgs[i]); }
 .restrict-container div{position:relative} img { position:absolute; max-width:100%; top:0; left:0; height:auto }
 <div class="restrict-container" style="width:300px;border:1px solid red"> <img width="400" height="300" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAZAAAAEsCAIAAABi1XKVAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAf3SURBVHhe7do9chtXGoVhb2Ryr0TllSjwLpx7CY6cusrZBFqAEydegPMpL2NEUhTvPf0HkBBxDDxVT6BXajbB7r5fNyB+992v//vef/z775Y8/FxvAmbLhYgwsLi377n3/x4evayxW2g9/PeRPn6bt2WZgcWnZd2w5qgYfPn76+ZenP//98/eLrwXeQ/a92p1W4ccfFl8OvIfs+/Tpx3EkxZuXp3eCAwMLriT7Lo0jaf0jqmmiGVhwJdn36M+Pfz8Po83Pp4ZtDgfW78+fdr348PH3xWYrz26fx+X4jZ5fT+zwhA/Rlnveeg2XNn3QPtl+2d/kOMxPzYNzjsPqTv76bf3HfPj7xR6ueS5uUfY9OmkYvVx22+vk8IOw+fFtXpPn2brit+fFs2/7v3WbY2LnuF34OJz2ceTRyNj5QbbkD3jtc3GTsu/SdA/cuE9+vb1v/FrDyatuuKzX7r0nW67/09fY9sx9s8s8YZ3h9cdh8+Z0zv/ADMYrp+Jc3KLs+7TyJu68u18sufjaXAAxE+Pi/vKvOQGfBuWwq/kZIVdIrsYcCltz+cKGn+JwZV7kOBw5vjmtv4wna7el5U5Kz8VNyL5bazNrsPu51XSBbm05PXpMj2njlw/X7nhZv2w/bDzsZNr55qidf8bpNXwrrx1YrzwOp9h/Sdun6dnB7af3XNyE7PuWt76FtQtrvOvu3u3Ha3RcKhtrb3gxwxBc3Xhjqa8Yt3yPNyOvHFivPA6nWd/ho3EYbT9iz89ZccB7z8VNyOZR3kUHeR2PY2j/Ap2WyjDa3rxQhy3PsvUweEHXHFg7J/FZHoGdWTYZZ8180ovPxU3IZkV8kLz54dHxrX5147cu1PmGf4bzPv15lesMrJOnRoyJk1/t5l2q+VzchGw2bL5Z2F05aXXjty5UA+tl48XdZZ+B9W+TfYeeL77tzyyeDCthvEaHlXO0h2nqXW5gTQ8U8+q9unceWDkvVs/I+g6P/mkyfPedt4Rl5+ImZN+fU6/RrYE13dJP3sPx2jtjoU4f1hzOhXf1vgNrfPDZPhc7Z3zzOXoyj8V5YBWfi5uQfX/GW+LOI9LOZtM1urlOprcq0x7evlDnnccSSl/3sL/ZZbzvwNrYw+joZE1HcnUn8x6Wh7H2XNyE7PszTqIneZlO9+3Plh83HLwTyUs8lu7bF+r894+WL3JeSOvbXNzVBtZiGOU5WtvmURzJaZSs7WQ5a0rPxU3Ivj/LgbVv4ylseQlueVkkW9/6aQUu/vXxC3MxvCzXHIvH1pbrG5z/Ar4czAseh3PP5hfzMD3vB1l7OLr6ubhZ2ffn6yX+efEcXe4Ht8HD1TIPu9V7/qPHNbDc28OaXCzUacHkw+COi6+Q7R9nx8OkuPBx2D8LG2d5cWaX+9+yNrAeXPNc3K7sO/Tlwnq5aNZuj+dcUmvX+tfnoNHW0nrFk8XsYAR8Iw1PWM+WR+BlJK18u623qyun8mk/wwP1wSG9zrm4WdnAsdMHFheVDRwzsK4kGzgyvvldfbPPt5IN7Jo+qjv8XQ0uKxt4tPVfAQO//frP/wEiNOVSBSWikgAAAABJRU5ErkJggg=="/> Some text<br> <img width="400" height="300" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAZAAAAEsCAIAAABi1XKVAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAf3SURBVHhe7do9chtXGoVhb2Ryr0TllSjwLpx7CY6cusrZBFqAEydegPMpL2NEUhTvPf0HkBBxDDxVT6BXajbB7r5fNyB+992v//vef/z775Y8/FxvAmbLhYgwsLi377n3/x4evayxW2g9/PeRPn6bt2WZgcWnZd2w5qgYfPn76+ZenP//98/eLrwXeQ/a92p1W4ccfFl8OvIfs+/Tpx3EkxZuXp3eCAwMLriT7Lo0jaf0jqmmiGVhwJdn36M+Pfz8Po83Pp4ZtDgfW78+fdr348PH3xWYrz26fx+X4jZ5fT+zwhA/Rlnveeg2XNn3QPtl+2d/kOMxPzYNzjsPqTv76bf3HfPj7xR6ueS5uUfY9OmkYvVx22+vk8IOw+fFtXpPn2brit+fFs2/7v3WbY2LnuF34OJz2ceTRyNj5QbbkD3jtc3GTsu/SdA/cuE9+vb1v/FrDyatuuKzX7r0nW67/09fY9sx9s8s8YZ3h9cdh8+Z0zv/ADMYrp+Jc3KLs+7TyJu68u18sufjaXAAxE+Pi/vKvOQGfBuWwq/kZIVdIrsYcCltz+cKGn+JwZV7kOBw5vjmtv4wna7el5U5Kz8VNyL5bazNrsPu51XSBbm05PXpMj2njlw/X7nhZv2w/bDzsZNr55qidf8bpNXwrrx1YrzwOp9h/Sdun6dnB7af3XNyE7PuWt76FtQtrvOvu3u3Ha3RcKhtrb3gxwxBc3Xhjqa8Yt3yPNyOvHFivPA6nWd/ho3EYbT9iz89ZccB7z8VNyOZR3kUHeR2PY2j/Ap2WyjDa3rxQhy3PsvUweEHXHFg7J/FZHoGdWTYZZ8180ovPxU3IZkV8kLz54dHxrX5147cu1PmGf4bzPv15lesMrJOnRoyJk1/t5l2q+VzchGw2bL5Z2F05aXXjty5UA+tl48XdZZ+B9W+TfYeeL77tzyyeDCthvEaHlXO0h2nqXW5gTQ8U8+q9unceWDkvVs/I+g6P/mkyfPedt4Rl5+ImZN+fU6/RrYE13dJP3sPx2jtjoU4f1hzOhXf1vgNrfPDZPhc7Z3zzOXoyj8V5YBWfi5uQfX/GW+LOI9LOZtM1urlOprcq0x7evlDnnccSSl/3sL/ZZbzvwNrYw+joZE1HcnUn8x6Wh7H2XNyE7PszTqIneZlO9+3Plh83HLwTyUs8lu7bF+r894+WL3JeSOvbXNzVBtZiGOU5WtvmURzJaZSs7WQ5a0rPxU3Ivj/LgbVv4ylseQlueVkkW9/6aQUu/vXxC3MxvCzXHIvH1pbrG5z/Ar4czAseh3PP5hfzMD3vB1l7OLr6ubhZ2ffn6yX+efEcXe4Ht8HD1TIPu9V7/qPHNbDc28OaXCzUacHkw+COi6+Q7R9nx8OkuPBx2D8LG2d5cWaX+9+yNrAeXPNc3K7sO/Tlwnq5aNZuj+dcUmvX+tfnoNHW0nrFk8XsYAR8Iw1PWM+WR+BlJK18u623qyun8mk/wwP1wSG9zrm4WdnAsdMHFheVDRwzsK4kGzgyvvldfbPPt5IN7Jo+qjv8XQ0uKxt4tPVfAQO//frP/wEiNOVSBSWikgAAAABJRU5ErkJggg=="/> Some text </div>

來自 2013 年 10 月答案的錯誤:圖像應該絕對放置( position:absolute )到包裝容器,但它不是這樣放置的。

我對這個問題的回答到此結束。


欲了解更多信息,請閱讀更多關於

如果我理解要求沒問題,您希望能夠設置圖像大小,該大小僅在內容(HTML)生成時才知道,因此可以將其設置為內聯樣式。

但這必須獨立於 CSS,並且在圖像加載之前,所以也獨立於這個圖像大小。

我已經找到了一個解決方案,它涉及將圖像包裝在一個 div 中,並在這個 div 中包含一個 svg,該 svg 可以直接設置為內聯樣式。

顯然這沒有太多語義,但至少它有效

包含的 div 有一個名為 img 的類,以表明它應該是一個 img

為了嘗試重現加載階段,圖像的 src 已損壞

 .container { margin: 10px; border: solid 1px black; width: 200px; height: 400px; position: relative; } .img { border: solid 1px red; width: fit-content; max-width: 100%; position: relative; } svg { max-width: 100%; background-color: lightgreen; opacity: 0.1; } #ct2 { width: 500px; } .img img { position: absolute; width: 100%; height: 100%; max-height: 100%; max-width: 100%; top: 0px; left: 0px; box-shadow: inset 0px 0px 10px blue; }
 <div class="container" id="ct1"> <div class="img"> <svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMinYMin meet" viewBox="0 0 400 300" width="400"> </svg> <img width="400" height="300" src="missing.jpg"> </div> </div> <div class="container" id="ct2"> <div class="img"> <svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMinYMin meet" viewBox="0 0 40 30" width="400"> </svg> <img width="400" height="300" src="missing.jpg"> </div> </div>

我發現最好的解決方案是創建一個具有相應尺寸的透明 base64 gif 作為 img 標簽的占位符,在加載頁面后通過 js 觸發加載。

<img data-src="/image.png" src="data:image/gif;base64,R0lGODlhyAAsAYABAP///wAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==">

對於博客文章等,我使用這個 PHP 函數來自動創建它們

function CreatePreloadPlaceholderGif($width, $height) {
    $wHex = str_split(str_pad(dechex($width), 4, "0", STR_PAD_LEFT), 2);
    $hHex = str_split(str_pad(dechex($height), 4, "0", STR_PAD_LEFT), 2);
    $hex = "474946383961".$wHex[1].$wHex[0].$hHex[1].$hHex[0]."800100ffffff00000021f904010a0001002c00000000010001000002024c01003b";
    $base64= '';
    foreach(str_split($hex, 2) as $pair){
       $base64.= chr(hexdec($pair));
    }
    return base64_encode($base64);
}
echo CreatePreloadPlaceholderGif(300, 500);
//  R0lGODlhLAH0AYABAP///wAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==

在前端,結果是這樣的

 function loadimage() { elements = document.querySelectorAll('img[data-src]'); elements.forEach( el => { el.setAttribute('src', el.getAttribute('data-src')) }); }
 img { background-color:#696969; }
 <div>300x500 image placeholder</div> <img data-src="https://ibec.or.id/wp-content/uploads/2018/10/300x500.png" src="data:image/gif;base64,R0lGODlhLAH0AYABAP///wAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="> <div>After page load, run js command to replace src attribute with data-src</div> <button onclick="loadimage()">Load image</button>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM