【问题标题】:Using CSS Sprites: Does replicating one large image many times burden the client?使用 CSS Sprites:多次复制一张大图像会给客户端带来负担吗?
【发布时间】:2019-01-09 23:19:47
【问题描述】:

我有一个有趣的小部件,它邀请用户从 114 种动物的列表中进行选择。 UI 包括每个物种的小缩略图,大小相同 (100x70)。缩略图总和为 2.1M。

我并不急于发出 114 个服务器请求,所以我使用 ImageMagick 制作了一张非常长的图像 (11400x70),它缩小到 960K。因此,挑战是在客户端将那个长图像分割成 114 个小图像。 (编辑:我需要每个动物都作为自己的图像,因为 UI 会过滤列表,例如“只显示食草动物”)。

我最初有一个复杂的方法,我在加载组合图像的 base64 字符串后将大图像绘制到画布上,为每个动物拉取 ImageData,将其绘制到第二个画布上,然后拉取 dataURL:

var combined_canvas = document.createElement('canvas');
var combined_ctx = combined_canvas.getContext('2d');

var indv_canvas = document.createElement('canvas');
var indv_ctx = indv_canvas.getContext('2d');    

combined_canvas.width = 11400; combined_canvas.height = 70;
indv_canvas.width = 100; indv_canvas.height = 70;

var image = new Image();
image.onload = function() {
    combined_ctx.drawImage(image, 0, 0); // paint combined image

    // loop through the list of 114 animals
    Object.keys(master_list).forEach((d, i) => {
        // get the image data just for this animal in sequence
        var imageData = combined_ctx.getImageData(i * 100, 0, 100, 70);
        // paint that image data to the second canvas
        indv_ctx.putImageData(imageData, 0, 0); 
        var img = document.createElement('img'); 
        img.src = indv_canvas.toDataURL();
        document.getElementById("animal_thumbnails").appendChild(img);
    });
};
image.src = combined_images; // the base64 of the combined image

当然,制作 114 CSS Sprites 会容易得多,这也可以防止 Canvas 绘制图像的方式造成质量上的小幅损失。但我不太了解的是浏览器如何存储相同的图像,多次放置不同的偏移量。

如果客户端在内存中复制组合图像,我会为所有这些缩略图查看大约 100Mb。我希望即使是最糟糕的浏览器也比这更智能,但这对于我来说太遥远了。

我将图像加载为 base64 的原因是我的另一个想法是使用 atob() 解码 base64 并使用 jpg-js 将其分割,每个 this Stackoverflow suggestion。但是 jpg-js 在缩小后增加了大约 300K,我不确定它是否真的是为客户设计的。

【问题讨论】:

  • 你不会制作 114 个 CSS 精灵。 CSS sprite 正是您所做的,将许多图像组合在一起。现在你要做的就是把这张图片设置为div的背景,div为70x70px,然后移动背景来显示你想要的图片。 div 就像一个窗口。
  • 对,但我需要每只动物作为自己的过滤节点(例如,只显示食肉动物),所以我需要 114 个 div,对吧?
  • 您的问题似乎与浏览器有关。您是在询问一组特定的浏览器,还是常见的浏览器实现?
  • 后者——主要是在一个页面上多次放置同一张图片的约定。

标签: javascript css image canvas css-sprites


【解决方案1】:

关于内存使用,请参阅this 帖子和this 帖子

因此,挑战是将那张长图分割成 114 张小图 在客户端上。

长图有什么需要砍的。我会将其保留为单个图像并用作 CSS sprite 并显示所有图像。

如果您的图像具有固定尺寸,则 JavaScript 循环可以呈现页面中的所有图像。或者您可以使用this 之类的工具来获取动物位置并将其保存在 css 文件中。但我更喜欢JS循环方法。

代码是这样的

var imageItem = "";
var x = 0;
for (var i = 0; i < 144, i++) {

  imageItem += "<li style='background-position: "+ x + " 0'></li>";
  x = x + 100; // this is the width of the each image
}

someElement.innerHtml = "<ul class='img-container'>" + imageItem + "</ul>";

在 CSS 中

.img-container li {
  width: 100px;
  height: 70px;
  background-image : url('../your-long-image.jpg');
  background-repeat: no-repeat;
}

看这个例子,我只使用一个图像,我正在改变偏移位置以显示同一个图像的不同位置。

var imageItem = "";
var x = 0;
for (var i = 0; i < 3; i++) {
      
      imageItem += "<li style='background-position: "+ x + "px  0'>ss</li>";
      x = x - 125; // this is the width of the each image
}

    document.getElementById("container").innerHTML = "<ul class='img-container'>" + imageItem + "</ul>";
.img-container li {
      width: 125px;
      height: 200px;
      border: 1px solid green;
      background-image : url('https://images-wixmp-ed30a86b8c4ca887773594c2.wixmp.com/intermediary/f/c9702304-c06d-4500-90b7-b6b6168093f8/db9n9km-ee485eb1-1ecc-4cd8-b845-f16900bde9e0.png');
      background-repeat: no-repeat;
      float:left;
      list-style: none;
    }
&lt;div id="container"&gt;&lt;/div&gt;

【讨论】:

  • 为了清楚起见,循环会在每次迭代时创建一个新的 Image 元素,将其设置为组合图像,并将样式设置为正确偏移?
  • 没有图片元素,我们使用background-image来展示图片,我们改变background-position来展示不同的图片。
  • 对,当然。但问题仍然存在:在不同的位置使用相同的图像 114 次是否会将其视为内存中的新图像?
  • @ChrisWilson 因为它是每个动物的新元素,它会在浏览器中占用一些内存,但图像信息只会存储一次。所以它将被视为 1 张图像而不是 144 张图像。我添加了一个例子
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-04
  • 2010-12-03
  • 2018-05-03
相关资源
最近更新 更多