The reason is that in both cases the html element (and the body) element has height equal to 0 and a width equal to screen width.
Contain always consider the smallest dimension while cover always consider the biggest one.
let's take an example with a classic element to see what is happening:
.box {
height: 5px;
border: 1px solid;
margin:5px; background:url(https://media.architecturaldigest.com/photos/5da74823d599ec0008227ea8/16:9/w_2560%2Cc_limit/GettyImages-946087016.jpg) center no-repeat
}
<div class="box" style="background-size:contain"></div>
<div class="box" style="background-size:cover"></div>
I took a div with a small height and you can clearly see how the image is small when using contain
but with cover
the image will cover all the width. Now imagine that we make the height equal to 0
. In both cases, we will logically see nothing but imagine how the background will behaves. With contain the size will be 0
but not with cover and all the trick is here.
In addition to the above observation, you have the background propagation trick:
For documents whose root element is an HTML HTML element or an XHTML html element [HTML]: if the computed value of background-image on the root element is none and its background-color is transparent, user agents must instead propagate the computed values of the background properties from that element’s first HTML BODY or XHTML body child element. The used values of that BODY element’s background properties are their initial values, and the propagated values are treated as if they were specified on the root element. It is recommended that authors of HTML documents specify the canvas background for the BODY element rather than the HTML element.
All the trick lies on the "are treated as if they were specified on the root element". In other words, you background is applied to html
(0 height and full width) and in this case the size of the background is 0 so we see nothing after the propagation but in the case of cover the size of the background is different from 0 and we see something.
If you take your example with cover
and you apply 0 to the width you will see nothing:
body {
background-image: url(https://media.architecturaldigest.com/photos/5da74823d599ec0008227ea8/16:9/w_2560%2Cc_limit/GettyImages-946087016.jpg);
background-size: cover;
margin:0;
}
html {
width: 0px;
}
Increase the width a little and the background will start showing
body {
background-image: url(https://media.architecturaldigest.com/photos/5da74823d599ec0008227ea8/16:9/w_2560%2Cc_limit/GettyImages-946087016.jpg);
background-size: cover;
margin: 0;
}
html {
width: 5px;
}
A repeated pattern of small images having width equal to 5px
. Same logic with contain if you increase the height of your first example
body {
background-image: url(https://media.architecturaldigest.com/photos/5da74823d599ec0008227ea8/16:9/w_2560%2Cc_limit/GettyImages-946087016.jpg);
background-size: contain;
margin: 0;
}
html {
height: 5px;
}
Related question to see a similar behavior but with gradients: How to remove the stripes that appears when using linear gradient property
Your padding question becomes trivial now. Adding padding will increase the height of the html element and the size of your image will be different from 0