Scale元素与jQuery的背景覆盖成比例。

时间:2021-08-18 20:08:45

I have a tricky question: I have a fullsize background over the site I'm working on. Now I want to attach a div to a certain position on the image and also that the div scales in the same way the my background image with the "background-size: cover" property does. So in this example, I have a picture of a city, which covers the browser window and I want my div to overlay one particular building, no matter of the window size.

我有一个棘手的问题:我在我的网站上有一个完整的背景。现在我想将div附加到图像上的某个位置上,并且div以与我的背景图像相同的方式缩放“background-size: cover”属性。在这个例子中,我有一个城市的图片,它覆盖了浏览器窗口,我想要我的div覆盖一个特定的建筑,不管窗口的大小。

I already managed to make the div sticking to one position, but cant make it resize properly. What I did so far:

我已经设法使div坚持在一个位置,但不能使它适当地调整大小。到目前为止我所做的:

http://codepen.io/EmmieBln/pen/YqWaYZ

http://codepen.io/EmmieBln/pen/YqWaYZ

var imageWidth = 1920,
    imageHeight = 1368,
    imageAspectRatio = imageWidth / imageHeight,
    $window = $(window);

var hotSpots = [{
    'x': -160,
    'y': -20,
    'height': 400,
    'width': 300
}];

function appendHotSpots() {
    for (var i = 0; i < hotSpots.length; i++) {
        var $hotSpot = $('<div>').addClass('hot-spot');
        $('.container').append($hotSpot);
    }
    positionHotSpots();
}

function positionHotSpots() {
    var windowWidth = $window.width(),
        windowHeight = $window.height(),
        windowAspectRatio = windowWidth / windowHeight,
        $hotSpot = $('.hot-spot');

    $hotSpot.each(function(index) {
        var xPos = hotSpots[index]['x'],
            yPos = hotSpots[index]['y'],
            xSize = hotSpots[index]['width'],
            ySize = hotSpots[index]['height'],
            desiredLeft = 0,
            desiredTop = 0;

        if (windowAspectRatio > imageAspectRatio) {
            yPos = (yPos / imageHeight) * 100;
            xPos = (xPos / imageWidth) * 100;
            xSize = (xSize / imageWidth) * 1000;
            ySize = (ySize / imageHeight) * 1000;
        } else {
            yPos = ((yPos / (windowAspectRatio / imageAspectRatio)) / imageHeight) * 100;
            xPos = ((xPos / (windowAspectRatio / imageAspectRatio)) / imageWidth) * 100;
        }

        $(this).css({
            'margin-top': yPos + '%',
            'margin-left': xPos + '%',
            'width': xSize + 'px',
            'height': ySize + 'px'
        });

    });
}

appendHotSpots();
$(window).resize(positionHotSpots);

My idea was: If (imageWidth / windowWidth) < 1 then set Value for var Scale = (windowWidth / imageWidth) else var Scale ( windowHeight / imageHeight ) and to use the var Scale for transform: scale (Scale,Scale) but I couldnt manage to make this work…

我的想法是:如果(imageWidth / windowWidth) < 1,那么为var Scale = (windowWidth / imageWidth)设置值else var Scale (windowHeight / imageHeight),并使用var Scale进行转换:Scale (Scale,Scale),但我没办法做到这一点…

Maybe you guys could help me out…

也许你们能帮我个忙……

6 个解决方案

#1


11  

Solution for background-size:cover

解决方案background-size:封面

I am trying to give you solution(or consider as an idea). You can check working demo here. Resize the window to see the result.

我想给你一个解决方案(或者把它当作一个想法)。您可以在这里查看工作演示。调整窗口大小以查看结果。

First,I didn't understand why you are using transform,top:50% and left:50%for hotspot. So I tried to solve this using minimal use-case and adjusted your markup and css for my convenience.

首先,我不明白为什么要使用transform,top:50%,而hotspot:50%。因此,我尝试用最小的用例来解决这个问题,并调整了标记和css以方便我。

Here rImage is the aspect ratio of the original image.

这里的裂缝是原始图像的长宽比。

 var imageWidth = 1920;
 var imageHeight = 1368;
 var h = {
   x: imageWidth / 2,
   y: imageHeight / 2,
   height: 100,
   width: 50
 };
 var rImage= imageWidth / imageHeight;

In window resize handler,calculate the aspect ration of viewport r. Next,the trick is to find the dimensions of the image when we resize the window. But,viewport will clip the image to maintain aspect ratio. So to calculate the image dimensions we need some formula.

在窗口大小调整处理程序中,计算viewport r的方面定量。接下来,关键是当我们调整窗口大小时,找到图像的尺寸。但是,viewport将剪辑图像以保持长宽比。为了计算图像的尺寸我们需要一些公式。

When using background-size:cover to calculate the dimensions of image,below formulas are used.

当使用背景尺寸:覆盖来计算图像的尺寸时,使用下面的公式。

if(actual_image_aspectratio <= viewport_aspectratio)
    image_width = width_of_viewport
    image_height = width_ofviewport / actual_image_aspectratio 

And

if(actual_image_aspectratio > viewport_aspectratio)
    image_width = height_of_viewport * actual_image_aspectratio 
    image_height = height_of_viewport

You can refer this URL for more understanding on image dimensions calculation when using background-size:cover.

在使用背景尺寸:cover时,您可以参考这个URL以了解图像尺寸的计算。

After getting the dimensions of the image, we need to plot the hot-spot coordinates from actual image to new image dimensions.

得到图像的维数后,需要将热点坐标从实际图像绘制到新的图像维数。

To fit the image in viewport image will be clipped on top & bottom / left & right of the image. So we should consider this clipped image size as an offset while plotting hotspots.

为了适应viewport图像中的图像,将在图像的顶部和底部/左边和右边进行裁剪。因此,在绘制热点时,我们应该将剪切后的图像大小视为偏移量。

offset_top=(image_height-viewport_height)/2
offset_left=(image_width-viewport_width)/2

add this offset values to each hotspot's x,y coordnates

将这个偏移值添加到每个热点的x,y坐标

var imageWidth = 1920;
var imageHeight = 1368;
var hotspots = [{
  x: 100,
  y: 200,
  height: 100,
  width: 50
}, {
  x: 300,
  y: 500,
  height: 200,
  width: 100
}, {
  x: 600,
  y: 600,
  height: 150,
  width: 100
}, {
  x: 900,
  y: 550,
  height: 100,
  width: 25
}];
var aspectRatio = imageWidth / imageHeight;

