如何在HTML页面中保持图像的位置相对于背景图像的位置?

时间:2016-08-04 09:21:11

标签: jquery css arrays html5 jquery-animate

我有一个HTML页面,我将背景图像放在body css中。

body {
    /*cursor: URL("target.png"),pointer;*/
    background-color:#202020;
    background-image: url('../Images/BGimage.png');
    background-repeat: no-repeat;
    background-size: contain;
    background-position: center center;
}

现在,当我在html页面中添加新图像时,

<img src="target.png" style="position:absolute;margin-top:280px;margin-left:700px;z-index:1" />

当我全屏或最小化窗口时,图像的位置会发生变化。背景图像是固定的,但新图像会移动。我该如何解决这个问题?

5 个答案:

答案 0 :(得分:1)

要在调整大小模式下正确修复图像,您需要位置:相对于父级(在您的情况下,身体标记)。如此简单地将position;relative提供给body标签,您就完成了。

请参阅here

更新HTML

<img src="target.png" style="position:absolute;margin-top:280px;right:70px;z-index:1" />

更新了CSS

body {
    /*cursor: URL("target.png"),pointer;*/
    background-color:#202020;
    background-image: url('../Images/BGimage.png');
    background-repeat: no-repeat;
    background-size: contain;
    background-position: center center;
    position:relative;
}

答案 1 :(得分:0)

<img src="target.png" style="position:absolute;top:280px;left:700px;z-index:1" />

使用顶部和左侧可以设置图像的水平和垂直位置,然后它将不会移动,因为它位于像素的那个位置。

答案 2 :(得分:0)

如果您希望较小的图像将非重复背景图像覆盖在相对于背景图像的永久固定位置,那么您也可以在图像编辑应用程序中打开背景图像,复制和将较小的图像粘贴到画布中,按照您想要的方式定位,并将其另存为新的图像文件。然后,您可以将该新图像文件用作背景图像。

当然,如果您需要在页面生命周期内对较小的图像应用动态更改(例如转换或对其CSS的动态更改),则无法执行此操作。但除此之外,我认为这将是最好的解决方案。

我更仔细地研究了这个问题。由于您需要对较小的图像进行动态更改,因此将其嵌入背景图像将不起作用。相反,有必要计算并指定较小图像在包含元素中的确切位置,以便将背景图像覆盖在您想要的确切位置。

要完成此任务,有必要确定背景图像相对于包含元素的最终绝对位置。

CSS属性值序列

重要的是要理解CSS属性值经历一个复杂的计算过程,该过程可能包含浏览器默认值,CSS源声明,特异性,继承,相互依赖的属性交互,相对值的布局相关分辨率,以及在某些情况下舍入/近似

我们可以通过列出在此计算序列中可以发挥作用的不同阶段值来总结此过程:

initial value用作根元素的浏览器默认值。也用作非继承属性的非根元素的浏览器默认值(继承属性可以从根或其父级继承初始值,如果不在其沿袭或自我样式中覆盖)。

source value文档源中明确指定的值(文件链接,样式标记和内联样式属性)。这考虑了CSS的级联规则,为元素/伪元素选择最具体的规则。

specified value给定的源值,否则为继承的值(对于继承的属性)或初始值(对于非继承的属性)。请注意,源值本身可以设置为文字裸字inheritinitial

computed value来自指定值的派生,可解析inheritinitial以获取更具体的值,并应用其他转换,例如span position:absolute更改为{{1 }}。预布局。

used value执行所有计算后的最终值。后布局。将自动和百分比解析为绝对像素值。

actual value应用了所有近似值后的使用值。例如,用户代理可能只能使用整数像素值渲染边框,并且可能被迫接近计算出的边框宽度。

令人困惑的是,getComputedStyle()函数返回计算值,而是返回一个称为已解析值的内容:

