CSS background-size: cover + background-attachment: fixed clipping background images
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
and background-size: cover
. When you specify background-attachment: fixed
it essentially causes the background-image
to behave as if it were a position: 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 the scroll
event in JS that manually updates the background-position
relative to how far the window has been scrolled in order to simulate fixed positioning but still calculate background-size: cover
relative to the container element rather than the viewport.
Background attachment fixed but full size image
Using an image tag it's doable considering object-fict
and position:fixed
* {
box-sizing: border-box;
}
body {
margin: 0;
}
.home-panel {
display: grid;
grid-template-columns: 50% 50%;
align-items: center;
height: 100vh;
}
.home-panel-media {
height: 100vh;
clip-path: inset(0); /* to clip the image to this div */
}
.home-panel-media img {
height: 100vh;
width: 50vw;
position: fixed;
top: 0;
right: 0;
object-fit: cover;
object-position: top center;
}
<div id="wrapper">
<div class="home-panels-wrapper">
<div class="home-panel home-panel-1">
<div class="home-panel-content">
<h1>Hello World</h1>
<p>
Lorem ipsum dolar gamet
</p>
<p>
</div>
<div class="home-panel-media">
<img src="https://i.pinimg.com/originals/a1/1e/2a/a11e2a9d5803e4dc2c034819ce12a16e.jpg">
</div>
</div>
<div class="home-panel home-panel-2">
<div class="home-panel-content">
<h1>Hello World</h1>
<p>
Lorem ipsum dolar gamet
</p>
<p>
</div>
<div class="home-panel-media">
<img src="https://images.squarespace-cdn.com/content/v1/56e05d74746fb93dcd805e8b/1553109528895-RYRDJLVNN61UDN65S59U/ke17ZwdGBToddI8pDm48kDmiacAi515_OfcChA6MRIQUqsxRUqqbr1mOJYKfIPR7LoDQ9mXPOjoJoqy81S2I8PaoYXhp6HxIwZIk7-Mi3Tsic-L2IOPH3Dwrhl-Ne3Z23Oc3-AlX22j3PUzoYuTVI2MKzQWw7jmw4KYJnTQU-9E_twk1mUNduAk0T15_nZ7z/Tulsa-Headshot-Photographer_9639a.jpg?format=1500w">
</div>
</div>
</div>
</div>
Background-size cover jumping when background-position switches to fixed
I had the same issue, when setting background-size
to cover
or contain
Setting a fixed height, in example for smaller screens via @media
prevents the background-image from jumping. After my tests I came to the conclusion, that the jumping is due to the orientation of the element after setting background-attachment
to fixed
Setting it to fixed
, the size
is calculated by the size of the viewport, not the element containing the background-image
. This is where the jumping comes from and why setting a fixed height or width for the background-size
solves this issue.
Repaint bug with background-attachment fixed and background-size cover in Chrome
I have noticed the best way to make sure the page backgound stays fixed no matter what is: place it as the background image of an empty first child of body, with these CSS rules:
.background-holder {
position: fixed;
width: 100%;
height: 100%;
display: block;
z-index: -10;
background-image: url(//link-to-image);
background-size: cover;
}
And here's the page structure:
<html>
<head>
</head>
<body>
<div class="background-holder"></div>
<div class="main-container">
<!-- content goes here -->
</div>
</body>
</html>
Fix video to background position, when using background-size cover
Cascading style solution
There is a way to achieve this in pure CSS, but — as usual — it does come with some caveats:
It relies on
vh
andvw
units. These are relatively new, so support for them is not perfect, but it isn't that bad either. Yay for CSS3!In order for this to work, your target image has to be sized to the viewport, or at least something that relates to the viewport.
It relies on media queries, but then again, so does much of the mobile-enabled interweb.
It may need a little tweaking to get the video exactly where you want it. But it has worked in everything modern I've tested so far.
Explanification
The key point to realise is that when "covering" an image, the browser switches between two ways of scaling the image. This switch happens when the viewport width goes above a certain proportion of the height. That proportion depends on the aspect ratio of the image you are using.
I'd like to say I'm awake enough at the moment to have actually calculated the value used in @media (min-width: 178vh)
but if I'm honest, I trialed and errored it. Just know that taking the original dimensions of your image 3264 x 1836, and calculating a ratio from that, 3264 / 1836 = 1.7777777778
leaves you with a certain number. Because vh
and vw
a 1/100ths of the viewport dimensions, you should multiply this number by a 100 and you get 178
when rounded. This is the switch point. Obviously if you change the dimensions of your original image, you will need to recalculate this and update the media query's selector.
Other than that it's just the simple case of working out what proportion of the viewport your video occupies in terms of vh
and vw
. Again, this was trial and errored, but in my defense beer seems to increase the likelihood that I'll use that methodology... no idea why.
Ramifications
Ah well, after a bit further testing it seems that webkit doesn't like the vh
in the media query — or at least it doesn't seem to be applying. I shall have to investigate as to why. It's possible that it just doesn't support this in max-width
which is a shame. There may be a solution in using vmin
and vmax
however.
Some time later.
Yep. Webkit lets the side down, again. Sorry, hats off to what is a very good browser... it just seems I can always rely on Firefox to do the right thing, Webkit, not so much. Unfortunately if a browser doesn't understand vh
and vw
in a particular context, there isn't much that can be done, save for falling back to scripting. Annoyingly Webkit does understand the viewport lengths in other contexts, so they have implemented code to handle these values, just not for media queries — as far as I can tell.
There is a slight fix though, it involves using orientation
in the media query instead. This isn't perfect, as it fails when the viewport is anything that approximates a square. It definitely decreases the number of different ratios it will fail for however. I've updated the code below.
Concollusions
In the end if I were implementing this (as the browsers currently stand). I'd use the CSS version, and then enhance with JavaScript for browsers that don't support the viewport metrics in media queries. You could do this from scratch using window.matchMedia
or a library such as Enquire.js.
I've updated the following with a JavaScript fallback, it should be noted this should be improved upon... most likely by using existing libraries to use cross-browser methods for applying event listeners and adding and removing class names. The current code will override any class names set on the HTML tag, so beware!
/// with thanks to http://stackoverflow.com/questions/3437786/#answer-11744120var viewportDimensions = function(){ var w = window, d = document, e = d.documentElement, g = d.getElementsByTagName('body')[0]; return { w: w.innerWidth || e.clientWidth || g.clientWidth, h: w.innerHeight|| e.clientHeight|| g.clientHeight };};
window.matchMedia && (function(){ var test = window.matchMedia('screen and (min-width: 0vh)'), f; /// this will only fail on browsers that do not support vh in media queries if ( !test.matches ) { /// listen out for resize window.addEventListener('resize', (f=function(e){ /// get the viewport dimensions var vpd = viewportDimensions(); /// run our js based test, same as the media query if ( vpd.w > (1.78 * vpd.h) ) { document.documentElement.className = 'min-width-178vh'; } else { document.documentElement.className = 'max-width-178vh'; } })); /// first run! f(); }})();
/* Shifts the coordinates to the center, because that is the only fixed coordinate when using "cover" on an image */.layer { position: absolute; left: 50%; top: 50%; width: 1px; height: 1px;}
/* By default base our values on viewport height This is what "cover" is doing, at least when your image is streched to the viewport */.video { position: absolute; width: 25.5vh; left: -50.5vh; top: -22.8vh; background: #F00;}
/* Half fix for webkit, it seems webkit does not support vh and vw in its media queries... why??? This will work as long as the viewport dimension are not squareish */@media screen and (orientation: landscape) { .video { top: -12.75vw; left: -28.5vw; width: 14.2vw; }}
/* Detect when we change scaling/cropping reaction and base our values on viewport width instead */@media screen and (min-width: 178vh) { .video { top: -12.75vw; left: -28.5vw; width: 14.2vw; }}
/* Repeating myself to repair the damage that the webkit fix does to Firefox's handling */@media screen and (max-width: 178vh) { .video { width: 25.5vh; left: -50.5vh; top: -22.8vh; }}
/* These styles override the media queries when called in by the JavaScript fallback */.min-width-178vh .video { top: -12.75vw !important; left: -28.5vw !important; width: 14.2vw !important;}.max-width-178vh .video { width: 25.5vh !important; left: -50.5vh !important; top: -22.8vh !important;}
/* These styles are just for set-up. You don't need to split the background image out into .inner, I just did so to open up options whilst trialing a solution. */.main { top: 0; left: 0; position: absolute; width: 100%; height: 100%;}
.inner { position: absolute; background: url("http://www.codelamp.co.uk/so/cover-video-pos-bg.jpg") no-repeat center center / cover; background-color: #000; width: 100%; height: 100%;}
<div class="main"> <div class="inner"></div> <div class="layer"> <div class="video"> <video width="100%"></video> </div> </div></div>
background attachment:fixed how to make the image not full screen ?
Changing:
.pic1,
.pic2,
.pic3 {
background-size: cover;
background-position: center center;
...
to:
.pic1,
.pic2,
.pic3 {
background-size: 50% auto;
background-position: center right;
...
.pic2 {
background-image: url("../img/restaurant.jpg");
background-position: center left;
}
Could be one solution to fix your issue.
CSS Background Attachment Scroll/Fixed and Background Size cover
The difference isn't really in background-size: cover
. The difference between background-attachment: scroll
and background-attachment: fixed
is that
"...scroll means that the background is fixed with regard to the element itself and does not scroll with its contents. (It is effectively attached to the element's border.)
"...fixed means that the background is fixed with regard to the viewport. Even if an element has a scrolling mechanism, a ‘fixed’ background doesn't move with the element."
as MDN says. So you'll see in your fiddle that the background-attachment: fixed
background doesn't remain in its containing element <div id="two">
border. It is, instead taking on the fixed point of absolute positioning 0, 0 in the entire body's background.
In essence, background-attachment: fixed
is overwriting background-size: cover
and not allowing the latter style to take effect.
Related Topics
How to Make Child Element Higher Z-Index Than Parent
How to Make CSS Visible Only For Opera
Css Selector - Element With a Given Child
Fixed Sidebar Navigation in Fluid Twitter Bootstrap 2.0
Specify an Svg as a Background Image and Also Style the Svg in Css
How to Round Out Corners When Using CSS Clip-Path
Add a CSS Class to Single Code Chunks in Rmarkdown
What Is the Value of the CSS 'Ex' Unit
What Does "I" Mean in a CSS Attribute Selector
How to Rotate the Background Image in the Container
How to Make Internet Explorer 8 to Support Nth Child() CSS Element
Full-Screen Responsive Background Image
Top Nav Bar Blocking Top Content of the Page
How to Make Generated Content Selectable
How to Use Template Literals in Tailwindcss to Change Classes Dynamically