I have a list of figures containing background images. Something like the following:
<ul>
<li>
<figure style="background-image: url(...);"></figure>
</li>
<li>
<figure style="background-image: url(...);"></figure>
</li>
<li>
<figure style="background-image: url(...);"></figure>
</li>
</ul>
Each of these images has their background-size
set to cover
and background-attachment
set to fixed
.
figure {
width: 100%;
height: 100%;
background-size: cover;
background-attachment: fixed;
}
When each of the figures takes up the entire viewport, this works fine, but if there is an offset of any kind the background-image gets clipped.
As far as I can tell this is by design (https://developer.mozilla.org/en-US/docs/Web/CSS/background-size#Values).
I would like the images to either clip vertically or horizontally but not both, and be centred by the size of the figure itself.
I know there are javascript solutions but is there a way to do this using CSS?
Here is a working example: http://codepen.io/Godwin/pen/KepiJ
Another very simple solution is to use of the
vw
andvh
units (which, in case you didn't know, has totally passable browser support for most cases). For example, instead of doingbackground-size: cover
, dobackground-size: auto 100vh
.If you're not familiar with
vw
andvh
, they're viewport units, and they correspond to viewport width and viewport height. The values correspond to a percentage of the viewport height or width. For example,50vw
means 50% of the viewport width.For our purposes, we can simply tell the background to be 100% of the viewport height.
Here's a fiddle.
If you need to accommodate for different aspect ratios you can take advantage of the aspect-ratio @media rules.
An example of parallax effect for separately arranged elements (not for fullscreen elements):
html:
css:
js:
There is no real solution. However, you could make size height of the image
auto
instead ofcover
. And adjust the width size in % in your element until it bites the border.You see if you resize your window, it won't be clipped. Instead, it will always keep the original image size format. With this above you basically 'zoom' it but doesn't 'cover' it up.
Update in July 2018: There is now a 1-line fix for this problem
I had this same problem until I read this article, which taught me that I could add this line to my CSS to make it work:
will-change: transform;
It worked!
Now my CSS looks like this:
It's working for me on Windows Chrome, Edge, and Safari. But not Firefox.
The background-size: cover; property is indeed clipping the image in order for it to fill the area and not have any empty space.
The background-size: contain; property is determining which dimension is larger and scales according to that. So if you have a 100px x 100px block and a background image of 200x150px, setting the background-size to contain will scale the image to 100x75px. In this scenario however, you will have empty space if the element's aspect ratio is different than the image's.
You can also manually control which proportion has priority, assuming you know the image's aspect ratio.
So if you know that your image is always 100x200px, this means that the width is always the small dimension and the height the large one.
Now setting the background-size: 100% auto; will ensure that you will not get empty space but you will end up with clipping. If you set it to background-size: auto 100%; it will ensure that no clipping takes place and the height will never have empty space ( but the width will).
If you do want clipping and just center the image, use background-position: 50%;.
Nick Noordijk's answer put me on the right track, but I like to avoid scripts that perform a calculation every time the scroll event happens. Here's my version that only performs the calculation when page loads or screen size changes:
html:
css:
jQuery:
Note that this really only works with landscape "banner" images - using
background-size: auto nn%
doesn't have the same advantage ofbackground-size: cover
in working no matter if your image has excess in either direction.