Reputation: 9532
I'm using a background image which should be displayed with full width and for that I'm calculating the height with javascript.
Here's the HTML. The container is necessary for other purposes irrelevant to this question.
<div class="cover-container">
<div class="cover"></div>
</div>
<div>
And this is my CSS. This should make the background image take up the entire container width.
.cover-container {
display: block;
background: linear-gradient(rgba(0, 0, 0, 0.45), rgba(0, 0, 0, 0.45));
}
.cover {
background: linear-gradient(rgba(0, 0, 0, 0.45), rgba(0, 0, 0, 0.45));
background-size: 100%;
background-repeat: no-repeat;
background-attachment: fixed;
}
And then we adjust the height of the container to the ratio the width was stretched out or squeezed:
let resizeCover = size => {
const [w, h] = size;
const ratio = $cover.width() / w;
$cover.height(cover.height * ratio);
}
const $cover = $('.cover');
const cover = new Image();
cover.src = url;
let imgSize = null;
cover.onload = () => {
imgSize = [cover.width, cover.height];
const bg = 'linear-gradient(rgba(0, 0, 0, 0.45), rgba(0, 0, 0, 0.45)), url("' + url + '")';
$cover.css('background-image', bg);
resizeCover(imgSize);
};
Working fiddle. It has some content so you can see the fixed scroll effect we want in our cover.
Now, see how there's a grey gap below the background image. If you open the image source you can see it's offset to the top: the gap matches the top part of the image that isn't shown.
The image used in the fiddle has a 9:1 aspect ratio. The .cover
width/height ratio is pretty much the same (decimals), you can see it in the log. So it's not like the size of the container isn't matching the image aspect ratio and that's why it's not fitting exactly.
Why is this happening? Why is the image being pushed to the top, creating that gap? It should fit the container perfectly or almost perfectly.
I've tried with background-size: cover
because the docs say:
cover Scales the image as large as possible to fill the container, stretching the image if necessary. If the proportions of the image differ from the element, it is cropped either vertically or horizontally so that no empty space remains.
However, it's clear that the image is stretched out to the window's dimensions, not the container's.
PS: the sole reason I'm not using an <img>
tag, which would make things much easier and responsive, is that we want the background-attachment: fixed
effect.
Upvotes: 0
Views: 80
Reputation: 9532
I ended up fixing it by just applying the offset as background-position
:
const offset = $cover.offset().top;
$cover.css('background-position', `0 ${offset}px`);
This works because as per the docs, if the background image is fixed it is placed relative to the viewport, not the container.
Upvotes: 0
Reputation: 22653
You need to change background-attachment background-attachment: fixed;
to background-attachment: local;
or just remove it completlly and background-size: 100%;
to background-size: cover;
on the .cover
element.
local The background is fixed relative to the element's contents. If the element has a scrolling mechanism, the background scrolls with the element's contents, and the background painting area and background positioning area are relative to the scrollable area of the element rather than to the border framing them.
.cover {
background: linear-gradient(rgba(0, 0, 0, 0.45), rgba(0, 0, 0, 0.45));
background-size: 100%;
background-position: center top;
background-repeat: no-repeat;
/*background-attachment: fixed;*/
background-attachment: local;
}
Here is the final result:
//const url = 'https://images.unsplash.com/photo-1618960216830-281234f5f1fc?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=400&ixlib=rb-1.2.1&q=80&w=1200';
const url = 'https://images.unsplash.com/photo-1620380890341-424d001e03c3?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=100&ixlib=rb-1.2.1&q=80&w=900';
const $cover = $('.cover');
let imgSize = null;
const cover = new Image();
cover.src = url;
let resizeCover = () => {
const [w, h] = imgSize;
const ratio = $cover.width() / w;
$cover.height(cover.height * ratio);
console.log($cover.width() / $cover.height());
}
cover.onload = () => {
imgSize = [cover.width, cover.height];
const bg = 'linear-gradient(rgba(0, 0, 0, 0.45), rgba(0, 0, 0, 0.45)), url("' + url + '")';
$cover.css('background-image', bg);
resizeCover();
};
$(window).resize(() => resizeCover());
.cover-container {
display: block;
background: linear-gradient(rgba(0, 0, 0, 0.45), rgba(0, 0, 0, 0.45));
}
.cover {
background: linear-gradient(rgba(0, 0, 0, 0.45), rgba(0, 0, 0, 0.45));
/*background-size: 100%;*/
background-size: cover;
background-position: center top;
background-repeat: no-repeat;
/*background-attachment: fixed;*/
background-attachment: local;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="cover-container">
<div class="cover"></div>
</div>
<div>
DEMO 2:
//const url = 'https://images.unsplash.com/photo-1618960216830-281234f5f1fc?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=400&ixlib=rb-1.2.1&q=80&w=1200';
const url = 'https://images.unsplash.com/photo-1620380890341-424d001e03c3?crop=entropy&cs=tinysrgb&fit=crop&fm=jpg&h=100&ixlib=rb-1.2.1&q=80&w=900';
const $cover = $('.cover');
let imgSize = null;
const cover = new Image();
cover.src = url;
let resizeCover = () => {
const [w, h] = imgSize;
const ratio = $cover.width() / w;
$cover.height(cover.height * ratio);
console.log($cover.width() / $cover.height());
}
cover.onload = () => {
imgSize = [cover.width, cover.height];
const bg = 'linear-gradient(rgba(0, 0, 0, 0.45), rgba(0, 0, 0, 0.45)), url("' + url + '")';
$cover.css('background-image', bg);
resizeCover();
};
$(window).resize(() => resizeCover());
.cover-container {
display: block;
background: linear-gradient(rgba(0, 0, 0, 0.45), rgba(0, 0, 0, 0.45));
}
.cover {
background: linear-gradient(rgba(0, 0, 0, 0.45), rgba(0, 0, 0, 0.45));
background-size: 100%;
background-position: center top;
background-repeat: no-repeat;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="cover-container">
<div class="cover"></div>
</div>
<div>
Upvotes: 1