Position element over background image. But the BG img changes size with the window. CSS
Asked Answered
K

5

17

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;
}
Keewatin answered 5/4, 2013 at 14:39 Comment(4)
have you tried positioning it with javascript/jquery?Kwa
If I am reading this right, why not absoute position the element relative to body? If the bg img takes up the entire viewport then absolute positioning relative to the body should do the trick.Prenomen
On which element is your bg image attached to? body, some container div? Can you post some of the HTML that you are working with?Albertinealbertite
growingwiththeweb.com/2013/04/…Repugn
L
34

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);
}
Latonia answered 5/4, 2013 at 15:43 Comment(4)
+1 for taking the time to build an example. I just kind of giggled and pointed off in to the distance...Prato
For those who need it, I've altered the code to use multiple points. jsfiddle.net/dvksg9vkSisile
growingwiththeweb.com/2013/04/…Repugn
@MicFin by using position:absolute and manipulating the left, top, width and height styles of the img as well.Latonia
I
1

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.

Iguana answered 5/4, 2013 at 15:12 Comment(5)
I think the OP has the background image covered (he wasn't too clear on that, but his code suggests it). What he wants is for the content to follow the background image (e.g. stay in the same place relative to the background)Dactylology
I'm using an img but the element being refered to could be anything. The markup could be <div class="holdBGimg"><div>THis is my content</div></div> and have the same effect. The point is constraining the height, width, and positioning.Iguana
OP: I have a background image which changes size to the windows size It's probably more like body { background: //blahblahblah; } rather than an BG container.Prato
Same difference, just change the markup: <body class="holdBGimg"><div class="shiftable">This is the content that is being shifted</div></body> and then same markup with ".holdBGimg img" changed to "body div.shiftable"Iguana
@ElizabethFuller Sure, was confused about your useage of img.Dactylology
P
1

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?

Prato answered 5/4, 2013 at 15:44 Comment(0)
T
1

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.

Twombly answered 3/11, 2017 at 6:40 Comment(0)
D
0

Add a centering container:

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

And then add position: relative elements inside.

Dactylology answered 5/4, 2013 at 15:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.