我有一个棘手的问题: 我在我正在努力的网站上有一个完整的背景。 现在我想将div附加到图像上的某个位置,并且div的缩放方式与使用“background-size:cover”属性的背景图像相同。 所以在这个例子中,我有一个城市的图片,它覆盖了浏览器窗口,我希望我的div覆盖一个特定的建筑物,无论窗口大小如何。
我已经设法让div坚持到一个位置,但是不能让它正确调整大小。到目前为止我做了什么:
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);
我的想法是: 如果(imageWidth / windowWidth)&lt; 1然后设置值为var Scale =(windowWidth / imageWidth)否则var Scale(windowHeight / imageHeight) 并使用var Scale进行变换:scale(Scale,Scale) 但我无法成功完成这项工作......
也许你们可以帮助我......
答案 0 :(得分:11)
背景大小的解决方案:封面
我试图给你解决方案(或考虑作为一个想法)。您可以查看工作演示here。调整窗口大小以查看结果。
首先,我不明白为什么您使用transform
,top:50%
和left:50%
作为热点。所以我尝试用最少的用例来解决这个问题,并为了方便起见调整了你的标记和css。
此处rImage
是原始图片的宽高比。
var imageWidth = 1920;
var imageHeight = 1368;
var h = {
x: imageWidth / 2,
y: imageHeight / 2,
height: 100,
width: 50
};
var rImage= imageWidth / imageHeight;
在窗口大小调整处理程序中,计算视口r
的宽高比。
接下来,诀窍是在调整窗口大小时找到图像的尺寸。但是,视口将剪切图像以保持纵横比。因此,要计算图像尺寸,我们需要一些公式。
使用background-size:cover
计算图像尺寸时,使用以下公式。
if(actual_image_aspectratio <= viewport_aspectratio)
image_width = width_of_viewport
image_height = width_ofviewport / actual_image_aspectratio
和
if(actual_image_aspectratio > viewport_aspectratio)
image_width = height_of_viewport * actual_image_aspectratio
image_height = height_of_viewport
使用background-size:cover
时,您可以参考this URL了解有关图像尺寸计算的更多信息。
获取图像的尺寸后,我们需要绘制从实际图像到新图像尺寸的热点坐标。
在视口图像中拟合图像将被剪裁在顶部和顶部。底部/左侧&amp;图像右侧。因此,我们应该在绘制热点时将此剪裁的图像大小视为偏移。
offset_top=(image_height-viewport_height)/2
offset_left=(image_width-viewport_width)/2
将此偏移值添加到每个热点的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>
背景大小的解决方案:包含
使用background-size:contain
计算图像尺寸时,使用以下公式。
if(actual_image_aspectratio <= viewport_aspectratio)
image_width = height_of_viewport * actual_image_aspectratio
image_height = height_of_viewport
和
if(actual_image_aspectratio > viewport_aspectratio)
image_width = width_of_viewport
image_height = width_ofviewport / actual_image_aspectratio
要在视口中调整图像,将在顶部和顶部添加额外的空间。底部/左侧&amp;图像右侧。因此,我们应该在绘制热点时将此空间视为偏移量。
offset_top=(viewport_height-image_height)/2
offset_left=(viewport_width-image_width)/2
将此偏移值添加到每个热点的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').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>
背景大小的解决方案:100%100%
如果找到background-size:100% 100%
的人检查工作演示here,则可以使用此解决方案。调整窗口大小以查看结果。
这里我们不需要计算图像尺寸,因为图像总是适合div。因此,我们可以使用视口和实际图像的height
和width
来计算热点的新坐标。
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>
画布解决方案
根据@JayMee的评论,在画布上创建一个与实际图片尺寸相同的canvas
和draw
个热点rectangles
。
这种方法的一个优点是我们不必在调整窗口大小时重新计算热点坐标,因为热点是在图像本身中绘制的。
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>
答案 1 :(得分:6)
好的,所以很多人都不知道CSS测量vh
和vw
(意思是视图高度和视图宽度)。我已经创建了一个在pageload上运行一次的脚本(与其他一些代码相比,每次调整大小都有~50行代码)。
它计算背景图像的比例,将两个CSS应用到overlayContainer
,并完成它。
我还添加了一个ID为square
的div。所有这一切都是创建一个方块供您使用,其比例为1:1,而不是背景的比例。这样可以确保 - 如果要创建正方形 - 可以使用相同的宽度和高度,而不是手动尝试创建具有不同值的宽度和高度。当你略微改变背景图像的大小时,这也会派上用场,因为使用那个方格,你的重叠div不会失去它们的宽高比。
对于background-size: cover
,请参阅this Fiddle。
对于background-size: contain
,请参阅this Fiddle。
所需的HTML:
<div id="overlayContainer">
<div id="square">
<!-- Create overlay divs here -->
</div>
</div>
所需的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 */
需要的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'})
希望这有帮助
@LGSon更新
我没有期望找到一个仅CSS 解决方案,虽然在这里,它隐藏在这个答案中,因此我决定将它添加到同一个中。
通过将这两行添加到#overlayContainer
规则(适用于cover
和contain
),可以删除该脚本。
width: calc(100vh * (1920 / 1368));
height: calc(100vw * (1368 / 1920));
当然脚本版本具有自动获取值的优势,但由于热点在背景中具有特定的位置点,因此图像大小很可能是已知的。
background-size: cover
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%;
}
&#13;
<div id="overlayContainer">
<div id="square">
<div></div>
</div>
</div>
&#13;
答案 2 :(得分:4)
好的,所以我尝试使用你原来的想法,并且在这里和那里只修改了几个。
我没有使用百分比,而是发现使用像素值更容易。所以:
$(this).css({
'margin-top': yPos + 'px',
'margin-left': xPos + 'px',
'width': xSize + 'px',
'height': ySize + 'px'
});
然后,我们要做的就是检查视口的比例,看看我们如何修改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;
工作示例: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>
答案 3 :(得分:4)
依赖于css转换并将其应用于单个元素,无论热点数量多少(DOM操作更少,重新流程更少),都可以提供更好的性能。硬件加速也是一个不错的选择:)
首先,元代码:
在图片.hot-spot--container
.container
创建.hot-spot
并在.hot-spot--container
转换.hot-spot--container
模仿background-size: cover
行为
每当重新调整大小时重复#3
计算你的bg图像比率:
var bgHeight = 1368;
var bgWidth = 1920;
var bgRatio = bgHeight / bgWidth;
每当重新调整窗口大小时,重新计算容器比率:
var containerHeight = $container.height();
var containerWidth = $container.width();
var containerRatio = containerHeight / containerWidth;
计算缩放因子以模仿background-size: cover
行为......
if (containerRatio > bgRatio) {
//fgHeight = containerHeight
//fgWidth = containerHeight / bgRatio
xScale = (containerHeight / bgRatio) / containerWidth
} else {
//fgHeight = containerWidth / bgRatio
//fgWidth = containerWidth
yScale = (containerWidth * bgRatio) / containerHeight
}
...并将变换应用于热点容器元素,基本上重新调整大小并将其与背景“同步”重新定位:
var transform = 'scale(' + xScale + ', ' + yScale + ')';
$hotSpotContainer.css({
'transform': transform
});
Fiddled:https://jsfiddle.net/ovfiddle/a3pdLodm/(您可以非常有效地使用预览窗口。请注意,可以调整代码以采用基于像素的尺寸和热点定位,您只需要考虑容器和图像大小在计算比例值时)
更新:background-size: contain
行为使用相同的计算,除非containerRatio 小于而不是bgRatio。 Updating the background css and flipping the sign around is enough
答案 4 :(得分:3)
下面是一个jQuery解决方案,bgCoverTool插件根据父级背景图像的比例重新定位一个元素。
//bgCoverTool Properties
$('.hot-spot').bgCoverTool({
parent: $('#container'),
top: '100px',
left: '100px',
height: '100px',
width: '100px'})
演示:
$(function() {
$('.hot-spot').bgCoverTool();
});
&#13;
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;
}
&#13;
<!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>
&#13;
答案 5 :(得分:3)
更简单/更好的方法是使用SVG元素,它更适合您的要求。关于SVG很酷的事情是默认情况下一切都会按比例缩放,因为它是一个矢量对象而不是文档流对象。
此示例将演示技术
parse()
您可以将图像添加到SVG以实现您的需要。