$(window).resize(function() {
  positionHotSpots();
});
var positionHotSpots = function() {
  $('.hotspot').remove();
  var wi = 0,
    hi = 0;
  var r = $('#image').width() / $('#image').height();
  if (aspectRatio <= r) {
    wi = $('#image').width();
    hi = $('#image').width() / aspectRatio;
  } else {
    wi = $('#image').height() * aspectRatio;
    hi = $('#image').height();
  }
  var offsetTop = (hi - $('#image').height()) / 2;
  var offsetLeft = (wi - $('#image').width()) / 2;
  $.each(hotspots, function(i, h) {

    var x = (wi * h.x) / imageWidth;
    var y = (hi * h.y) / imageHeight;

    var ww = (wi * (h.width)) / imageWidth;
    var hh = (hi * (h.height)) / imageHeight;

    var hotspot = $('<div>').addClass('hotspot').css({
      top: y - offsetTop,
      left: x - offsetLeft,
      height: hh,
      width: ww
    });
    $('body').append(hotspot);
  });
};
positionHotSpots();
html,
body {
  height: 100%;
  padding: 0;
  margin: 0;
}
#image {
  height: 100%;
  width: 100%;
  background: url('https://upload.wikimedia.org/wikipedia/commons/thumb/0/08/Alexanderplatz_Stadtmodell_1.jpg/1920px-Alexanderplatz_Stadtmodell_1.jpg');
  background-size: cover;
  background-repeat: no-repeat;
  background-position: center;
}
.hotspot {
  position: absolute;
  z-index: 1;
  background: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id='image'></div>

Solution for background-size:contain

解决方案background-size:包含

When using background-size:contain to calculate the dimensions of image, below formulas are used.

当使用背景尺寸:包含计算图像尺寸时,使用以下公式。

if(actual_image_aspectratio <= viewport_aspectratio)
    image_width = height_of_viewport * actual_image_aspectratio 
    image_height = height_of_viewport

And

if(actual_image_aspectratio > viewport_aspectratio)
    image_width = width_of_viewport
    image_height = width_ofviewport / actual_image_aspectratio

To fit the image in viewport additional space will be added on top & bottom / left & right of the image. So we should consider this space as an offset while plotting hotspots.

为了在viewport中匹配图像,将在图像的顶部、底部、左边和右边添加额外的空间。因此,在绘制热点时,我们应该把这个空间看作一个偏移量。

offset_top=(viewport_height-image_height)/2
offset_left=(viewport_width-image_width)/2

Add this offset values to each hotspot's x,y coordnates

将这个偏移值添加到每个hotspot的x,y coordnates。

 var imageWidth = 1920;
 var imageHeight = 1368;
 var hotspots = [{
   x: 100,
   y: 200,
   height: 100,
   width: 50
 }, {
   x: 300,
   y: 500,
   height: 200,
   width: 100
 }, {
   x: 600,
   y: 600,
   height: 150,
   width: 100
 }, {
   x: 900,
   y: 550,
   height: 100,
   width: 25
 }];
 var aspectRatio = imageWidth / imageHeight;

 $(window).resize(function() {
   positionHotSpots();
 });
 var positionHotSpots = function() {
   $('.hotspot').remove();
   var wi = 0,
     hi = 0;

   var r = $('#image').width() / $('#image').height();
   if (aspectRatio <= r) {
     wi = $('#image').height() * aspectRatio;
     hi = $('#image').height();

   } else {
     wi = $('#image').width();
     hi = $('#image').width() / aspectRatio;
   }
   var offsetTop = ($('#image').height() - hi) / 2;
   var offsetLeft = ($('#image').width() - wi) / 2;
   $.each(hotspots, function(i, h) {

     var x = (wi * h.x) / imageWidth;
     var y = (hi * h.y) / imageHeight;

     var ww = (wi * (h.width)) / imageWidth;
     var hh = (hi * (h.height)) / imageHeight;

     var hotspot = $('<div>').addClass('hotspot').css({
       top: y + offsetTop,
       left: x + offsetLeft,
       height: hh,
       width: ww
     });
     $('body').append(hotspot);
   });
 };
 positionHotSpots();
html,
body {
  height: 100%;
  padding: 0;
  margin: 0;
}
#image {
  height: 100%;
  width: 100%;
  background: url('https://upload.wikimedia.org/wikipedia/commons/thumb/0/08/Alexanderplatz_Stadtmodell_1.jpg/1920px-Alexanderplatz_Stadtmodell_1.jpg');
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
}
.hotspot {
  position: absolute;
  z-index: 1;
  background: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id='image'></div>

Solution for background-size:100% 100%

解决方案background-size:100% - 100%

This is the solution if someone looking for background-size:100% 100% check the working demo here. Resize the window to see the result.

这是解决方案,如果有人寻找背景尺寸:100% 100% 100%检查这里的工作演示。调整窗口大小以查看结果。

Here we don't need to calculate the image dimensions as the image will always fit to into the div. So we can just calculate the new coordinates of hotspot using height and width of viewport and actualimage.

在这里,我们不需要计算图像的尺寸,因为图像总是适合于div。因此,我们可以使用viewport和actualimage的高度和宽度来计算新热点的坐标。

var imageWidth = 1920;
var imageHeight = 1368;
var hotspots = [{
  x: 100,
  y: 200,
  height: 100,
  width: 50
}, {
  x: 300,
  y: 500,
  height: 200,
  width: 100
}, {
  x: 600,
  y: 600,
  height: 150,
  width: 100
}, {
  x: 900,
  y: 550,
  height: 100,
  width: 25
}];

$(window).resize(function() {
  positionHotSpots();
});


var positionHotSpots = function() {
  $('.hotspot').remove();

  $.each(hotspots, function(i, h) {
    var x = ($('#image').width() * h.x) / imageWidth;
    var y = ($('#image').height() * h.y) / imageHeight;

    var ww = ($('#image').width() * (h.width)) / imageWidth;
    var hh = ($('#image').height() * (h.height)) / imageHeight;
    var hotspot = $('<div>').addClass('hotspot').css({
      top: y,
      left: x,
      height: hh,
      width: ww
    });
    $('body').append(hotspot);
  });

};
positionHotSpots();
html,
body {
  height: 100%;
  margin: 0;
  padding: 0;
}
#image {
  height: 100%;
  width: 100%;
  background: url('https://upload.wikimedia.org/wikipedia/commons/thumb/0/08/Alexanderplatz_Stadtmodell_1.jpg/1920px-Alexanderplatz_Stadtmodell_1.jpg');
  background-size: 100% 100%;
}
.hotspot {
  position: absolute;
  z-index: 1;
  background: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id='image'></div>

Canvas solution

画布上的解决方案

Based on comment by @JayMee , create a canvas with same dimensions as actual image and draw hotspots as rectangles on the canvas.

基于@JayMee的评论,创建一个与实际图像尺寸相同的画布,并在画布上绘制矩形热点。

One advantage in this approach is we don't have to recalculate the hotspot coordinates on resizing window as the hotspot are drawn in image itself.

这种方法的一个优点是,当热点在图像本身中绘制时,我们不必重新计算调整窗口大小时的热点坐标。

 var imageWidth = 1920;
 var imageHeight = 1368;
 var hotspots = [{
   x: 100,
   y: 200,
   height: 100,
   width: 50
 }, {
   x: 300,
   y: 500,
   height: 200,
   width: 100
 }, {
   x: 600,
   y: 600,
   height: 150,
   width: 100
 }, {
   x: 900,
   y: 550,
   height: 100,
   width: 25
 }];

 var positionHotSpots = function() {


   var canvas = document.createElement('canvas');
   canvas.height = imageHeight;
   canvas.width = imageWidth;
   var context = canvas.getContext('2d');
   var imageObj = new Image();
   imageObj.onload = function() {

     context.drawImage(imageObj, 0, 0);

     $.each(hotspots, function(i, h) {
       context.rect(h.x, h.y, h.width, h.height);
     });
     context.fillStyle = "red";
     context.fill();
     $('#image').css('background-image', 'url("' + canvas.toDataURL() + '")');
   };
   imageObj.setAttribute('crossOrigin', 'anonymous');
   imageObj.src = 'https://upload.wikimedia.org/wikipedia/commons/thumb/0/08/Alexanderplatz_Stadtmodell_1.jpg/1920px-Alexanderplatz_Stadtmodell_1.jpg';

 };
 positionHotSpots();
html,
body {
  height: 100%;
  padding: 0;
  margin: 0;
}
#image {
  height: 100%;
  width: 100%;
  background-size: cover;
  background-repeat: no-repeat;
  background-position: center;
}
<!DOCTYPE html>
<html>

