2016-08-04 103 views
1

我有一个HTML页面,我已经把背景图像放入正文css中。如何让我的图像在HTML页面中相对于背景图像保持固定位置?

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" /> 

,当我去全屏幕或最小化window.The背景图像是固定的,但新的图像图像的位置变化转变。我该如何解决这个问题?

+0

图像应该保持与背景图像上相对位置的相对位置吗? – Aaron

+0

你需要使用剩余百分比,顶部和变换属性。 – Aaron

+0

@Ritesh这样的事情? https://jsfiddle.net/LeoLion/dd8k66yj/ –

回答

-1

你可以试试position:fixed css style。无论您最大化还是最小化屏幕,这都会修复您的照片。

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

希望它会有所帮助。

+0

由此,如果用户将调整窗口大小,他将无法看到图像..什么是解决方案! –

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

使用上边和左边你可以设置的位置水平和垂直图像的话,就不会移动,因为它是在像素那个位置。

0

如果你想要一个较小的图像覆盖一个非重复的背景图像相对于背景图像永久固定的位置,那么你可能只需在图像编辑应用程序中打开背景图像,复制并粘贴将较小的图像放入画布中,按您想要的方式进行定位,然后将其保存为新的图像文件。然后,您可以使用该新图像文件作为背景图像。

当然,如果您需要在页面生命周期中对较小的图像应用动态更改(如过渡或对其CSS的动态更改),则此功能无效。但否则,我会认为这将是最好的解决方案。


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

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


CSS属性值序列

明白,CSS属性值经历一个复杂的计算处理,其可以结合的浏览器的默认值,CSS源声明,特异性,继承,相互依存的属性的相互作用,这是非常重要的依赖于版图的相对值的分辨率,以及某些情况下的舍入/近似值。

我们可以通过这个计算序列中,列出了可以发挥作用价值观的不同阶段总结这一过程:

initial value作为浏览器默认的根元素。还用作非继承属性的非根元素的浏览器默认值(继承属性可以继承根或父级的初始值(如果未在其谱系或自定义风格中进行超集)。

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

specified value如果给定源值,否则为继承的值(用于继承的属性)或初始值(用于非继承的属性)。请注意,源值本身可能被设置为文字空白字inheritinitial

computed value从指定的值解析inheritinitial获得更多的具体值,再加上额外的应用转换,如跨度position:absolute更改为display:block推导。预先布局。

used value完成所有计算后的最终值。后布局。解决自动和绝对像素值的百分比。

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


令人困惑的是,在getComputedStyle()功能确实回报计算的值,而是返回一些所谓的解析值:

resolved value通过getComputedStyle()返回。 (1)对于line-height,它始终是使用的值。 (2)否则,对于使用display:none的元素/伪元素(a),或(b)该属性永远不适用的元素/伪元素(a),或(c)对于过度限制的bottomleftrighttop,总是计算出的值(因为在大多数情况下,它们的布局不能确定)。 (3)否则,对于bottom,left,right,top,width,height,paddingmargin属性,它总是使用的值。 (4)否则,它总是计算值。


的问题

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

当然,上述三种CSS属性的值的排列组合会固定相对于其包含元素的背景图像,并且允许我们静态地确定将较小图像置于无论有没有其他细节,都需要相对于背景图像的位置。但对于你的情况,因为你有background-size:containbackground-position:center center,这里不适用。

在一般情况下,我们需要根据包含元素的上述三个CSS属性以及包含元素的其他CSS属性(特别是padding和,对于案例动态地计算背景图像的位置background-origin:border-box,边框),原始图像大小和包含的元素大小。


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

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

为什么getComputedStyle().backgroundPosition不能直接

使用你可能会认为,我们应该能够得到背景图像的最终绝对位置getComputedStyle().backgroundPosition包含的元素上运行。这是不正确的。原因是我们需要最后的使用的值为的背景图像位置。如前所述,getComputedStyle()仅为少数CSS属性返回已使用的值,即使只在某些情况下也是如此,而backgroundPosition不在其中。另外,正如前面所解释的,我们还需要背景图像的右下角,而backgroundPosition只会返回左上角。我们也可以通过得到getComputedStyle().backgroundSize来得到右下角,但是backgroundSize遭受与backgroundPosition相同的限制,因为它只会给我们计算出的值而不是用过的值。

浏览器API解决方案

我简单搜索的结果可以用来获得上述两个CSS属性的使用值在浏览器的API的规定,但不幸的是有没有出现任何。请参阅Is there a cross-browser method of getting the used css values of all properties of all elements?,它不能令人满意地回答该问题,并且没有一个会话似乎知道解析值的概念,并且getComputedStyle()函数在大多数情况下返回计算值。

现有的JavaScript解决方案

我做了一些搜索,看是否有人已经想出了一个JavaScript的解决这个问题。最接近的似乎是Get final size of background image中给出的JavaScript函数。不幸的是,该功能仅计算背景图像的大小,所以它是不够的。 (我认为它不适用于所有情况,但我没有证实这一点。)

解决方案

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

回想一下,getComputedStyle().backgroundPositiongetComputedStyle.backgroundSize不给我们这两个属性的最终使用值;他们只给我们计算价值。但是这些计算值为我们提供了一个必要的出发点,以手动计算符合标准的浏览器在布置包含元素及其背景图像时将使用的值。因此,在我的函数中,我得到了上述两个计算值以及getComputedStyle().backgroundOrigin,以及填充和边框CSS值,并继续计算适合当前值的背景图像的边界框。我们必须处理backgroundOrigin的所有三个可能值,backgroundPosition的百分比和绝对像素值以及backgroundSize的百分比绝对像素值autocovercontain

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

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); 
 
};
#containingElement { 
 
    position:relative; 
 
    background-color:#202020; 
 
    background-image:url('http://media.zenfs.com/en_US/News/BGR_News/planet-earth.jpg'); 
 
    background-repeat:no-repeat; 
 
    background-size:contain; 
 
    background-position:center center; 
 
    width:500px; 
 
    height:400px; 
 
    transition: 
 
    width 0.3s ease-in-out, 
 
    height 0.3s ease-in-out; 
 
} 
 

 
#smallerImage { 
 
    position:absolute; 
 
    width:80px; 
 
    height:32px; 
 
    display:none; /* will show after positioning */ 
 
    transition: 
 
    left 0.3s ease-in-out, 
 
    top 0.3s ease-in-out; 
 
} 
 

 
#controls { 
 
    position:fixed; 
 
    left:0; 
 
    top:0; 
 
    z-index:1; 
 
}
<div id="controls"> 
 
    <input type="button" value="▲" onclick="multContainingElementDim('height',1/MULT);"/> 
 
    <input type="button" value="◄" onclick="multContainingElementDim('width',1/MULT);"/> 
 
    <input type="button" value="►" onclick="multContainingElementDim('width',MULT);"/> 
 
    <input type="button" value="▼" onclick="multContainingElementDim('height',MULT);"/> 
 
    &nbsp; 
 
    <input id="indexButton" type="button" value="[0]" onclick="advanceSmallerIndexPctIndex();"/> 
 
