
It seems like such a simple request: “I need the whole image to show in the background.”
In this case, it wasn’t just for aesthetic reasons: the client had licensed that image under terms that said it had to be used as-is, without cropping or alterations. It was a large image, 1600 pixels wide by 2200 pixels tall.
The width was not really the issue in this case: it was the height. While this site has some long pages, the home page and many others are a lot less than 2200 pixels tall, even when the browser is set to 1600 pixels wide.
Normally, when you want a responsive background image, you use either background-size: cover
or background-size: contain
.
Neither worked in this case. With background-size: cover
, the image filled the width of the screen at any size, but the bottom was cut off.
With background-size: contain
, on the other hand, the image would be too narrow to show up on pages without much content—of which there were many in the early stages of building the site. Plus, the size of the image would vary with the amount of content on the page—awkward. And you have to have a much bigger screen than mine to set your browser height at 2200 pixels.
CSS for background images is designed to fit the background to the container. What I needed to do was fit the container to the background image.
After various unsuccessful experiments, I concluded that I couldn’t do what I needed to do with a background image. What I had to do was create a <div>
and put the image inside it. Then the image would resize automatically the way images within the content do.
Since I’m working with Genesis, I couldn’t just go in and add a few lines of HTML to my template file. I had to create the new <div>
by adding some code to functions.php
:
//* Add the background wrapper */ function open_body_background_wrap() { echo '<div id="img-background" class="wrap">'; echo '<img class="body-background" src="'. get_bloginfo( 'stylesheet_directory' ) .'/images/site-background.jpg" />'; } add_action('genesis_before', 'open_body_background_wrap',1); function close_body_background_wrap() { echo '</div><!-- end .wrap -->'; } add_action('genesis_after', 'close_body_background_wrap',15);
That results in the following HTML output:
<body class="custom-background"> <div id="img-background" class="wrap"> <img class="body-background" src="/images/site-background.jpg" /> <div class="before-header" class="widget-area"></div> <div class="site-container"> ... (The rest of the site content) </div> //site-container </div> //wrap </body>
That added the image and scaled it properly, but there was one small problem: all of the site content was rendered below the image rather than in front of it.
My initial solution to positioning the content (which only required positioning the first element, div.before-header
) was to use a negative margin on said div
. That worked fine for the desktop, but it played merry hell with media queries.
I realized that there had to be a better solution than trying to calculate all of the possible negative margins at different screen sizes.
I looked at jquery.background-fit, which seemed like a promising way to go back to using a real background image, but was still trying to fit the image to the screen rather than the other way around.
Returning to my original solution, I looked at jquery-ui.position. I could see that trying to work, but the div just bounced off the image and ended up back underneath it.
The solution turned out to be pure CSS, and actually very simple:
img.body-background { position: absolute; top:0px; z-index:-1; } .before-header { position:relative; top:30px; z-index:+2; }
No, really: that’s it.
Here is a mockup of the result. (The site isn’t live yet so I don’t want to use a screenshot.)
Now if you’re ever in the position of needing to fit your screen size to your background image, you’ll know what to do. And you’ll also know the answer to the question “When is a background image not a background image?”
This just helped me on the site I’m building, thanks