<head>
  <script src="https://code.jquery.com/jquery-2.1.4.js"></script>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>

<body>
  <div id='image'></div>
</body>

</html>

#2


5  

Okay, so not a lot of people know about the CSS measurements vh and vw (meaning viewheight and viewwidth). I've created a script that runs one time at pageload (unlike some other answers with ~50 lines of code at every resize).

好吧,没有多少人知道CSS测量vh和vw(意思是viewheight和viewwidth)。我已经创建了一个在pageload上运行一次的脚本(不同于其他每次调整大小都有大约50行代码的答案)。

It calculates the ratio of the background-image, applies two pieces of CSS to overlayContainer, and it's done.

它计算背景图像的比率,将两段CSS应用到overlayContainer,这样就完成了。

I've also added a div with id square. All this does is create a square for you to work with that has a ratio of 1:1, instead of the ratio the background has. This ensures that - if you want to create a square - you can use the same width and height, instead of manually trying to create one with different values. This also comes in handy when you slightly alter the size of the background-image, because with that square, your overlaying divs won't lose their aspect ratio.

我还添加了id square的div。所有这些所做的就是创建一个正方形让你使用它的比率为1:1,而不是背景的比率。这可以确保—如果您想创建一个正方形—您可以使用相同的宽度和高度,而不是手工尝试创建一个具有不同值的正方形。当您稍微改变背景图像的大小时,这也很有用,因为有了这个正方形,叠加的div不会失去它们的纵横比。

For background-size: cover, see this Fiddle.

背景尺寸:盖子,看这个小提琴。

For background-size: contain, see this Fiddle.

背景尺寸:包含,请参阅这个小提琴。

The HTML needed:

所需的HTML:

<div id="overlayContainer">
  <div id="square">
    <!-- Create overlay divs here -->
  </div>
</div>

The CSS needed:

CSS需要:

#overlayContainer{
  position: absolute; /* Fixed if the background-image is also fixed */
  min-width: 100vw;   /* When cover is applied */
  min-height: 100vh;  /* When cover is applied */
  max-width: 100vw;   /* When contain is applied */
  max-height: 100vh;  /* When contain is applied */
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

#square{
  position: relative;
  padding-bottom: 100%;
}

/* When creating divs, make them all absolutely positioned, and work with percentages only */
/* I advise looking at my Fiddle for an example */

The JavaScript needed:

所需的JavaScript:

