Splitting the background doesn't match perfectly

Not an easy question. Looking at the codepen will give you a better idea of โ€‹โ€‹what I am trying to do.

But basically, I want to split the image (in my case I am using background

) in blocks so that I can animate these different blocks with different animations.

TL; DR; I want the left set of blocks to look like the correct image in this code ... I created. This will probably help to consider a possible solution at the end of this question.

Let's say I have this image (taken from google). I have chosen this particular image to make it more than obvious what is going on. (Adding to that, I don't really care much about the aspect ratio of the image, that is, if it gets an axis squish or whatever).

line-wallpaper-1.jpg

I want to split it into 6 blocks:

<section class="blocks">
  <article class="block"></article>
  <article class="block"></article>
  <article class="block"></article>
  <article class="block"></article>
  <article class="block"></article>
  <article class="block"></article>
</section>

      

The first obvious solution I thought was using CSS w / Sass to align the background like this:

$num-of-blocks: 6;
.blocks {
  // ...
  .block {
    // ...
    height: 100%/$num-of-blocks;
    background-size: 100% 100%*$num-of-blocks;
    // THIS PUTS (allegedly) THE BACKGROUNDS IN PLACE
    // I say allegedly because it is not doing it the way it is supposed to.
    @for $b from 1 through $num-of-blocks {
      &:nth-child(#{$b}){
        background-position: 0% (100%/$num-of-blocks)*($b - 1);
      }
    }
  }
}

      

What the CSS does is basically by making the boxes available in height, then background

for each box it should take up 100% of the height multiplied by the number of boxes. After that, I "comb" each background up so that it is.

But the resulting blocks look like the image below. You can see that they are not perfect. My question is, am I doing something wrong? If so, how and how to fix it?

oupbUHN.png

codepen right here .

