使用jQuery按比例缩放背景的元素
我有一个棘手的问题:我在我正在工作的网站上有一个全面的背景。 现在我想附加一个div到图像上的某个位置,并且div的缩放方式与我的背景图像的“background-size:cover”属性一样。 因此,在这个例子中,我有一个城市的照片,覆盖浏览器窗口,我希望我的div覆盖一个特定的build筑物,不pipe窗口大小。
我已经设法使div坚持一个位置,但不能使其正确resize。 我到目前为止做了什么:
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);
我的想法是:如果(图像宽度/窗口宽度)<1,然后设置为VAR比例值=(windowWidth / imageWidth)否则无量纲(windowHeight / imageHeight),并使用变换比例缩放(比例,缩放),但我couldnt设法做这个工作…
也许你们可以帮我…
解决scheme的背景大小:封面
我试图给你解决scheme(或考虑作为一个想法)。 你可以在这里查看工作演示。 调整窗口大小以查看结果。
首先,我不明白你为什么使用transform
, top:50%
, left:50%
for hotots。 所以我试着用最less的用例来解决这个问题,并且为了方便起见而调整了你的标记和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
的纵横比。 接下来,诀窍是当我们调整窗口的大小时,find图像的尺寸。 但是,视口会剪切图像以保持宽高比。 所以要计算图像的尺寸,我们需要一些公式。
当使用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>
好吧,所以我试图用你最初的想法,并且在这里和那里只修改了几个位。
而不是使用百分比,我发现使用像素值更容易。 所以:
$(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转换并将其应用于单个元素,无论热点的数量如何(更less的DOM操作和更less的重新stream动),都可以提供更好的性能。 硬件加速也是一件好事:)
首先,元码:
-
在您的图像
.container
创build一个.hot-spot--container
-
在
.hot-spot--container
内创build.hot-spot
和位置/大小 -
转换
.hot-spot--container
模仿background-size: cover
.hot-spot--container
background-size: cover
行为 -
重复#3,每当有一个重新大小
计算你的图像比例:
var bgHeight = 1368; var bgWidth = 1920; var bgRatio = bgHeight / bgWidth;
每当窗户重新resize时,重新计算集装箱比率:
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 }
…并将转换应用于热点容器元素,实质上重新resize并将其与后台“同步”重新定位:
var transform = 'scale(' + xScale + ', ' + yScale + ')'; $hotSpotContainer.css({ 'transform': transform });
小提琴: https ://jsfiddle.net/ovfiddle/a3pdLodm/(你可以很有效地使用预览窗口,注意代码可以调整,以像素为基础的尺寸和热点定位,你只需要考虑计算比例值时的容器和图像大小)
更新:除了当containerRatio 小于 bgRatio时, background-size: contain
contains行为使用相同的计算。 更新背景CSS和翻转标志就足够了 。
好吧,所以不是很多人知道CSS测量vh
和vw
(意思是视图高度和视图宽度)。 我创build了一个在pageload上运行一次的脚本(不同于在每个resize时使用~50行代码的其他答案)。
它计算背景图像的比例,将两个CSS应用到overlayContainer
,然后完成。
我也添加了一个ID为square
的div。 所有这些都是为你创build一个正方形,它的比例是1:1,而不是背景的比例。 这确保了 – 如果你想创build一个正方形 – 你可以使用相同的宽度和高度,而不是手动尝试创build一个不同的值。 当你稍微改变背景图像的大小时,这也会派上用场,因为用这个正方形,你的叠加div不会失去宽高比。
对于background-size: cover
,请参阅此小提琴 。
对于background-size: contain
,请参阅此小提琴 。
所需的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更新
我没有想到find一个CSS解决scheme,尽pipe这里是隐藏在这个答案中,所以我决定把它添加到同一个。
通过将这两行添加到#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>
下面是一个jQuery解决scheme,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的一件很酷的事情是,默认情况下所有东西都会按比例缩放,因为它是一个vector对象而不是文档stream对象。
这个例子将演示这个技术
<!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以实现您所需的function。