var image = new Image()
image.src = $('body').css('background-image').replace(/url\((['"])?(.*?)\1\)/gi,'$2').split(',')[0]

/* When cover is applied, use this: */
$('#overlayContainer').css({'height':100/(image.width/image.height)+'vw','width':100/(image.height/image.width)+'vh'})

/* When contain is applied, use this: */
$('#overlayContainer').css({'height':100*(image.height/image.width)+'vw','width':100*(image.width/image.height)+'vh'})

Hope this helps

希望这有助于


Update by @LGSon

由@LGSon更新

I didn't expect to find a CSS only solution, though here it is, hiding itself in this answer, and therefore I decided to add it into the same.

我没有想到会找到一个CSS唯一的解决方案,尽管它就在这里,隐藏在这个答案中,因此我决定将它添加到同一个答案中。

By adding these 2 lines to the #overlayContainer rule (works for both cover and contain), the script can be dropped.

通过将这两行添加到#overlayContainer规则(适用于cover和contains),可以删除脚本。

width: calc(100vh * (1920 / 1368));
height: calc(100vw * (1368 / 1920));

Of course the script version has the advantage of automatically get the values, though since the hotspot(s) has a specific location point in the background, the image size will most likely be known.

当然,脚本版本具有自动获取值的优势,但是由于hotspot在后台有一个特定的位置,所以图像的大小很可能是已知的。

Sample with background-size: cover

样本background-size:封面

html, body{
  height: 100%;
  overflow: hidden;
}

body{
  margin: 0;
  background-image: url('https://upload.wikimedia.org/wikipedia/commons/thumb/0/08/Alexanderplatz_Stadtmodell_1.jpg/1920px-Alexanderplatz_Stadtmodell_1.jpg');
  background-size: cover;
  background-repeat: no-repeat;
  background-position: center;
}

#overlayContainer{
  position: absolute;
  width: calc(100vh * (1920 / 1368));
  height: calc(100vw * (1368 / 1920));
  min-width: 100vw;      /*  for cover    */
  min-height: 100vh;     /*  for cover    */
  /* max-width: 100vw;       for contain  */
  /* max-height: 100vh;      for contain  */
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

#square{
  position: relative;
  padding-bottom: 100%;
}

#square div{
  position: absolute;
  top: 19.75%;
  left: 49.75%;
  width: 4.75%;
  height: 4.75%;
  background-color: rgba(255,0,0,.7);
  border-radius: 50%;
}
<div id="overlayContainer">
  <div id="square">
    <div></div>
  </div>
</div>

#3


4  

Ok, so I tried to use your original idea, and modified only a few bits here and there.

好吧,我试着用你最初的想法,在这里和那里只修改了几个位元。

Instead of using percentages, I found it easier to use pixel values. So:

我发现使用像素值比使用百分比更容易。所以:

$(this).css({
  'margin-top': yPos + 'px',
  'margin-left': xPos + 'px',
  'width': xSize + 'px',
  'height': ySize + 'px'
});

Then, all we have to do is check the proportion of the viewport to see how we have to modify the div's properties

然后,我们要做的就是检查viewport的比例,看看我们如何修改div的属性。

if (windowAspectRatio > imageAspectRatio) {
  var ratio = windowWidth / imageWidth;
} else {
  var ratio = windowHeight / imageHeight;
}

xPos = xPos * ratio;
yPos = yPos * ratio;
xSize = xSize * ratio;
ySize = ySize * ratio;

Working example: http://codepen.io/jaimerodas/pen/RaGQVm

工作示例:http://codepen.io/jaimerodas/pen/RaGQVm

Stack snippet

堆栈段

var imageWidth = 1920,
    imageHeight = 1368,
    imageAspectRatio = imageWidth / imageHeight,
    $window = $(window);

var hotSpots = [{
  x: -210,
  y: -150,
  height: 250,
  width: 120
}, {
  x: 240,
  y: 75,
  height: 85,
  width: 175
}];

function appendHotSpots() {
  for (var i = 0; i < hotSpots.length; i++) {
    var $hotSpot = $('<div>').addClass('hot-spot');
    $('.container').append($hotSpot);
  }
  positionHotSpots();
}



function positionHotSpots() {
  var windowWidth = $window.width(),
    windowHeight = $window.height(),
    windowAspectRatio = windowWidth / windowHeight,
    $hotSpot = $('.hot-spot');

  $hotSpot.each(function(index) {
    var cambio = 1,
        xPos = hotSpots[index]['x'],
        yPos = hotSpots[index]['y'],
        xSize = hotSpots[index]['width'],
        ySize = hotSpots[index]['height'],
        desiredLeft = 0,
        desiredTop = 0;
    
    if (windowAspectRatio > imageAspectRatio) {
      var ratio = windowWidth / imageWidth;
    } else {
      var ratio = windowHeight / imageHeight;
    }
    
    xPos = xPos * ratio;
    yPos = yPos * ratio;
    xSize = xSize * ratio;
    ySize = ySize * ratio;

    $(this).css({
      'margin-top': yPos + 'px',
      'margin-left': xPos + 'px',
      'width': xSize + 'px',
      'height': ySize + 'px'
    });

  });
}

appendHotSpots();
$(window).resize(positionHotSpots);
html, body {
  margin: 0;
  width: 100%;
  height: 100%;
}

.container {
  width: 100%;
  height: 100%;
  position: relative;
  background-image: url(https://upload.wikimedia.org/wikipedia/commons/thumb/0/08/Alexanderplatz_Stadtmodell_1.jpg/1920px-Alexanderplatz_Stadtmodell_1.jpg);
  background-size: cover;
  background-repeat: no-repeat;
  background-position: center;
}

.hot-spot {
  background-color: red;
  border-radius: 0;
  position: absolute;
  top: 50%;
  left: 50%;
  z-index: 1;
  opacity: 0.8;
  content: "";
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container"></div>

#4


4  

Relying on css transforms and applying it to a single element gives you much better performance regardless of the number of hotspots (fewer DOM manipulations and much fewer re-flows). Hardware acceleration is also a nice-to-have :)

依赖css转换并将其应用到单个元素可以获得更好的性能,而不考虑热点的数量(更少的DOM操作和更少的回流)。硬件加速也是一个不错的选择:)

First, meta-code:

首先,meta-code:

  1. Create a .hot-spot--container inside your image .container

    在映像.container中创建.hot-spot容器

  2. Create .hot-spot and position/size them within the .hot-spot--container

    在.hot-spot容器中创建.hot-spot和位置/大小

  3. Transform .hot-spot--container mimicking background-size: cover behaviour

    转换。热点——容器模拟背景大小:覆盖行为

  4. Repeat #3 whenever there's a re-size

    当有尺寸调整时,重复第三点

Calculate your bg image ratio:

计算你的bg影像比率:

var bgHeight = 1368;
var bgWidth = 1920;
var bgRatio = bgHeight / bgWidth;

Whenever the window is re-sized, re-calculate container ratio:

每当窗口被重新调整大小时,重新计算集装箱比率:

var containerHeight = $container.height();
var containerWidth = $container.width();
var containerRatio = containerHeight / containerWidth;

Calculate scale factors to mimic background-size: cover behaviour...

计算规模因子来模拟背景尺寸:覆盖行为……

if (containerRatio > bgRatio) {
    //fgHeight = containerHeight
    //fgWidth = containerHeight / bgRatio
    xScale = (containerHeight / bgRatio) / containerWidth
} else {
    //fgHeight = containerWidth / bgRatio
    //fgWidth = containerWidth 
    yScale = (containerWidth * bgRatio) / containerHeight
}

...and apply the transform to the hot spot container element, essentially re-sizing and re-positioning it "in sync" with the background:

…将变换应用到热点容器元素,本质上是重新调整大小,并与背景“同步”重新定位:

var transform = 'scale(' + xScale + ', ' + yScale + ')';

$hotSpotContainer.css({
    'transform': transform
});

Fiddled: https://jsfiddle.net/ovfiddle/a3pdLodm/ (you can play with the preview window pretty effectively. Note the code can be adjusted to take pixel-based dimensions and positioning for hot spots, you'll just have to consider container and image sizes when calculating scale values)

fi: https://jsfiddle.net/ovfiddle/a3pdLodm/(您可以非常有效地使用预览窗口)。注意,代码可以调整为基于像素的维度和热点位置,在计算比例值时,您只需考虑容器和图像大小)

Update: the background-size: contain behaviour uses the same calculation except when the containerRatio is smaller than the bgRatio. Updating the background css and flipping the sign around is enough.

更新:后台大小:包含行为使用相同的计算,除非容器误差小于bgRatio。更新背景css和翻转符号就足够了。

#5


3  

Below is a jQuery solution,the bgCoverTool plugin repositions an element based on the scale of the parent's background image.

下面是一个jQuery解决方案,bgCoverTool插件基于父映像的大小重新定位一个元素。

//bgCoverTool Properties
$('.hot-spot').bgCoverTool({
  parent: $('#container'),
  top: '100px',
  left: '100px',
  height: '100px',
  width: '100px'})

Demo:

演示:

$(function() {
  $('.hot-spot').bgCoverTool();
});
html,
body {
  height: 100%;
  padding: 0;
  margin: 0;
}
#container {
  height: 100%;
  width: 100%;
  background: url('https://upload.wikimedia.org/wikipedia/commons/thumb/0/08/Alexanderplatz_Stadtmodell_1.jpg/1920px-Alexanderplatz_Stadtmodell_1.jpg');
  background-size: cover;
  background-repeat: no-repeat;
  position: relative;
}
.hot-spot {
  position: absolute;
  z-index: 1;
  background: red;
  left: 980px;
  top: 400px;
  height: 40px;
  width: 40px;
  opacity: 0.7;
}
<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <title>BG Cover Tool</title>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
  <script type="text/javascript" charset="utf-8">
    //bgCoverTool jQuery plugin
    (function($) {
      $.bgCoverTool = function(element, options) {
        var $element = $(element),
          imgsize = {};
        var defaults = {
          parent: $element.parent(),
          top: $element.css('top'),
          left: $element.css('left'),
          height: $element.css('height'),
          width: $element.css('width')
        };
        var plugin = this;
        plugin.settings = {};
        plugin.init = function() {
          plugin.settings = $.extend({}, defaults, options);
          var tempurl = plugin.settings.parent.css('background-image').slice(4, -1)
          .replace('"', '').replace('"', '');
          var tempimg = new Image();
          var console = console || {
            error: function() {}
          };
          if (plugin.settings.parent.css('background-size') != "cover") {
            return false;
          }
          if (typeof tempurl !== "string") {
            return false;
          }
          if (plugin.settings.top == "auto" || plugin.settings.left == "auto") {
            console.error("#" + $element.attr('id') + " needs CSS values for 'top' and 'left'");
            return false;
          }
          $(tempimg).on('load', function() {
            imgsize.width = this.width;
            imgsize.height = this.height;
            imageSizeDetected(imgsize.width, imgsize.height);
          });
          $(window).on('resize', function() {
            if ('width' in imgsize && imgsize.width != 0) {
              imageSizeDetected(imgsize.width, imgsize.height);
            }
          });
          tempimg.src = tempurl;
        };
        var imageSizeDetected = function(w, h) {
          var scale_h = plugin.settings.parent.width() / w,
            scale_v = plugin.settings.parent.height() / h,
            scale = scale_h > scale_v ? scale_h : scale_v;
          $element.css({
            top: parseInt(plugin.settings.top, 10) * scale,
            left: parseInt(plugin.settings.left, 10) * scale,
            height: parseInt(plugin.settings.height, 10) * scale,
            width: parseInt(plugin.settings.width, 10) * scale
          });

        };
        plugin.init();
      };
      /**
       * @param {options} object Three optional properties are parent, top and left.
       */
      $.fn.bgCoverTool = function(options) {
        return this.each(function() {
          if (undefined == $(this).data('bgCoverTool')) {
            var plugin = new $.bgCoverTool(this, options);
            $(this).data('bgCoverTool', plugin);
          }
        });
      }
    })(jQuery);
  </script>
</head>

<body>
  <div id="container">
    <div class="hot-spot"></div>
  </div>
</body>

</html>

#6


3  

A far simpler/better approach to you problem is to use an SVG element, it is better suited to your requirement. The cool thing about SVG is everything will scale proportionally by default because it is a vector object not a document flow object.

更简单/更好的方法是使用SVG元素,它更适合您的需求。SVG很酷的一点是,默认情况下,所有内容都会按比例缩放,因为它是向量对象,而不是文档流对象。

This example will demonstrate the technique

这个示例将演示该技术。

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>SVG</title>
        <style type="text/css" media="screen">
            body {
                background: #eee;
                margin: 0;
            }
            svg {
                display: block;
                border: 1px solid #ccc;
                position: absolute;
                top: 0;
                left: 0;
                width: 100%;
                height: 100%;
                background: #fff;
            }
            .face {
                stroke: #000;
                stroke-width: 20px;
                stroke-linecap: round
            }
        </style>
    </head>
    <body>
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="-350 -250 700 500">
            <circle r="200" class="face" fill="red"/>
            <path fill="none" class="face" transform="translate(-396,-230)" d="M487.41,282.411c-15.07,36.137-50.735,61.537-92.333,61.537 c-41.421,0-76.961-25.185-92.142-61.076"/>
            <circle id="leftEye" cx="-60" cy="-50" r="20" fill="#00F"/>
            <circle id="rightEye" cx="60" cy="-50" r="20" fill="#00F"/>
        </svg>
        <script type="text/javascript">
            document.getElementById('leftEye').addEventListener('mouseover', function (e) {
                alert('Left Eye');
            });
            document.getElementById('rightEye').addEventListener('mouseover', function (e) {
                alert('Right Eye');
            });
        </script>
    </body>
</html>

You can add images to SVG to achieve what you need.

您可以向SVG添加图像来实现所需的内容。

https://jsfiddle.net/tnt1/3f23amue/

https://jsfiddle.net/tnt1/3f23amue/

#1


11  

Solution for background-size:cover

解决方案background-size:封面

I am trying to give you solution(or consider as an idea). You can check working demo here. Resize the window to see the result.

我想给你一个解决方案(或者把它当作一个想法)。您可以在这里查看工作演示。调整窗口大小以查看结果。

First,I didn't understand why you are using transform,top:50% and left:50%for hotspot. So I tried to solve this using minimal use-case and adjusted your markup and css for my convenience.

首先,我不明白为什么要使用transform,top:50%,而hotspot:50%。因此,我尝试用最小的用例来解决这个问题,并调整了标记和css以方便我。

Here rImage is the aspect ratio of the original image.

这里的裂缝是原始图像的长宽比。

 var imageWidth = 1920;
 var imageHeight = 1368;
 var h = {
   x: imageWidth / 2,
   y: imageHeight / 2,
   height: 100,
   width: 50
 };
 var rImage= imageWidth / imageHeight;

In window resize handler,calculate the aspect ration of viewport r. Next,the trick is to find the dimensions of the image when we resize the window. But,viewport will clip the image to maintain aspect ratio. So to calculate the image dimensions we need some formula.

在窗口大小调整处理程序中,计算viewport r的方面定量。接下来,关键是当我们调整窗口大小时,找到图像的尺寸。但是,viewport将剪辑图像以保持长宽比。为了计算图像的尺寸我们需要一些公式。

When using background-size:cover to calculate the dimensions of image,below formulas are used.

当使用背景尺寸:覆盖来计算图像的尺寸时,使用下面的公式。

if(actual_image_aspectratio <= viewport_aspectratio)
    image_width = width_of_viewport
    image_height = width_ofviewport / actual_image_aspectratio 

And

if(actual_image_aspectratio > viewport_aspectratio)
    image_width = height_of_viewport * actual_image_aspectratio 
    image_height = height_of_viewport

You can refer this URL for more understanding on image dimensions calculation when using background-size:cover.

在使用背景尺寸:cover时,您可以参考这个URL以了解图像尺寸的计算。

After getting the dimensions of the image, we need to plot the hot-spot coordinates from actual image to new image dimensions.

得到图像的维数后,需要将热点坐标从实际图像绘制到新的图像维数。

To fit the image in viewport image will be clipped on top & bottom / left & right of the image. So we should consider this clipped image size as an offset while plotting hotspots.

为了适应viewport图像中的图像,将在图像的顶部和底部/左边和右边进行裁剪。因此,在绘制热点时,我们应该将剪切后的图像大小视为偏移量。

offset_top=(image_height-viewport_height)/2
offset_left=(image_width-viewport_width)/2

add this offset values to each hotspot's x,y coordnates

将这个偏移值添加到每个热点的x,y坐标

var imageWidth = 1920;
var imageHeight = 1368;
var hotspots = [{
  x: 100,
  y: 200,
  height: 100,
  width: 50
}, {
  x: 300,
  y: 500,
  height: 200,
  width: 100
}, {
  x: 600,
  y: 600,
  height: 150,
  width: 100
}, {
  x: 900,
  y: 550,
  height: 100,
  width: 25
}];
var aspectRatio = imageWidth / imageHeight;

$(window).resize(function() {
  positionHotSpots();
});
var positionHotSpots = function() {
  $('.hotspot').remove();
  var wi = 0,
    hi = 0;
  var r = $('#image').width() / $('#image').height();
  if (aspectRatio <= r) {
    wi = $('#image').width();
    hi = $('#image').width() / aspectRatio;
  } else {
    wi = $('#image').height() * aspectRatio;
    hi = $('#image').height();
  }
  var offsetTop = (hi - $('#image').height()) / 2;
  var offsetLeft = (wi - $('#image').width()) / 2;
  $.each(hotspots, function(i, h) {

    var x = (wi * h.x) / imageWidth;
    var y = (hi * h.y) / imageHeight;

    var ww = (wi * (h.width)) / imageWidth;
    var hh = (hi * (h.height)) / imageHeight;

    var hotspot = $('<div>').addClass('hotspot').css({
      top: y - offsetTop,
      left: x - offsetLeft,
      height: hh,
      width: ww
    });
    $('body').append(hotspot);
  });
};
positionHotSpots();
html,
body {
  height: 100%;
  padding: 0;
  margin: 0;
}
#image {
  height: 100%;
  width: 100%;
  background: url('https://upload.wikimedia.org/wikipedia/commons/thumb/0/08/Alexanderplatz_Stadtmodell_1.jpg/1920px-Alexanderplatz_Stadtmodell_1.jpg');
  background-size: cover;
  background-repeat: no-repeat;
  background-position: center;
}
.hotspot {
  position: absolute;
  z-index: 1;
  background: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id='image'></div>

Solution for background-size:contain

解决方案background-size:包含

When using background-size:contain to calculate the dimensions of image, below formulas are used.

当使用背景尺寸:包含计算图像尺寸时,使用以下公式。

if(actual_image_aspectratio <= viewport_aspectratio)
    image_width = height_of_viewport * actual_image_aspectratio 
    image_height = height_of_viewport

And

if(actual_image_aspectratio > viewport_aspectratio)
    image_width = width_of_viewport
    image_height = width_ofviewport / actual_image_aspectratio

To fit the image in viewport additional space will be added on top & bottom / left & right of the image. So we should consider this space as an offset while plotting hotspots.

为了在viewport中匹配图像,将在图像的顶部、底部、左边和右边添加额外的空间。因此,在绘制热点时,我们应该把这个空间看作一个偏移量。

offset_top=(viewport_height-image_height)/2
offset_left=(viewport_width-image_width)/2

Add this offset values to each hotspot's x,y coordnates

将这个偏移值添加到每个hotspot的x,y coordnates。

 var imageWidth = 1920;
 var imageHeight = 1368;
 var hotspots = [{
   x: 100,
   y: 200,
   height: 100,
   width: 50
 }, {
   x: 300,
   y: 500,
   height: 200,
   width: 100
 }, {
   x: 600,
   y: 600,
   height: 150,
   width: 100
 }, {
   x: 900,
   y: 550,
   height: 100,
   width: 25
 }];
 var aspectRatio = imageWidth / imageHeight;

 $(window).resize(function() {
   positionHotSpots();
 });
 var positionHotSpots = function() {
   $('.hotspot').remove();
   var wi = 0,
     hi = 0;

   var r = $('#image').width() / $('#image').height();
   if (aspectRatio <= r) {
     wi = $('#image').height() * aspectRatio;
     hi = $('#image').height();

   } else {
     wi = $('#image').width();
     hi = $('#image').width() / aspectRatio;
   }
   var offsetTop = ($('#image').height() - hi) / 2;
   var offsetLeft = ($('#image').width() - wi) / 2;
   $.each(hotspots, function(i, h) {

     var x = (wi * h.x) / imageWidth;
     var y = (hi * h.y) / imageHeight;

     var ww = (wi * (h.width)) / imageWidth;
     var hh = (hi * (h.height)) / imageHeight;

     var hotspot = $('<div>').addClass('hotspot').css({
       top: y + offsetTop,
       left: x + offsetLeft,
       height: hh,
       width: ww
     });
     $('body').append(hotspot);
   });
 };
 positionHotSpots();
html,
body {
  height: 100%;
  padding: 0;
  margin: 0;
}
#image {
  height: 100%;
  width: 100%;
  background: url('https://upload.wikimedia.org/wikipedia/commons/thumb/0/08/Alexanderplatz_Stadtmodell_1.jpg/1920px-Alexanderplatz_Stadtmodell_1.jpg');
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
}
.hotspot {
  position: absolute;
  z-index: 1;
  background: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id='image'></div>

Solution for background-size:100% 100%

解决方案background-size:100% - 100%

This is the solution if someone looking for background-size:100% 100% check the working demo here. Resize the window to see the result.

这是解决方案,如果有人寻找背景尺寸:100% 100% 100%检查这里的工作演示。调整窗口大小以查看结果。

Here we don't need to calculate the image dimensions as the image will always fit to into the div. So we can just calculate the new coordinates of hotspot using height and width of viewport and actualimage.

在这里,我们不需要计算图像的尺寸,因为图像总是适合于div。因此,我们可以使用viewport和actualimage的高度和宽度来计算新热点的坐标。

var imageWidth = 1920;
var imageHeight = 1368;
var hotspots = [{
  x: 100,
  y: 200,
  height: 100,
  width: 50
}, {
  x: 300,
  y: 500,
  height: 200,
  width: 100
}, {
  x: 600,
  y: 600,
  height: 150,
  width: 100
}, {
  x: 900,
  y: 550,
  height: 100,
  width: 25
}];

$(window).resize(function() {
  positionHotSpots();
});


var positionHotSpots = function() {
  $('.hotspot').remove();

  $.each(hotspots, function(i, h) {
    var x = ($('#image').width() * h.x) / imageWidth;
    var y = ($('#image').height() * h.y) / imageHeight;

    var ww = ($('#image').width() * (h.width)) / imageWidth;
    var hh = ($('#image').height() * (h.height)) / imageHeight;
    var hotspot = $('<div>').addClass('hotspot').css({
      top: y,
      left: x,
      height: hh,
      width: ww
    });
    $('body').append(hotspot);
  });

};
positionHotSpots();
html,
body {
  height: 100%;
  margin: 0;
  padding: 0;
}
#image {
  height: 100%;
  width: 100%;
  background: url('https://upload.wikimedia.org/wikipedia/commons/thumb/0/08/Alexanderplatz_Stadtmodell_1.jpg/1920px-Alexanderplatz_Stadtmodell_1.jpg');
  background-size: 100% 100%;
}
.hotspot {
  position: absolute;
  z-index: 1;
  background: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id='image'></div>

Canvas solution

画布上的解决方案

Based on comment by @JayMee , create a canvas with same dimensions as actual image and draw hotspots as rectangles on the canvas.

基于@JayMee的评论,创建一个与实际图像尺寸相同的画布,并在画布上绘制矩形热点。

One advantage in this approach is we don't have to recalculate the hotspot coordinates on resizing window as the hotspot are drawn in image itself.

这种方法的一个优点是,当热点在图像本身中绘制时,我们不必重新计算调整窗口大小时的热点坐标。

 var imageWidth = 1920;
 var imageHeight = 1368;
 var hotspots = [{
   x: 100,
   y: 200,
   height: 100,
   width: 50
 }, {
   x: 300,
   y: 500,
   height: 200,
   width: 100
 }, {
   x: 600,
   y: 600,
   height: 150,
   width: 100
 }, {
   x: 900,
   y: 550,
   height: 100,
   width: 25
 }];

 var positionHotSpots = function() {


   var canvas = document.createElement('canvas');
   canvas.height = imageHeight;
   canvas.width = imageWidth;
   var context = canvas.getContext('2d');
   var imageObj = new Image();
   imageObj.onload = function() {

     context.drawImage(imageObj, 0, 0);

     $.each(hotspots, function(i, h) {
       context.rect(h.x, h.y, h.width, h.height);
     });
     context.fillStyle = "red";
     context.fill();
     $('#image').css('background-image', 'url("' + canvas.toDataURL() + '")');
   };
   imageObj.setAttribute('crossOrigin', 'anonymous');
   imageObj.src = 'https://upload.wikimedia.org/wikipedia/commons/thumb/0/08/Alexanderplatz_Stadtmodell_1.jpg/1920px-Alexanderplatz_Stadtmodell_1.jpg';

 };
 positionHotSpots();
html,
body {
  height: 100%;
  padding: 0;
  margin: 0;
}
#image {
  height: 100%;
  width: 100%;
  background-size: cover;
  background-repeat: no-repeat;
  background-position: center;
}
<!DOCTYPE html>
<html>

