Domanda

I have a background image which changes size to the windows size, and I need to position an element on it so that it is always in the same place relative to the background image.

HOW!?

CSS

background:url("http://placehold.it/100x100") no-repeat center center fixed;
-webkit-background-size:"cover";
-moz-background-size:"cover";
-o-background-size:"cover";
background-size:"cover";

The background image covers the entire background and changes size with the window but keeps proportions by having some overlay.

EDIT - 2016

My solution to this with pure CSS is to position the element in the middle and then offset it correctly using calc function. And then to resize it accordingly i use the vmin value:

$offset-top: ...;
$offset-left: ...;

.element {
  top: 50%;
  left: 50%;
  transform: translate(calc(-50% + #{$offset-top}), calc(-50% + #{$offset-top}));
  width: 50vim; 
  height: 50vim;
}
È stato utile?

Soluzione

What you are asking for is not a trivial thing at all, it basically involves figuring out how background-size:cover works and then positioning your element using JavaScript. Due to the nature of background-size:cover how the image can flow out of the x-axis or y-axis this cannot be done with CSS.

Here is my solution to the problem, on load and resize it calculates the scale of the image and the x or y offset and draws the pointer at the relevant location.

jsFiddle (red dot in Google's red 'o')

enter image description here

HTML

<div id="pointer"></div>

CSS

body {
    background:url(https://www.google.com.au/images/srpr/logo4w.png) no-repeat center center fixed;
    -webkit-background-size:cover;
    -moz-background-size:cover;
    -o-background-size:cover;
    background-size:cover;
}

#pointer {
    margin-left:-10px;
    margin-top:-10px;
    width:20px;
    height:20px;
    background-color:#F00;
    position:fixed;
}

JS

var image = { width: 550, height: 190 };
var target = { x: 184, y: 88 };

var pointer = $('#pointer');

$(document).ready(updatePointer);
$(window).resize(updatePointer);

function updatePointer() {
    var windowWidth = $(window).width();
    var windowHeight = $(window).height();

    // Get largest dimension increase
    var xScale = windowWidth / image.width;
    var yScale = windowHeight / image.height;
    var scale;
    var yOffset = 0;
    var xOffset = 0;

    if (xScale > yScale) {
        // The image fits perfectly in x axis, stretched in y
        scale = xScale;
        yOffset = (windowHeight - (image.height * scale)) / 2;
    } else {
        // The image fits perfectly in y axis, stretched in x
        scale = yScale;
        xOffset = (windowWidth - (image.width * scale)) / 2;
    }

    pointer.css('top', (target.y) * scale + yOffset);
    pointer.css('left', (target.x) * scale + xOffset);
}

Altri suggerimenti

I'm going to have to guess on your markup, but presuming that you have some container for the background image and your other image that needs to also be centered is inside it, like so:

<div class="holdBGimg">
    <img src="image.jpg">
</div>

you could do something like:

.holdBGimg {
    position: relative;
}
.holdBGimg img {
    width: 100px;
    height: 100px;
    position: absolute;
    top: 50%;
    left: 50%;
    margin-top: -50px;
    margin-left: -50px;
}

where you are compensating for the offset of the height and width by taking away half of that measurement from the relative margins.

If you are looking to scale it, the solution could be more along the lines of:

.holdBGimg {
    position: relative;
}
.holdBGimg img {
    width: 20%;
    height: 20%;
    position: absolute;
    top: 40%;
    left: 40%;
}

This is all depending on the size of the image you are trying to center.

I would create an array of positions for the props you are going to put over the background. Use the x and y positions within the full sized background image...

var propPositions = [
  { name: "StoveBurner1", x: 23, y: 566 },
  { name: "StoveBurner2", x: 676, y: 456 },
  { name: "TableChair1", x: 765, y: 35 },
  ...
];

You will need to also hold onto the size of the background at full size so you can use it on size change to calculate a scaling factor.

var fullBackgroundSize = { width: 1920, height: 1080 };

When the image size changes, calculate the scaling factor, and then scale the x and y positions for every element in the array...

for (var i = 0; i < propPositions.length; i++)
{
    propPositions[i].x *= scalingFactor;
    propPositions[i].y *= scalingFactor;
}

This will allow you to precisely position all of your props regardless of image size.

This also allows you to look up positions by name, which would enable you to do stuff like...

placeObject(pot1, "StoveBurner1");
placeObject(pot2, "StoveBurner2");
placeObject(SittingPerson, "TableChair1");

That way, the only code which calculates positions and moves objects to them is in one small function.

Add a centering container:

#container {
    position: fixed;
    width: 0;
    height: 0;
    top: 50%;
    left: 50%;
    overflow: visible;
}

And then add position: relative elements inside.

Relative (scalable, responsive, insert buzz word here) units (%).

Responsive design takes A LOT more work. You'd have to test where the regions of the image you want to align with are in accordance to the window size, and then match those values to your element placement in accordance to the window size. But cover is going off of the aspect ratio of the image itself and either matching the width or the height. So depending on the aspect ratio of the window, it's going to mess up your layout.

You could try using jQuery and javascript to get the dimensions of the window, jquery then matches the dimension of your image to that and changes the dimensions of your elements. Lots of coding work, tough on page loads, but we must make sacrifices, mustn't we?

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top