POSSIBLE SOLUTION (But I don't understand why).

I noticed that if instead .block { background-size: 100% 100%*$num-of-blocks }

I do:.block { background-size: 100% 100%*($num-of-blocks + 1) }

oPuDo3A.png

it looks like the image I'm aiming at, but it doesn't make sense to me. If this solves the problem, how and why does it happen? Or why not +1.1 instead of +1, etc.?

+3


source to share


1 answer


The answer is so hard to explain how it was, but I will try my best. The root cause of the problem is how it background-position

works when percentages are used . Please see my answer here for details on how this works. I am writing a separate answer here to explain why your suggested solution (in the question) works, but not the original one.

As you can see in the linked answer, when percentages are used for background-position

, browsers try to align the point indicated by the percentages in the image along with the corresponding point in the container .

From the W3C spec:

With a pair of values โ€‹โ€‹of '14% 84%, point 14% and 84% down, the image should be placed at point 14% across and 84% down in the padding box.


Why doesn't the original snippet output the expected output?

the first block is not a problem in any fragment in question, because it tries to align 0% 0%

on the image with the help 0% 0%

on the container. The problem is visible in the second and subsequent blocks.

For purposes of illustration, assume that the entire page is 600 pixels high. This means that the height of each individual box will be 16.66667% of 600 pixels, which is roughly 100 pixels. The height background

will also be only 600 pixels because although we say that 600% is 600% of the container size and 600% of 100 pixels is 600 pixels.

With the above assumption, let's see how the background positioning for the second block works :

  • The y-point in the image is 16.66667% of 600 pixels, which is about 100 pixels down.
  • The y-point of the container is 16.66667% of 100 pixels, which is roughly 16.66667 pixels. But since we already have a 100px box above that box, it actually gets 116.66667px down.

Likewise, for the third block :

  • The y-point in the image is 33.33333% of 600 pixels, which is about 200 pixels down.
  • The y-point of the container is 33.33333% of 100 pixels, which is about 33.33333 pixels down. But since we already have two 100px blocks above that, it actually gets 233.33333px down.

As you can see, there is a gap in terms of no. pixels, we move down the page and in the image. This is why there is misalignment.

.blocks {
  float: left; /* display: inline-block causes line break in snippet due to margin*/
  width: 50%;
  height: 100%;
  position: relative;
}
.blocks .block {
  width: 100%;
  height: 16.66667%;
  position: relative;
  background-size: 100% 600%;
  background-image: url("http://phandroid.s3.amazonaws.com/wp-content/uploads/2015/04/line-wallpaper-1.jpg");
}
.blocks .block:nth-child(1) {
  background-position: 0% 0%;
}
.blocks .block:nth-child(2) {
  background-position: 0% 16.66667%;
}
.blocks .block:nth-child(3) {
  background-position: 0% 33.33333%;
}
.blocks .block:nth-child(4) {
  background-position: 0% 50%;
}
.blocks .block:nth-child(5) {
  background-position: 0% 66.66667%;
}
.blocks .block:nth-child(6) {
  background-position: 0% 83.33333%;
}
img {
  float: left;
  width: 50%;
  height: 100%;
}
* {
  margin: 0;
  padding: 0;
}
html,
body {
  width: 100%;
  height: 100%;
}
      

<section class="blocks">
  <article class="block"></article>
  <article class="block"></article>
  <article class="block"></article>
  <article class="block"></article>
  <article class="block"></article>
  <article class="block"></article>
</section>
<img src="http://phandroid.s3.amazonaws.com/wp-content/uploads/2015/04/line-wallpaper-1.jpg" alt="" />
      

Run codeHide result



Why does the second snippet output the expected output?

Let's assume again that the height of the entire page is 600 pixels. This means that the height of each individual box will be 16.66667% of 600 pixels, which is roughly 100 pixels. The height background

will be 700 pixels here, because here it is 700% of the container's size.



With the above assumption, let's see how the background positioning for the second block works :

  • The y-point in the image is 16.66667% of 700 pixels, which is about 116.66667 pixels down.
  • The y-point of the container is 16.66667% of 100 pixels, which is roughly 16.66667 pixels. But since we already have a 100px box above that box, it actually gets 116.66667px down.

Likewise, for the third block :

  • The Y-point in the image is 33.33333% of 700 pixels, which is roughly 233.33333 pixels down.
  • The y-point of the container is 33.33333% of 100 pixels, which is about 33.33333 pixels down. But since we already have two 100px blocks above that, it actually gets 233.33333px down.

As you can see, there is no decoupling here in terms of no. pixels, we move down the page and in the image. Hence, there is no offset, and they exactly match what a 600px high image would look like.

.blocks {
  float: left;
  width: 50%;
  height: 100%;
  position: relative;
}
.blocks .block {
  width: 100%;
  height: 16.66667%;
  position: relative;
  background-size: 100% 700%;
  background-image: url("http://phandroid.s3.amazonaws.com/wp-content/uploads/2015/04/line-wallpaper-1.jpg");
}
.blocks .block:nth-child(1) {
  background-position: 0% 0%;
}
.blocks .block:nth-child(2) {
  background-position: 0% 16.66667%;
}
.blocks .block:nth-child(3) {
  background-position: 0% 33.33333%;
}
.blocks .block:nth-child(4) {
  background-position: 0% 50%;
}
.blocks .block:nth-child(5) {
  background-position: 0% 66.66667%;
}
.blocks .block:nth-child(6) {
  background-position: 0% 83.33333%;
}
img {
  float: left;
  width: 50%;
  height: 100%;
}
* {
  margin: 0;
  padding: 0;
}
html,
body {
  width: 100%;
  height: 100%;
}
      

<section class="blocks">
  <article class="block"></article>
  <article class="block"></article>
  <article class="block"></article>
  <article class="block"></article>
  <article class="block"></article>
  <article class="block"></article>
</section>
<img src="http://phandroid.s3.amazonaws.com/wp-content/uploads/2015/04/line-wallpaper-1.jpg" alt="" />
      

Run codeHide result



In the above method, the bottom of the image (100px) will be reduced to some extent because the image is 700px (700%) in size, but the total page height (total height of the containers) is only 600px.

If this is not desired, the calculation logic for background-size

and background-position

can be changed as shown below (including only the changed parts):

.block { 
  background-size: 100% $h*$num-of-blocks;
  @for $b from 1 through $num-of-blocks {
    &:nth-child(#{$b}){
      background-position: 0% ($h/($num-of-blocks - 1))*($b - 1);
    }
  }
}

      

.blocks {
  float: left;
  width: 50%;
  height: 100%;
  position: relative;
}
.blocks .block {
  width: 100%;
  height: 16.66667%;
  position: relative;
  background-size: 100% 600%;
  background-image: url("http://phandroid.s3.amazonaws.com/wp-content/uploads/2015/04/line-wallpaper-1.jpg");
}
.blocks .block:nth-child(1) {
  background-position: 0% 0%;
}
.blocks .block:nth-child(2) {
  background-position: 0% 20%;
}
.blocks .block:nth-child(3) {
  background-position: 0% 40%;
}
.blocks .block:nth-child(4) {
  background-position: 0% 60%;
}
.blocks .block:nth-child(5) {
  background-position: 0% 80%;
}
.blocks .block:nth-child(6) {
  background-position: 0% 100%;
}
img {
  float: left;
  width: 50%;
  height: 100%;
}
* {
  margin: 0;
  padding: 0;
}
html,
body {
  width: 100%;
  height: 100%;
}
      

<section class="blocks">
  <article class="block"></article>
  <article class="block"></article>
  <article class="block"></article>
  <article class="block"></article>
  <article class="block"></article>
  <article class="block"></article>
</section>
<img src="http://phandroid.s3.amazonaws.com/wp-content/uploads/2015/04/line-wallpaper-1.jpg" alt="" />
      

Run codeHide result


The calculation logic is the same as above, except for a different set of values. For the second block :

  • The y-point in the image is 20% of 600 pixels, which is 120 pixels lower.
  • The y-point of the container is 20% of 100 pixels, which is 20 pixels lower. But since we already have a block 100 pixels above that block, it actually gets 120 pixels lower.

Likewise, for the third block :

  • The y-point in the image is 40% of 600 pixels, which is 240 pixels lower.
  • The y-point of the container is 40% of 100 pixels, which is 40 pixels lower. But since we already have two 100px blocks above that, it actually gets 240px down.
+3


source







All Articles