</div> 
 

 
<div id="containingElement"> 
 
    <img id="smallerImage" src="http://freepngimages.com/wp-content/uploads/2015/12/international-space-station-transparent-background.png"/> 
 
</div>

测试

我在Firefox非常彻底的测试主要实现功能getBackgroundImageBox(),试图为上述三个属性810个不同的排列,它完美地工作为他们所有。我在Chrome和Internet Explorer中进行了更少的彻底检查。所有检查均在Chrome中运行,但不幸的是,Internet Explorer在两种情况下都失败了,这似乎是因为它为getComputedStyle().backgroundSize返回的值对于那些失败的案例而言是不正确的。我还没有找出失败的原因,或者如果有可能的解决方法,请注意这个问题。

这就是说,对于你的特定的CSS,一切似乎工作。主要实现功能以及整个演示似乎都基于我在所有Firefox,Chrome和Internet Explorer中的测试而工作。

+0

我需要应用动态更改。你有什么解决方案吗? –

+0

你需要申请什么样的动态变化? – bgoldst

+0

我需要将背景图像上方的图像动画到背景图像上的新位置。 –

1

即使在调整大小模式下,也要修正图像的位置:相对于父母(在您的情况下,身体标记)。所以简单给position;relative身体标记,你就完成了。

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; 
} 
+0

我以为一样,但它不工作。问题是背景图像重新调整大小,因为它本质上是有反应的。现在,由于重新调整大小,原始图像相对于身体标记而不是背景图像发生变化。 –

+0

这是我的原始css代码: - html, body { height:100%; } body { background-image:url('Images/BGimage.png'); background-repeat:no-repeat; background-size:contains; background-position:center center; /* background-attachment:fixed; */ } –

+0

这是我的原始css代码: - –

0

你可以尝试保证金百分比,而不是像素

+0

试过了,不起作用!!!!! –

+0

保证金比例导致相同类型的问题。 –