<head>
  <script src="https://code.jquery.com/jquery-2.1.4.js"></script>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>

<body>
  <div id='image'></div>
</body>

</html>

#2


5  

Okay, so not a lot of people know about the CSS measurements vh and vw (meaning viewheight and viewwidth). I've created a script that runs one time at pageload (unlike some other answers with ~50 lines of code at every resize).

好吧,没有多少人知道CSS测量vh和vw(意思是viewheight和viewwidth)。我已经创建了一个在pageload上运行一次的脚本(不同于其他每次调整大小都有大约50行代码的答案)。

It calculates the ratio of the background-image, applies two pieces of CSS to overlayContainer, and it's done.

它计算背景图像的比率,将两段CSS应用到overlayContainer,这样就完成了。

I've also added a div with id square. All this does is create a square for you to work with that has a ratio of 1:1, instead of the ratio the background has. This ensures that - if you want to create a square - you can use the same width and height, instead of manually trying to create one with different values. This also comes in handy when you slightly alter the size of the background-image, because with that square, your overlaying divs won't lose their aspect ratio.

我还添加了id square的div。所有这些所做的就是创建一个正方形让你使用它的比率为1:1,而不是背景的比率。这可以确保—如果您想创建一个正方形—您可以使用相同的宽度和高度,而不是手工尝试创建一个具有不同值的正方形。当您稍微改变背景图像的大小时,这也很有用,因为有了这个正方形,叠加的div不会失去它们的纵横比。

