Buggy edges in Chrome when using ‘background-size: cover’
Chrome seems to have an issue with using background-size: cover to make background images fill the entirety of the element the property is used on. Instead of a clean edge, a line of pixels from the opposite end of the image often shows up. I’ve created a fiddle demonstrating the bug, pictured below:
Your first thought is likely ‘Ah, a rounding bug!’ — and you’d be right. Indeed, you might need to slowly adjust the size of your browser and/or element size to expose the issue, making it very easy for one person to never encounter it while someone else sees it all the time.
The problem occurs because the browser tries to match the image size to the element, retaining the image’s aspect ratio at all costs. If this can’t be done perfectly (i.e. the height or width of the image ends up being a decimal), the browser has to decide how to round the numbers.
When it comes to this particular CSS property, the browser’s decision should be simple: always round up. That way, the worst that’ll happen is a row of pixels will get cut off. Most browsers get it right — Chrome isn’t one of them.
I’ve come up with two fixes, the second of which produces the best results in return for a bit more work:
Method 1: Don’t allow the background to repeat
Use background-repeat: no-repeat on the element. If the bug occurs, all that’ll happen is whatever’s behind the element will show through (this can be a background-color). This is only really masking the issue as there’ll still be a row of pixels not showing up correctly, but it’s sometimes an adequate drop-in solution. Check out my fiddle.
Method 2: Overscan the background
Borrowing from the concept of TV overscanning, apply the background image properties to a child element that’s absolutely positioned to be 1% bigger in each direction than it needs to be. The image can then be cleanly cropped by overflow: hidden — you’ll lose the very edges of your image, but the element you want to fill with a background image will be well and truly filled.
background-position: 50% 50%;
The .background element should be unique to your project; it could just as easily be .header, and the dimensions don’t matter. Just ensure that it has overflow: hidden and position: relative (or absolute), as they’re used to position the .overscan-background element.
You can more or less use the .overscan-background element as it is, apart from changing the background-image path. As I mentioned before, this method involves a small part of the image being cut off. You can control the amount lost by adjusting the percentages:
background-position: 50% 50%;
Take a look at my fiddle demonstrating this method. I’ve also prepared another fiddle showing the same concept, but with a circle used as the background image in a square element — it’s easier to see how the technique works with this example.
If anyone has a simpler solution to the problem, let me know!