![](/img/trans.png)
[英]Stretching a background image vertically not in scale, not just cover - Can this be accomplished?
[英]Scale element proportional to Background Cover with jQuery
我有一個棘手的問題:我在我正在研究的網站上有一個完整的背景。 現在我想將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)<1則設置值為var Scale =(windowWidth / imageWidth)否則var Scale(windowHeight / imageHeight)並使用var Scale進行變換:scale(Scale,Scale)但我不能設法使這項工作......
也許你們可以幫幫我...
背景大小的解決方案:封面
我試圖給你解決方案(或考慮作為一個想法)。 你可以在這里查看工作演示。 調整窗口大小以查看結果。
首先,我不明白你為什么要使用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
時,您可以參考此URL以更深入地了解圖像尺寸計算。
獲取圖像的尺寸后,我們需要繪制從實際圖像到新圖像尺寸的熱點坐標。
要在視口圖像中擬合圖像,將在圖像的頂部和底部/左側和右側剪切。 因此,我們應該在繪制熱點時將此剪裁的圖像大小視為偏移。
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 * hx) / imageWidth; var y = (hi * hy) / 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
要在視口中調整圖像,將在圖像的頂部和底部/左側和右側添加額外的空間。 因此,我們應該在繪制熱點時將此空間視為偏移量。
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 * hx) / imageWidth; var y = (hi * hy) / 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%
這是解決方案background-size:100% 100%
檢查這里的工作演示。 調整窗口大小以查看結果。
在這里,我們不需要計算圖像尺寸,因為圖像將始終適合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() * hx) / imageWidth; var y = ($('#image').height() * hy) / 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(hx, hy, 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>
好吧,所以很多人都不知道CSS單位vh
和vw
(意思是ViewportHeight和ViewportWidth)。 我創建了一個在pageload運行一次的腳本(與每次調整大小時運行的其他一些答案不同)。
它計算背景圖像的比例,向overlayContainer
添加兩個CSS規則,並完成。
那里還有一個div #square
,其目的是我們有一個比例為1:1的容器作為畫布。 此比率可確保在制作疊加元素時,垂直和水平百分比距離相同。
對於background-size: cover
,請參閱此小提琴 。
對於background-size: contain
,請參閱此小提琴 。
HTML:
<div id="overlayContainer">
<div id="square">
<!-- Overlaying elements 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 placing overlaying elements, make them all absolutely positioned, and work with percentages only */
/* Look at my Fiddles for examples */
JavaScript(jQuery):
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
樣本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%; }
<div id="overlayContainer"> <div id="square"> <div></div> </div> </div>
好的,所以我嘗試使用你原來的想法,並在這里和那里只修改了幾個位。
我沒有使用百分比,而是發現使用像素值更容易。 所以:
$(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
堆棧代碼段
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>
依賴於css轉換並將其應用於單個元素,無論熱點數量多少(DOM操作更少,重新流動更少),都可以提供更好的性能。 硬件加速也是一個不錯的選擇:)
首先,元代碼:
在圖像.container
創建一個.hot-spot--container
在.hot-spot--container
創建.hot-spot
並定位/調整它們的大小
變換.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
});
擺弄: https ://jsfiddle.net/ovfiddle/a3pdLodm/(您可以非常有效地使用預覽窗口。注意代碼可以調整為基於像素的尺寸和定位熱點,你只需要考慮計算比例值時的容器和圖像大小)
更新: background-size: contain
行為使用相同的計算,除非containerRatio 小於 bgRatio。 更新背景css並翻轉符號就足夠了 。
下面是一個jQuery解決方案,bgCoverTool插件根據父級背景圖像的比例重新定位一個元素。
//bgCoverTool Properties
$('.hot-spot').bgCoverTool({
parent: $('#container'),
top: '100px',
left: '100px',
height: '100px',
width: '100px'})
演示:
$(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>
解決問題的一個更簡單/更好的方法是使用SVG元素,它更適合您的要求。 關於SVG的一件很酷的事情是,默認情況下,所有內容都會按比例縮放,因為它是一個矢量對象,而不是文檔流對象。
此示例將演示該技術
<!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>
您可以將圖像添加到SVG以實現所需。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.