For background-size: cover, see this Fiddle.

背景尺寸:盖子,看这个小提琴。

For background-size: contain, see this Fiddle.

背景尺寸:包含,请参阅这个小提琴。

The HTML needed:

所需的HTML:

<div id="overlayContainer">
  <div id="square">
    <!-- Create overlay divs here -->
  </div>
</div>

The CSS needed:

CSS需要:

#overlayContainer{
  position: absolute; /* Fixed if the background-image is also fixed */
  min-width: 100vw;   /* When cover is applied */
  min-height: 100vh;  /* When cover is applied */
  max-width: 100vw;   /* When contain is applied */
  max-height: 100vh;  /* When contain is applied */
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

#square{
  position: relative;
  padding-bottom: 100%;
}

/* When creating divs, make them all absolutely positioned, and work with percentages only */
/* I advise looking at my Fiddle for an example */

The JavaScript needed:

所需的JavaScript:

var image = new Image()
image.src = $('body').css('background-image').replace(/url\((['"])?(.*?)\1\)/gi,'$2').split(',')[0]

/* When cover is applied, use this: */
$('#overlayContainer').css({'height':100/(image.width/image.height)+'vw','width':100/(image.height/image.width)+'vh'})

/* When contain is applied, use this: */
$('#overlayContainer').css({'height':100*(image.height/image.width)+'vw','width':100*(image.width/image.height)+'vh'})

Hope this helps

希望这有助于


Update by @LGSon

由@LGSon更新

I didn't expect to find a CSS only solution, though here it is, hiding itself in this answer, and therefore I decided to add it into the same.

我没有想到会找到一个CSS唯一的解决方案,尽管它就在这里,隐藏在这个答案中,因此我决定将它添加到同一个答案中。

By adding these 2 lines to the #overlayContainer rule (works for both cover and contain), the script can be dropped.

通过将这两行添加到#overlayContainer规则(适用于cover和contains),可以删除脚本。

width: calc(100vh * (1920 / 1368));
height: calc(100vw * (1368 / 1920));

Of course the script version has the advantage of automatically get the values, though since the hotspot(s) has a specific location point in the background, the image size will most likely be known.

当然,脚本版本具有自动获取值的优势,但是由于hotspot在后台有一个特定的位置,所以图像的大小很可能是已知的。

Sample with background-size: cover

样本background-size:封面

html, body{
  height: 100%;
  overflow: hidden;
}

body{
  margin: 0;
  background-image: url('https://upload.wikimedia.org/wikipedia/commons/thumb/0/08/Alexanderplatz_Stadtmodell_1.jpg/1920px-Alexanderplatz_Stadtmodell_1.jpg');
  background-size: cover;
  background-repeat: no-repeat;
  background-position: center;
}

#overlayContainer{
  position: absolute;
  width: calc(100vh * (1920 / 1368));
  height: calc(100vw * (1368 / 1920));
  min-width: 100vw;      /*  for cover    */
  min-height: 100vh;     /*  for cover    */
  /* max-width: 100vw;       for contain  */
  /* max-height: 100vh;      for contain  */
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

#square{
  position: relative;
  padding-bottom: 100%;
}

#square div{
  position: absolute;
  top: 19.75%;
  left: 49.75%;
  width: 4.75%;
  height: 4.75%;
  background-color: rgba(255,0,0,.7);
  border-radius: 50%;
}
<div id="overlayContainer">
  <div id="square">
    <div></div>
  </div>
</div>

#3


4  

Ok, so I tried to use your original idea, and modified only a few bits here and there.

好吧,我试着用你最初的想法,在这里和那里只修改了几个位元。

Instead of using percentages, I found it easier to use pixel values. So:

我发现使用像素值比使用百分比更容易。所以:

$(this).css({
  'margin-top': yPos + 'px',
  'margin-left': xPos + 'px',
  'width': xSize + 'px',
  'height': ySize + 'px'
});

Then, all we have to do is check the proportion of the viewport to see how we have to modify the div's properties

然后,我们要做的就是检查viewport的比例,看看我们如何修改div的属性。

if (windowAspectRatio > imageAspectRatio) {
  var ratio = windowWidth / imageWidth;
} else {
  var ratio = windowHeight / imageHeight;
}

xPos = xPos * ratio;
yPos = yPos * ratio;
xSize = xSize * ratio;
ySize = ySize * ratio;

Working example: http://codepen.io/jaimerodas/pen/RaGQVm

工作示例:http://codepen.io/jaimerodas/pen/RaGQVm

Stack snippet

堆栈段

var imageWidth = 1920,
    imageHeight = 1368,
    imageAspectRatio = imageWidth / imageHeight,
    $window = $(window);

var hotSpots = [{
  x: -210,
  y: -150,
  height: 250,
  width: 120
}, {
  x: 240,
  y: 75,
  height: 85,
  width: 175
}];

function appendHotSpots() {
  for (var i = 0; i < hotSpots.length; i++) {
    var $hotSpot = $('<div>').addClass('hot-spot');
    $('.container').append($hotSpot);
  }
  positionHotSpots();
}



function positionHotSpots() {
  var windowWidth = $window.width(),
    windowHeight = $window.height(),
    windowAspectRatio = windowWidth / windowHeight,
    $hotSpot = $('.hot-spot');

  $hotSpot.each(function(index) {
    var cambio = 1,
        xPos = hotSpots[index]['x'],
        yPos = hotSpots[index]['y'],
        xSize = hotSpots[index]['width'],
        ySize = hotSpots[index]['height'],
        desiredLeft = 0,
        desiredTop = 0;
    
    if (windowAspectRatio > imageAspectRatio) {
      var ratio = windowWidth / imageWidth;
    } else {
      var ratio = windowHeight / imageHeight;
    }
    
    xPos = xPos * ratio;
    yPos = yPos * ratio;
    xSize = xSize * ratio;
    ySize = ySize * ratio;

    $(this).css({
      'margin-top': yPos + 'px',
      'margin-left': xPos + 'px',
      'width': xSize + 'px',
      'height': ySize + 'px'
    });

  });
}

appendHotSpots();
$(window).resize(positionHotSpots);
html, body {
  margin: 0;
  width: 100%;
  height: 100%;
}

.container {
  width: 100%;
  height: 100%;
  position: relative;
  background-image: url(https://upload.wikimedia.org/wikipedia/commons/thumb/0/08/Alexanderplatz_Stadtmodell_1.jpg/1920px-Alexanderplatz_Stadtmodell_1.jpg);
  background-size: cover;
  background-repeat: no-repeat;
  background-position: center;
}

.hot-spot {
  background-color: red;
  border-radius: 0;
  position: absolute;
  top: 50%;
  left: 50%;
  z-index: 1;
  opacity: 0.8;
  content: "";
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container"></div>

#4


4  

Relying on css transforms and applying it to a single element gives you much better performance regardless of the number of hotspots (fewer DOM manipulations and much fewer re-flows). Hardware acceleration is also a nice-to-have :)

依赖css转换并将其应用到单个元素可以获得更好的性能,而不考虑热点的数量(更少的DOM操作和更少的回流)。硬件加速也是一个不错的选择:)

First, meta-code:

首先,meta-code:

  1. Create a .hot-spot--container inside your image .container

    在映像.container中创建.hot-spot容器

  2. Create .hot-spot and position/size them within the .hot-spot--container

    在.hot-spot容器中创建.hot-spot和位置/大小

  3. Transform .hot-spot--container mimicking background-size: cover behaviour

    转换。热点——容器模拟背景大小:覆盖行为

  4. Repeat #3 whenever there's a re-size

    当有尺寸调整时,重复第三点

Calculate your bg image ratio:

计算你的bg影像比率:

var bgHeight = 1368;
var bgWidth = 1920;
var bgRatio = bgHeight / bgWidth;

Whenever the window is re-sized, re-calculate container ratio:

每当窗口被重新调整大小时,重新计算集装箱比率:

var containerHeight = $container.height();
var containerWidth = $container.width();
var containerRatio = containerHeight / containerWidth;

Calculate scale factors to mimic background-size: cover behaviour...

计算规模因子来模拟背景尺寸:覆盖行为……

if (containerRatio > bgRatio) {
    //fgHeight = containerHeight
    //fgWidth = containerHeight / bgRatio
    xScale = (containerHeight / bgRatio) / containerWidth
} else {
    //fgHeight = containerWidth / bgRatio
    //fgWidth = containerWidth 
    yScale = (containerWidth * bgRatio) / containerHeight
}

...and apply the transform to the hot spot container element, essentially re-sizing and re-positioning it "in sync" with the background:

…将变换应用到热点容器元素,本质上是重新调整大小,并与背景“同步”重新定位:

var transform = 'scale(' + xScale + ', ' + yScale + ')';

$hotSpotContainer.css({
    'transform': transform
});

Fiddled: https://jsfiddle.net/ovfiddle/a3pdLodm/ (you can play with the preview window pretty effectively. Note the code can be adjusted to take pixel-based dimensions and positioning for hot spots, you'll just have to consider container and image sizes when calculating scale values)

fi: https://jsfiddle.net/ovfiddle/a3pdLodm/(您可以非常有效地使用预览窗口)。注意,代码可以调整为基于像素的维度和热点位置,在计算比例值时,您只需考虑容器和图像大小)

Update: the background-size: contain behaviour uses the same calculation except when the containerRatio is smaller than the bgRatio. Updating the background css and flipping the sign around is enough.

更新:后台大小:包含行为使用相同的计算,除非容器误差小于bgRatio。更新背景css和翻转符号就足够了。

#5


3  

Below is a jQuery solution,the bgCoverTool plugin repositions an element based on the scale of the parent's background image.

下面是一个jQuery解决方案,bgCoverTool插件基于父映像的大小重新定位一个元素。

//bgCoverTool Properties
$('.hot-spot').bgCoverTool({
  parent: $('#container'),
  top: '100px',
  left: '100px',
  height: '100px',
  width: '100px'})

Demo:

演示:

$(function() {
  $('.hot-spot').bgCoverTool();
});
html,
body {
  height: 100%;
  padding: 0;
  margin: 0;
}
#container {
  height: 100%;
  width: 100%;
  background: url('https://upload.wikimedia.org/wikipedia/commons/thumb/0/08/Alexanderplatz_Stadtmodell_1.jpg/1920px-Alexanderplatz_Stadtmodell_1.jpg');
  background-size: cover;
  background-repeat: no-repeat;
  position: relative;
}
.hot-spot {
  position: absolute;
  z-index: 1;
  background: red;
  left: 980px;
  top: 400px;
  height: 40px;
  width: 40px;
  opacity: 0.7;
}
<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <title>BG Cover Tool</title>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
  <script type="text/javascript" charset="utf-8">
    //bgCoverTool jQuery plugin
    (function($) {
      $.bgCoverTool = function(element, options) {
        var $element = $(element),
          imgsize = {};
        var defaults = {
          parent: $element.parent(),
          top: $element.css('top'),
          left: $element.css('left'),
          height: $element.css('height'),
          width: $element.css('width')
        };
        var plugin = this;
        plugin.settings = {};
        plugin.init = function() {
          plugin.settings = $.extend({}, defaults, options);
          var tempurl = plugin.settings.parent.css('background-image').slice(4, -1)
          .replace('"', '').replace('"', '');
          var tempimg = new Image();
          var console = console || {
            error: function() {}
          };
          if (plugin.settings.parent.css('background-size') != "cover") {
            return false;
          }
          if (typeof tempurl !== "string") {
            return false;
          }
          if (plugin.settings.top == "auto" || plugin.settings.left == "auto") {
            console.error("#" + $element.attr('id') + " needs CSS values for 'top' and 'left'");
            return false;
          }
          $(tempimg).on('load', function() {
            imgsize.width = this.width;
            imgsize.height = this.height;
            imageSizeDetected(imgsize.width, imgsize.height);
          });
          $(window).on('resize', function() {
            if ('width' in imgsize && imgsize.width != 0) {
              imageSizeDetected(imgsize.width, imgsize.height);
            }
          });
          tempimg.src = tempurl;
        };
        var imageSizeDetected = function(w, h) {
          var scale_h = plugin.settings.parent.width() / w,
            scale_v = plugin.settings.parent.height() / h,
            scale = scale_h > scale_v ? scale_h : scale_v;
          $element.css({
            top: parseInt(plugin.settings.top, 10) * scale,
            left: parseInt(plugin.settings.left, 10) * scale,
            height: parseInt(plugin.settings.height, 10) * scale,
            width: parseInt(plugin.settings.width, 10) * scale
          });

        };
        plugin.init();
      };
      /**
       * @param {options} object Three optional properties are parent, top and left.
       */
      $.fn.bgCoverTool = function(options) {
        return this.each(function() {
          if (undefined == $(this).data('bgCoverTool')) {
            var plugin = new $.bgCoverTool(this, options);
            $(this).data('bgCoverTool', plugin);
          }
        });
      }
    })(jQuery);
  </script>
</head>

<body>
  <div id="container">
    <div class="hot-spot"></div>
  </div>
</body>

</html>

#6


3  

A far simpler/better approach to you problem is to use an SVG element, it is better suited to your requirement. The cool thing about SVG is everything will scale proportionally by default because it is a vector object not a document flow object.

更简单/更好的方法是使用SVG元素,它更适合您的需求。SVG很酷的一点是,默认情况下,所有内容都会按比例缩放,因为它是向量对象,而不是文档流对象。

This example will demonstrate the technique

这个示例将演示该技术。

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>SVG</title>
        <style type="text/css" media="screen">
            body {
                background: #eee;
                margin: 0;
            }
            svg {
                display: block;
                border: 1px solid #ccc;
                position: absolute;
                top: 0;
                left: 0;
                width: 100%;
                height: 100%;
                background: #fff;
            }
            .face {
                stroke: #000;
                stroke-width: 20px;
                stroke-linecap: round
            }
        </style>
    </head>
    <body>
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="-350 -250 700 500">
            <circle r="200" class="face" fill="red"/>
            <path fill="none" class="face" transform="translate(-396,-230)" d="M487.41,282.411c-15.07,36.137-50.735,61.537-92.333,61.537 c-41.421,0-76.961-25.185-92.142-61.076"/>
            <circle id="leftEye" cx="-60" cy="-50" r="20" fill="#00F"/>
            <circle id="rightEye" cx="60" cy="-50" r="20" fill="#00F"/>
        </svg>
        <script type="text/javascript">
            document.getElementById('leftEye').addEventListener('mouseover', function (e) {
                alert('Left Eye');
            });
            document.getElementById('rightEye').addEventListener('mouseover', function (e) {
                alert('Right Eye');
            });
        </script>
    </body>
</html>

You can add images to SVG to achieve what you need.

您可以向SVG添加图像来实现所需的内容。

https://jsfiddle.net/tnt1/3f23amue/

https://jsfiddle.net/tnt1/3f23amue/