<{> resolved valuedisplay:block返回。 (1)对于getComputedStyle(),它始终是使用的值。 (2)否则,对于具有line-height或(b)的元素/伪元素(a),该属性不适用,或(c)过度约束display:none,{ {1}},bottomleft,它始终是计算值(因为在大多数情况下无法确定其布局)。 (3)否则,对于righttopbottomleftrighttopwidth和{ {1}}属性,它始终是使用的值。 (4)否则,它始终是计算值。

问题

问题是我们需要背景图片的位置。背景图像本身不是一个元素,因此我们无法从CSS使用的值中获取它的位置,因为它没有自己的CSS值。此外,由于背景图像放置的复杂性,其精确位置可以从其包含元素的位置以微妙的方式变化,这取决于(1)background-originbackground-size和{{3的值(2)原始背景图像大小,以及(3)包含元素大小,其本身可以取决于用户浏览器窗口的大小,其可以动态地改变。

当然,存在上述三个CSS属性的值的排列,这些属性将背景图像相对于其包含元素固定到位,并且允许我们静态地确定将较小图像放置在期望值的绝对位置相对于背景图像的位置,无论其他任何细节。但是对于您的情况,由于您有heightpadding,因此此处不适用。

在一般情况下,我们需要根据包含元素的上述三个CSS属性动态计算背景图像的位置,以及包含元素的其他CSS属性(特别是填充和,对于margin,边框),原始图片大小和包含元素大小。

解决方案

该解决方案需要JavaScript函数来计算包含元素中背景图像的位置。

请注意,我一直在使用术语&#34;背景位置&#34;在目标计算的描述中有点松散,但应该澄清的是,为了计算较小图像的所需位置,我们需要计算左下角右下角背景图像的一角。换句话说,我们需要确定背景图像的整个边界框,以便能够计算背景图像中我们希望放置较小图像的目标位置的坐标。

为什么background-size:contain无法直接使用

您可能认为我们应该能够在包含元素的情况下运行background-position:center center来获取背景图像的最终绝对位置。这是不正确的。原因是我们需要背景图像位置的最终使用值。如前所述,background-origin:border-box仅返回一些CSS属性的已使用值,即使只是在某些情况下,getComputedStyle().backgroundPosition也不在其中。

另外,正如刚才所说,我们还需要背景图像的右下角,而getComputedStyle().backgroundPosition只会返回左上角。我们也可以通过获取getComputedStyle()来获得右下角,但backgroundPosition受到与backgroundPosition相同的限制,因为它只会给我们计算值而不是使用值。 / p>

浏览器API解决方案

我简要地搜索了浏览器API中可用于获取上述两个CSS属性的已使用值的规定,但不幸的是,似乎没有任何规定。请参阅background-position,它没有令人满意地回答这个问题,并且没有一个会话者似乎知道已解决的值的概念,以及getComputedStyle().backgroundSize函数返回大多数情况下的计算值。

现有JavaScript解决方案

我做了一些搜索,看看是否有人已经提出了解决此问题的JavaScript解决方案。最近似乎是Is there a cross-browser method of getting the used css values of all properties of all elements?中给出的JavaScript函数。不幸的是,该函数只计算背景图像的 size ,所以还不够。 (而且我认为它不适用于所有情况,但我还没有对此进行验证。)

<强>解决方案

所以,我已经编写了自己的JavaScript函数来解决这个问题。

回想一下backgroundSizebackgroundPosition没有给我们这两个属性的最终使用值;他们只给我们计算值。但是,这些计算值为我们提供了一个必要的起点,可以手动计算符合标准的浏览器在布局包含元素及其背景图像时所使用的值。

因此,在我的函数中,我得到上面两个计算值以及getComputedStyle(),以及填充和边框CSS值,然后继续计算背景图像的边界框,以适应当前的排列。值。我们必须处理getComputedStyle().backgroundPosition的所有三个可能值,getComputedStyle.backgroundSize的百分比和绝对像素值,百分比,绝对像素值,getComputedStyle().backgroundOriginbackgroundOrigin以及{{1 } backgroundPosition

下面我将该功能作为完整工作演示的一部分。我有点过火,发现地球的背景图像,国际空间站的图片,透过较小的图像,在背景图像中定义了三个不同的位置,指定为宽度和高度的百分比,并提供控件允许(1)在三个不同位置之间转换,以及(2)动态调整包含元素的大小,触发较小的图像重新计算其所需的绝对像素位置,以便保留在背景图像中当前选定的位置。

&#13;
&#13;
auto
&#13;
cover
&#13;
contain
&#13;
&#13;
&#13;

<强>测试

我在Firefox中非常彻底地测试了主要的实现函数backgroundSize,为上述三个属性尝试了810种不同的排列,并且它对所有这些都很有效。我在Chrome和Internet Explorer中进行了不那么彻底的抽查。所有检查都在Chrome中运行,但不幸的是,Internet Explorer在几种情况下都失败了,这似乎是因为window.getBackgroundImageBox = function(elem,i) { // elem -- the element that instantiates the background image // i -- the index into the list of background images set in the CSS // there are 8 specific CSS background properties: // // background-image: assume this is set to an image URL // background-position: will get resolved value, must calculate used value // background-size: will get resolved value, must calculate used value // background-repeat: assume this is set to no-repeat // background-origin: must take this into account when determining pos and size // background-clip: can ignore this; only clips, doesn't change actual image pos and size // background-attachment: assume either scroll (default), or fixed with no scrolling, so ignore this // background-color: not relevant to pos and size // default i if not given if (i === undefined) i = 0; // get resolved origin, size, and pos let computedStyle = getComputedStyle(elem); let resolvedOrigin = computedStyle.backgroundOrigin.split(', ')[i]; let resolvedSize = computedStyle.backgroundSize.split(', ')[i]; let resolvedPos = computedStyle.backgroundPosition.split(', ')[i]; // get resolved elem width and height let resolvedWidth = computedStyle.width.split(', ')[i]; let resolvedHeight = computedStyle.height.split(', ')[i]; let elemWidth = parseInt(resolvedWidth.replace('px',''),10); let elemHeight = parseInt(resolvedHeight.replace('px',''),10); // get resolved border sizes let borderLeft = !computedStyle.borderLeftWidth ? 0 : parseInt(computedStyle.borderLeftWidth.replace('px',''),10); let borderTop = !computedStyle.borderTopWidth ? 0 : parseInt(computedStyle.borderTopWidth.replace('px',''),10); let borderRight = !computedStyle.borderRightWidth ? 0 : parseInt(computedStyle.borderRightWidth.replace('px',''),10); let borderBottom = !computedStyle.borderBottomWidth ? 0 : parseInt(computedStyle.borderBottomWidth.replace('px',''),10); // get resolved padding sizes let paddingLeft = !computedStyle.paddingLeft ? 0 : parseInt(computedStyle.paddingLeft.replace('px',''),10); let paddingTop = !computedStyle.paddingTop ? 0 : parseInt(computedStyle.paddingTop.replace('px',''),10); let paddingRight = !computedStyle.paddingRight ? 0 : parseInt(computedStyle.paddingRight.replace('px',''),10); let paddingBottom = !computedStyle.paddingBottom ? 0 : parseInt(computedStyle.paddingBottom.replace('px',''),10); // derive actual bounding box, which could be different from content box due to origin let byOriginLeft; let byOriginTop; let byOriginRight; let byOriginBottom; if (resolvedOrigin === 'content-box') { byOriginLeft = paddingLeft; byOriginTop = paddingTop; byOriginRight = paddingLeft+elemWidth; byOriginBottom = paddingTop+elemHeight; } else if (resolvedOrigin === 'padding-box') { byOriginLeft = 0; byOriginTop = 0; byOriginRight = paddingLeft+elemWidth+paddingRight; byOriginBottom = paddingTop+elemHeight+paddingBottom; } else if (resolvedOrigin === 'border-box') { byOriginLeft = -borderLeft; byOriginTop = -borderTop; byOriginRight = paddingLeft+elemWidth+paddingRight+borderRight; byOriginBottom = paddingTop+elemHeight+paddingBottom+borderBottom; } else { throw 'unsupported origin: '+resolvedOrigin; } // end if let byOriginWidth = byOriginRight-byOriginLeft; let byOriginHeight = byOriginBottom-byOriginTop; // create image object to get original image's size let image = new Image(); image.src = computedStyle.backgroundImage.split(', ')[i].replace(/url\((['"])?(.*?)\1\)/gi,'$2').replace(/\\(.)/,'$1'); // note: don't have to decode URI to assign, but must manually strip backslash escape codes let imageWidth = image.width; let imageHeight = image.height; // get original image y/x ratio, and elem y/x ratio let imageRatio = imageHeight/imageWidth; let elemRatio = elemHeight/elemWidth; // compute initial idea of the result based on origin and size; will apply position afterward if (resolvedSize === 'cover') { if (elemRatio > imageRatio) { // more height in elem than image => flush height, surplus width res = { 'left':byOriginLeft, 'top':byOriginTop, 'right':byOriginLeft+byOriginHeight/imageRatio, 'bottom':byOriginBottom }; } else { // more width in elem than image => flush width, surplus height res = { 'left':byOriginLeft, 'top':byOriginTop, 'right':byOriginRight, 'bottom':byOriginTop+byOriginWidth*imageRatio }; } // end if } else if (resolvedSize === 'contain') { if (elemRatio > imageRatio) { // more height in elem than image => flush width, deficient height res = { 'left':byOriginLeft, 'top':byOriginTop, 'right':byOriginRight, 'bottom':byOriginTop+byOriginWidth*imageRatio }; } else { // more width in elem than image => flush height, deficient width res = { 'left':byOriginLeft, 'top':byOriginTop, 'right':byOriginLeft+byOriginHeight/imageRatio, 'bottom':byOriginBottom }; } // end if } else { // parse size into width and height values let resolvedSizeSplit = resolvedSize.split(' '); let resolvedSizeWidth = resolvedSizeSplit[0]; let resolvedSizeHeight = resolvedSizeSplit.length >= 2 ? resolvedSizeSplit[1] : 'auto'; // resolved always has both in FF, but not IE // resolve to integer width and height values let sizeWidth; let sizeHeight; if (resolvedSizeWidth === 'auto' && resolvedSizeHeight === 'auto') { // double auto uses original img size sizeWidth = imageWidth; sizeHeight = imageHeight; } else { // if not double auto, calculate non-auto first, then resolve auto if exists if (resolvedSizeWidth !== 'auto') { if (resolvedSizeWidth.indexOf('%') > -1) { let sizeWidthPct = parseInt(resolvedSizeWidth.replace('%','')); sizeWidth = sizeWidthPct*byOriginWidth/100; } else { sizeWidth = parseInt(resolvedSizeWidth.replace('px','')); } // end if } // end if if (resolvedSizeHeight !== 'auto') { if (resolvedSizeHeight.indexOf('%') > -1) { let sizeHeightPct = parseInt(resolvedSizeHeight.replace('%','')); sizeHeight = sizeHeightPct*byOriginHeight/100; } else { sizeHeight = parseInt(resolvedSizeHeight.replace('px','')); } // end if } // end if // resolve dependent auto if (resolvedSizeWidth === 'auto') sizeWidth = sizeHeight/imageRatio; if (resolvedSizeHeight === 'auto') sizeHeight = sizeWidth*imageRatio; } // end if res = { 'left':byOriginLeft, 'top':byOriginTop, 'right':byOriginLeft+sizeWidth, 'bottom':byOriginTop+sizeHeight }; } // end if // get absolute pos value in pixels let resolvedPosSplit = resolvedPos.split(' '); let resolvedPosLeft = resolvedPosSplit[0]; let resolvedPosTop = resolvedPosSplit.length >= 2 ? resolvedPosSplit[1] : '50%'; // resolved always has both in FF, but not IE let posLeft; let isPosLeftPct; if (resolvedPosLeft.indexOf('%') > -1) { isPosLeftPct = true; let posLeftPct = parseInt(resolvedPosLeft.replace('%','')); posLeft = posLeftPct*(byOriginWidth-(res.right-res.left))/100; } else { isPosLeftPct = false; posLeft = parseInt(resolvedPosLeft.replace('px','')); } // end if let posTop; let isPosTopPct; if (resolvedPosTop.indexOf('%') > -1) { isPosTopPct = true; let posTopPct = parseInt(resolvedPosTop.replace('%','')); posTop = posTopPct*(byOriginHeight-(res.bottom-res.top))/100; } else { isPosTopPct = false; posTop = parseInt(resolvedPosTop.replace('px','')); } // end if // apply pos // tricky: must *not* apply pct pos adjustment to flush dimension for cover and contain if (!( isPosLeftPct && ( resolvedSize === 'cover' && elemRatio < imageRatio || resolvedSize === 'contain' && elemRatio > imageRatio ) )) { res.left += posLeft; res.right += posLeft; } // end if if (!( isPosTopPct && ( resolvedSize === 'cover' && elemRatio > imageRatio || resolvedSize === 'contain' && elemRatio < imageRatio ) )) { res.top += posTop; res.bottom += posTop; } // end if return res; }; // global constants var SMALLERIMAGE_LEFTPCT = [67,90,15]; var SMALLERIMAGE_TOPPCT = [64,10,70]; var MULT = 1.2; // global variables var g_pctIndex = 0; // state change functions window.updateSmallerImage = function() { let leftPct = SMALLERIMAGE_LEFTPCT[g_pctIndex]; let topPct = SMALLERIMAGE_TOPPCT[g_pctIndex]; // get the smaller image element and its containing element let smallerImageElem = document.getElementById('smallerImage'); let containingElem = smallerImageElem.parentElement; // get the bounding box of the background image in the containing element let bgbox = getBackgroundImageBox(containingElem); // get the computed style of the smaller image element let computedStyle = getComputedStyle(smallerImageElem); // move the smaller image to the required position // note: subtracting half the width and height for centering, but could do it differently // must use computedStyle for the subtraction in case the inline style attribute has not been set yet smallerImageElem.style.left = (bgbox.left + (bgbox.right-bgbox.left)*leftPct/100 - computedStyle.width.replace('px','')/2)+'px'; smallerImageElem.style.top = (bgbox.top + (bgbox.bottom-bgbox.top)*topPct/100 - computedStyle.height.replace('px','')/2)+'px'; // ensure the smaller image is displayed smallerImageElem.style.display = 'block'; }; window.multContainingElementDim = function(prop,mult) { let containingElem = document.getElementById('containingElement'); let computedStyle = getComputedStyle(containingElem); containingElem.style[prop] = (computedStyle[prop].replace('px','')*mult)+'px'; }; window.advanceSmallerIndexPctIndex = function() { g_pctIndex = (g_pctIndex+1)%SMALLERIMAGE_LEFTPCT.length; let indexButton = document.getElementById('indexButton'); indexButton.value = '['+g_pctIndex+']'; updateSmallerImage(); }; window.onload = function() { updateSmallerImage(); let containingElem = document.getElementById('containingElement'); containingElem.addEventListener('transitionend',updateSmallerImage,false); };返回的值对于那些发生故障的情况而言是不正确的。我没有弄清楚失败的原因或是否有可能的解决方法,所以请注意这个问题。

话虽如此,对于您的特定CSS,一切似乎都在起作用。主要的实现功能以及整个演示似乎都基于我在Firefox,Chrome和Internet Explorer中的测试工作。

答案 3 :(得分:0)

您可以尝试 margin 百分比而不是像素

答案 4 :(得分:-1)

你可以试试位置:修复css风格。无论您最大化还是最小化屏幕,这都将修复您的图片。

style{
    position:fixed;
    margin-top:280px;
    margin-left:700px;
}

希望它会有所帮助。