0

I realize there are similar questions but I haven't been able to find a proper explanation. I'm trying to understand best CSS practices for having multiple repeating backgrounds. Essentially I want to be able to repeat a background image to fit the entire height and width of the screen AND have another div centered inside of each repeating background image, but that inner-centered div should repeat only once per background image.

So below I have set a background image to fill the entire viewport and repeat. However, everything I've tried to do to have a the center image repeat has not worked. I end up with the inner image div repeating across the whole viewport as well as opposed to only repeating once per background image.

I know that I can just have a div with an img tag inside of it, style it however I want and then just copy + paste the div in HTML, but this is not DRY and I want to avoid that. I also know that you can declare multiple backgrounds with CSS3, but so far nothing has worked. I'm not sure if this is the right approach to this problem, but I find CSS to be really confusing for things of this nature. I'm not sure if there is a completely different and better way to do this so I appreciate any help at all, thanks

<div id='bground'>
 <div id='center-image'></div>
</div>

<style>
#bground {
  height:100vh;
  width:100vw;
  background-image: url(./img);
  background-repeat: repeat;
}

#center-image {
???
}
<style>
James
  • 1
  • 1
  • I don't think you get the idea of CSS and HTML. HTML and CSS are 2 different entities - meaning you can't possibly style what's not there in the HTML in the first place. In other words to achieve what you want, you can't just have 1 `
    ` and expect CSS to create multiple instances of that `
    `. Put simply - **You need to create the structure first then style those strucutues. You can't create 1 structure then let style create multiple instances of that structure.**
    – Nikhil Nanjappa Feb 21 '17 at 22:05
  • Whether you copy paste or create a loop and iterate - that's the HTML logic you need to decide and that has nothing to do with the CSS at all. **Basically first decide how your HTML should be structured for the requirement you need.** – Nikhil Nanjappa Feb 21 '17 at 22:11
  • @NikhilNanjappa Of course your recommendations are sound. However, if someone wants to repeat imagery or content in concert with a repeating background and they don't want to generate an image server-side, it can be done. See my answer below. I'd categorize the approach as a cool proof, but not a best practice. – ifugu Mar 13 '17 at 15:27

1 Answers1

1

Image

If your intention is to repeat two images, one centered over top of the other, you can use an SVG for the centered image. Unfortunately, you will need to use a data URI for the centered image.

Essentially, you will use the SVG image as a container for the centered image. You need to make the SVG's width and height match the underlying image's dimensions. Then, the smaller image inside the SVG needs to be positioned so that it is centered relative to the underlying image. Notice the x, y, width, and height attributes on the image element within the SVG.

The example below uses multiple background images.

An answer on this question discusses the SVG approach in more detail: CSS, background-repeat distance

body {
  margin: 0;
}
#bground {
  height:100vh;
  width:100vw;
  background-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%22200%22%20height%3D%22300%22%3E%3Cimage%20x%3D%2280%22%20y%3D%22130%22%20width%3D%2240%22%20height%3D%2240%22%20xlink%3Ahref%3D%22data%3Aimage%2Fjpeg%3Bbase64%2C%2F9j%2F4AAQSkZJRgABAQAAAQABAAD%2F2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj%2F2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj%2FwgARCAAoACgDASIAAhEBAxEB%2F8QAGwAAAwEAAwEAAAAAAAAAAAAAAAQGAwECBQf%2FxAAXAQADAQAAAAAAAAAAAAAAAAABAgMA%2F9oADAMBAAIQAxAAAAG86acOV1s9MqB6A8n5WklJX%2Be1spUAXYuMNlgBjUw09AMf%2F8QAIRAAAgICAQQDAAAAAAAAAAAAAgMAAQQRBQYQEiETFBX%2F2gAIAQEAAQUClwpcZ77%2FAGkk%2BtHPCbqc3ksWJUW%2Bn8mwO2rnqc0L4T23fAibGWIQj1LbUyFoXkDmfFP0jn%2F%2FxAAZEQACAwEAAAAAAAAAAAAAAAAAAQMQESD%2F2gAIAQMBAT8BGOPecr%2F%2FxAAYEQEBAQEBAAAAAAAAAAAAAAAAARAREv%2FaAAgBAgEBPwFHpUzqXP%2FEACMQAAEDAwMFAQAAAAAAAAAAAAEAAiEDEBESMTIEE0FxkSD%2F2gAIAQEABj8C%2FZpNqDWPCg59XDKOZE4WxTqL4aZGVzb9sH9PqAAnSubvqfUe7LBGCthaV3GjfwiGDHq3%2F8QAHhAAAgICAwEBAAAAAAAAAAAAAAERITFBEFFhkXH%2F2gAIAQEAAT8haky4Yk6rhk9ldiBK0xsVPRDcN4kl5b%2BG6dVLEs%2FIN9V8Hk4zXQWCcOpK2NluSVmRnNR6PKc26JjoircsTUz%2F2gAMAwEAAgADAAAAEDOwo1gwYfv%2FxAAYEQEBAQEBAAAAAAAAAAAAAAABABEQYf%2FaAAgBAwEBPxC8yLXuss6dbL%2F%2FxAAYEQEAAwEAAAAAAAAAAAAAAAABABARMf%2FaAAgBAgEBPxCgDk3lNiiJX%2F%2FEACEQAQACAgIBBQEAAAAAAAAAAAEAESExQVFxEGGBobHR%2F9oACAEBAAE%2FELW0gqmyDDiYrR5lZuXo9KVbULukWV5B0pzUsrFUqlmyGZMLEtl8wBS6zwWtmuZz55VQ3LMSNlQbLcZilBff%2B0RlvhzNRXR3Q52y0I1bVzNQpLb5p6gGyHhB%2FZtwQwhRpbIkobZnuBFUklgL3Eiln3P%2F2Q%3D%3D%22%20%2F%3E%3C%2Fsvg%3E'), url('https://unsplash.it/200/300/?random');

