admin管理员组文章数量:1293503
I want to overlay some text over a background image with background-size: cover
.
Problem here is how do I keep the overlay div at the same position, relative to the background image, regardless of the window's size?
Here's a fiddle to play around: /
So I want to position the word eye
over the eye of the cat, regardless of window size.
CSS or JS solutions are both weled.
I want to overlay some text over a background image with background-size: cover
.
Problem here is how do I keep the overlay div at the same position, relative to the background image, regardless of the window's size?
Here's a fiddle to play around: http://jsfiddle/resting/2yr0b6v7/
So I want to position the word eye
over the eye of the cat, regardless of window size.
CSS or JS solutions are both weled.
Share Improve this question asked Nov 12, 2014 at 2:15 restingresting 17.5k17 gold badges63 silver badges90 bronze badges 3-
it will move a little but a quick way that would keep it within that area is using
%
rather thanpx
to give it its position – akaBase Commented Nov 12, 2014 at 2:24 -
Have tried
%
but it actually moves a lot out of position. Maybe its impossible to have a div overlay relative to a background image. Seems to me its always relative to the window. – resting Commented Nov 12, 2014 at 2:30 - jsfiddle/f4yovb09/1/embedded/result check that out it stays fairly close to the eye on resizing using the % like i mentioned? – akaBase Commented Nov 12, 2014 at 2:41
3 Answers
Reset to default 9EDIT: Added js alternative
I was convinced that this could be done with css and almost gave up, but then I remembered the new(ish) css units vh and vw....
jsfiddle
CSS
html, body{
height: 100%;
width: 100%;
}
.cat {
height: 100%;
width: 100%;
position: relative;
background:url(http://placekitten./g/800/400) no-repeat center center / cover;
}
.place-on-eye {
position: absolute;
color: #fff;
margin:0;
}
@media (min-aspect-ratio: 2/1) {
.place-on-eye {
bottom: 50%;
left: 46.875%;
margin-bottom: 1.25vw;
}
}
@media (max-aspect-ratio: 2/1) {
.place-on-eye {
bottom: 52.5%;
left: 50%;
margin-left: -6.25vh;
}
}
Explanation
So the left eye is at approx 375, 190, and since the image is centered, we will also want to know how far off the center it is, so 25, 10. Since the image is covering, the size of the image will change based on whether the aspect ratio of the viewport is greater or less than the aspect ratio of the background image. Knowing this, we can use media queries to position the text.
The image is 2:1, so when the viewport aspect ratio is > 2:1, we know that the width of the image is the width of the viewport, so the left position of the <p>
should always be 46.867% (375/800). The bottom position is going to be more difficult because the image extends beyond the viewport top and bottom. We know that the image is centered, so first move the <p>
to the middle, then push it up by 2.5% (10/400) of the height of the image. We don't know the height of the image, but we do know the image aspect ratio and that the width of the image is equal to the width of the viewport, so 2.5% of the height = 1.25% width. So we have to move the bottom up by 1.25% width, which we can do by setting margin-bottom:1.25vw
. Incidentally, we can do this without vw
in this case because padding is always calculated relative to the width, so we could have set padding-bottom:1.25%
, however this won't work in the next case where you have to position the left relative to the height.
The case when the aspect ratio is < 2:1 is analogous. The height of the image is the height of the viewport, so the bottom position should always be 52.5% (210/400) and the left is calculated similar to above. Move it over to center, then back it up by 3.125% (25/800) the width of the image, which is equal to 6.25% the height of the image, which is equal to the viewport height, so margin-left:-6.25vh
.
Hopefully this is correct and helps you out!
JS Alternative
jsfiddle
Here's an alternative that uses js. It uses some features like forEach and bind that might cause problems depending on how old a browser you need it to work on, but they are easily replaceable. With js you can directly calculate the scaled dimensions of the bg image which makes the positioning easier. Not the most elegant code, but here goes:
//elem: element that has the bg image
//features: array of features to mark on the image
//bgWidth: intrinsic width of background image
//bgHeight: intrinsic height of background image
function FeatureImage(elem, features, bgWidth, bgHeight) {
this.ratio = bgWidth / bgHeight; //aspect ratio of bg image
this.element = elem;
this.features = features;
var feature, p;
for (var i = 0; i < features.length; i++) {
feature = features[i];
feature.left = feature.x / bgWidth; //percent from the left edge of bg image the feature resides
feature.bottom = (bgHeight - feature.y) / bgHeight; //percent from bottom edge of bg image that feature resides
feature.p = this.createMarker(feature.name);
}
window.addEventListener("resize", this.setFeaturePositions.bind(this));
this.setFeaturePositions(); //initialize the <p> positions
}
FeatureImage.prototype.createMarker = function(name) {
var p = document.createElement("p"); //the <p> that acts as the feature marker
p.className = "featureTag";
p.innerHTML = name;
this.element.appendChild(p);
return p
}
FeatureImage.prototype.setFeaturePositions = function () {
var eratio = this.element.clientWidth / this.element.clientHeight; //calc the current container aspect ratio
if (eratio > this.ratio) { // width of scaled bg image is equal to width of container
this.scaledHeight = this.element.clientWidth / this.ratio; // pre calc the scaled height of bg image
this.scaledDY = (this.scaledHeight - this.element.clientHeight) / 2; // pre calc the amount of the image that is outside the bottom of the container
this.features.forEach(this.setWide, this); // set the position of each feature marker
}
else { // height of scaled bg image is equal to height of container
this.scaledWidth = this.element.clientHeight * this.ratio; // pre calc the scaled width of bg image
this.scaledDX = (this.scaledWidth - this.element.clientWidth) / 2; // pre calc the amount of the image that is outside the left of the container
this.features.forEach(this.setTall, this); // set the position of each feature marker
}
}
FeatureImage.prototype.setWide = function (feature) {
feature.p.style.left = feature.left * this.element.clientWidth + "px";
feature.p.style.bottom = this.scaledHeight * feature.bottom - this.scaledDY + "px"; // calc the pixels above the bottom edge of the image - the amount below the container
}
FeatureImage.prototype.setTall = function (feature) {
feature.p.style.bottom = feature.bottom * this.element.clientHeight + "px";
feature.p.style.left = this.scaledWidth * feature.left - this.scaledDX + "px"; // calc the pixels to the right of the left edge of image - the amount left of the container
}
var features = [
{
x: 375,
y: 190,
name: "right eye"
},
{
x: 495,
y: 175,
name: "left eye"
},
{
x: 445,
y: 255,
name: "nose"
},
{
x: 260,
y: 45,
name: "right ear"
},
{
x: 540,
y: 20,
name: "left ear"
}
];
var x = new FeatureImage(document.getElementsByClassName("cat")[0], features, 800, 400);
I have done a fiddle borrowing the principles from the 2 answers. Black dot should overlay at the end of the line. But this solution drifts from actual spot a little in certain ratios.
Maybe someone can improve it?
JS:
$(function() {
function position_spot() {
w = $(window).width();
h = $(window).height();
wR = w/h;
// Point to place overlay based on 1397x1300 size
mT = 293;
mL = -195;
imgW = 1397;
imgH = 1300;
imgR = imgW/imgH;
tR = mT / imgH; // Top ratio
lR = mL / imgW; // Left ratio
wWr = w / imgW; // window width ratio to image
wHr = h / imgH; // window height ratio to image
if (wR > imgR) {
// backgroundimage size
h = imgH * wWr;
w = imgW * wWr;
} else {
h = imgH * wHr;
w = imgW * wHr;
}
$('.overlay-spot').css({
'margin-top': h * tR,
'margin-left': w * lR
});
}
$(window).resize(function() {
position_spot();
});
position_spot();
});
According to how you set your background image position and size:
background-position:center center;
background-size:cover;
the center of background image should still be in the center of your screen - that es in handy as a constant, so just try to do the same with your p.place-on-eye
.place-on-eye {
...
top: 50%;
left: 50%;
}
Right now paragraph's left top corner is in the center of your screen, if you also add width and height properties you can actually pint elements center into the screen's center. So it's like:
.place-on-eye {
...
width:50px;
height:50px;
text-align:center /* to make sure the text is center according to elements width */
top: 50%;
left: 50%;
margin:-25px 0 0 -25px;
}
So now the center of p.place-on-eye
is in the exact center of your screen, just like the center of your background image. To get it over the cat's eye just offset the left and top margin as needed.
so something like margin:-27px 0 0 -60px;
should do it.
fiddle
本文标签: javascriptKeep div overlay relative to background image regardless of window sizeStack Overflow
版权声明:本文标题:javascript - Keep div overlay relative to background image regardless of window size - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741578704a2386442.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论