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
I did a version with Responsive background image.
http://jsfiddle.net/onigetoc/grpku1gk/
Unfortunately this is simply an artifact of how fixed positioning works in CSS and there is no way around it in pure CSS - you have to use Javascript.
The reason this happens is due to the combination of
background-attachment: fixed
andbackground-size: cover
. When you specifybackground-attachment: fixed
it essentially causes thebackground-image
to behave as if it were aposition: fixed
image, meaning that it's taken out of the page flow and positioning context and becomes relative to the viewport rather than the element it's the background image of.So whenever you use these properties together, the
cover
value is being calculated relative to the size of the viewport irrespective of the size of the element itself, which is why it works as expected when the element is the same size as the viewport but is cropped in unexpected ways when the element is smaller than the viewport.To get around this you basically need to use
background-attachment: scroll
and bind an event listener to thescroll
event in JS that manually updates thebackground-position
relative to how far the window has been scrolled in order to simulate fixed positioning but still calculatebackground-size: cover
relative to the container element rather than the viewport.There's a jQuery fix for this: http://jsfiddle.net/QN9cH/1/ I know it's not optimal but at least it works :)