/*
SVG image before URL encoding (required for IE/Edge)
data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="300"><image x="80" y="130" width="40" height="40" xlink:href="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wgARCAAoACgDASIAAhEBAxEB/8QAGwAAAwEAAwEAAAAAAAAAAAAAAAQGAwECBQf/xAAXAQADAQAAAAAAAAAAAAAAAAABAgMA/9oADAMBAAIQAxAAAAG86acOV1s9MqB6A8n5WklJX+e1spUAXYuMNlgBjUw09AMf/8QAIRAAAgICAQQDAAAAAAAAAAAAAgMAAQQRBQYQEiETFBX/2gAIAQEAAQUClwpcZ77/AGkk+tHPCbqc3ksWJUW+n8mwO2rnqc0L4T23fAibGWIQj1LbUyFoXkDmfFP0jn//xAAZEQACAwEAAAAAAAAAAAAAAAAAAQMQESD/2gAIAQMBAT8BGOPecr//xAAYEQEBAQEBAAAAAAAAAAAAAAAAARAREv/aAAgBAgEBPwFHpUzqXP/EACMQAAEDAwMFAQAAAAAAAAAAAAEAAiEDEBESMTIEE0FxkSD/2gAIAQEABj8C/ZpNqDWPCg59XDKOZE4WxTqL4aZGVzb9sH9PqAAnSubvqfUe7LBGCthaV3GjfwiGDHq3/8QAHhAAAgICAwEBAAAAAAAAAAAAAAERITFBEFFhkXH/2gAIAQEAAT8haky4Yk6rhk9ldiBK0xsVPRDcN4kl5b+G6dVLEs/IN9V8Hk4zXQWCcOpK2NluSVmRnNR6PKc26JjoircsTUz/2gAMAwEAAgADAAAAEDOwo1gwYfv/xAAYEQEBAQEBAAAAAAAAAAAAAAABABEQYf/aAAgBAwEBPxC8yLXuss6dbL//xAAYEQEAAwEAAAAAAAAAAAAAAAABABARMf/aAAgBAgEBPxCgDk3lNiiJX//EACEQAQACAgIBBQEAAAAAAAAAAAEAESExQVFxEGGBobHR/9oACAEBAAE/ELW0gqmyDDiYrR5lZuXo9KVbULukWV5B0pzUsrFUqlmyGZMLEtl8wBS6zwWtmuZz55VQ3LMSNlQbLcZilBff+0RlvhzNRXR3Q52y0I1bVzNQpLb5p6gGyHhB/ZtwQwhRpbIkobZnuBFUklgL3Eiln3P/2Q==" /></svg>
*/
}
<div id="bground">
</div>

Arbitrary Content

If your intention is to have your inner div contain arbitrary content, then you must use either a server-side solution or client-side script.

Here's a solution that uses html2canvas to convert your div into an image. The image is then inserted into an SVG like the example above.

var repeats = document.getElementsByClassName('background-repeat-centered');

for (var i = 0, max = repeats.length; i < max; i++) {
  var repeat = repeats[i],
      measureImage = new Image(),
      parentImage = repeat.parentElement,
      parentImageStyle = parentImage.currentStyle || window.getComputedStyle(parentImage, false),
      parentImageSrc = parentImageStyle.backgroundImage;

  measureImage.src = parentImageSrc.replace(/url\((['"])?(.*?)\1\)/gi, '$2').split(',')[0];
  
  measureImage.addEventListener('load', function () {
    var parentWidth = measureImage.width,
        parentHeight = measureImage.height;

    html2canvas(repeat, {
      onrendered: function(canvas) {
        var repeatWidth = canvas.width,
            repeatHeight = canvas.height,
            x = (parentWidth - repeatWidth) / 2,
            y = (parentHeight - repeatHeight) / 2;

        repeat.parentElement.style.backgroundImage = 'url(\'data:image/svg+xml,' + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="' + parentWidth + '" height="' + parentHeight + '"><image x="' + x + '" y="' + y + '" width="' + repeatWidth + '" height="' + repeatHeight + '" xlink:href="' + canvas.toDataURL() + '" /></svg>') + '\'), ' + parentImageSrc;
      }
    });

  }, false)
}
.background-repeat-centered {
  visibility: hidden;
}

body {
  margin: 0;
}
#bground {
  height: 100vh;
  width: 100vw;
  background-image: url('http://lorempixel.com/200/300/');
}
#sample {
  background: Purple;
  color: White;
  display: inline-block;
  font-family: sans-serif;
  font-weight: bold;
  padding: 10px;
  text-align: center;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/0.4.1/html2canvas.min.js"></script>

<div id="bground">
  <div class="background-repeat-centered" id="sample">
     Repeat after me!
  </div>
</div>
Community
  • 1
  • 1
ifugu
  • 648
  • 7
  • 11