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.