Keep div overlay relative to background image regardless of window size

I want to overlay some text on top of a background image with background-size: cover

.

The problem is how to keep the overlay div in the same position relative to the background image regardless of the window size?

There is a fiddle here: http://jsfiddle.net/resting/2yr0b6v7/

So, I want to place the word eye

above the cat's eye, regardless of the size of the window.

CSS or JS solutions are appreciated.

+3


source to share


3 answers


EDIT: Added js alternative

I was convinced that it could be done with css and almost gave up, but then I remembered the new (ish) units of css vh and vw ....

jsfiddle

CSS

html, body{
    height: 100%;
    width: 100%;
}
.cat {
    height: 100%;
    width: 100%;
    position: relative;
    background:url(http://placekitten.com/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 about 375, 190, and since the image is centered, we also need to know how far from the center, so 25, 10. Since the image covers, the image will resize depending on whether the ratio is the aspect ratio of the viewport is larger or smaller than the aspect ratio of the background image. Knowing this, we can use media queries to place text.



The image is 2: 1, so when the aspect ratio of the viewport is> 2: 1, we know that the width of the image is the same as the width of the viewport, so the left position <p>

should always be 46.867% (375/800). The bottom position will be more difficult because the image extends beyond the top and bottom of the viewport. We know the image is centered, so move it <p>

to the middle first and then raise it 2.5% (10/400) of the image height. We do not know the height of the image, but we know the aspect ratio of the image to the width of the image equal to the width of the viewport, so 2.5% of the height = 1.25% of the width. Therefore, we need to move the bottom 1.25% of the width, which we can do by setting margin-bottom:1.25vw

. By the way, we can do it withoutvw

in this case, because the padding is always calculated relative to the width, so we could set padding-bottom:1.25%

, however, it won't work in the next case where you have to put the left relative to the height.

The case where the aspect ratio is <2: 1 is similar. Image height is the height of the viewport, so the bottom position should always be 52.5% (210/400) and the left calculation is similar to the one above. Move it to the center, then set it back to 3.125% (25/800) of the image width, which is 6.25% of the image height, which is equal to the height of the viewport, so margin-left:-6.25vh

.

Hope this is correct and helps you!

Alternative to JS

jsfiddle

Here's an alternative that uses js. It uses some features like forEach and bind which can cause problems depending on how old the browser you need to work, but they are easily replaceable. With js you can calculate the scaled dimensions of the bg image directly, which makes 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);

      

+4


source


According to how you set the position and size of the background image:

background-position:center center;
background-size:cover;

      

the center of the background image should still be in the center of the screen - this is useful as a constant, so try doing the same with your p.place-on-eye

.place-on-eye {
    ...
    top: 50%;
    left: 50%;
}

      

Right now, the top left corner is in the center of the screen, if you add width and height properties as well, you can actually center the elements in the center of the screen. So here:



.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, the center p.place-on-eye

is in the exact center of your screen, just like the center of your background image. To get this over the cat's eye, only offset the left and top edges as needed.

so something like margin:-27px 0 0 -60px;

should do it.

fiddle

0


source


I made a fiddle borrowing principles from two answers. The black dot must overlap at the end of the line. But this solution deviates slightly from the real place in certain proportions.

Can someone 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();

});

      

0


source







All Articles