user94896
user94896

Reputation:

Horizontally repeating SVG pattern

Is it possible to emulate the following CSS in an SVG fill?

background-image: url(/* URL */);
background-position: 50%;
background-size: auto 100%;
background-repeat: repeat-x;

i.e. A background image that has its aspect ratio preserved, has the same height as its container, is centred, and repeats horizontally. This JSBin demonstrates the behaviour I'm trying to implement, using an animation to show how the background responds to height changes.

Upvotes: 5

Views: 11525

Answers (1)

ccprog
ccprog

Reputation: 21856

It's awkward, to say the least, and it is far from perfect. As the outermost element, I have set a html <div> element, but it could also be a <svg> element. The key point is to remember that you need an inner <svg> with overflow: visible, and an outer element with overflow: hidden (which would be the default for an <svg> element.

@keyframes shrink {
  0% { height: 200px; }
  100% { height: 50px; }
}

div {
  animation: 2s ease-in-out 0s infinite alternate shrink;
  border: 1px solid #000;
  height: 200px;
  width: 200px;
  overflow: hidden;
}
<div>
  <svg width="100%" height="100%" viewBox="-0.675 0 0.1 1"
       preserveAspectRatio="xMidYMid meet" overflow="visible">
    <pattern id="p1" viewBox="0 0 100 80" height="1" width="1.25"
             patternUnits="userSpaceOnUse">
      <image xlink:href="http://static.jsbin.com/images/dave.min.svg"
             width="100" height="80" />
      <rect width="100" height="80" fill="none" stroke="brown" />
    </pattern>
    <rect fill="url(#p1)" x="-500" y="0" width="1000" height="1" />
  </svg>
</div>

  • The repetitions are not conceptually endless, but merely very long - I've set 1000 / 1.
  • If the container is higher than wide in respect to the aspect ratio of the svg viewBox, the image will only scale so far that the viewBox still fits inside. This is due to the meet keyword being always applied for both directions. Therefore, the viewBox width needs to be small - I've set 1 / 10.
  • The size of the image needs to be known in advance, and it must be used in four places:
    • The <image> width and height must be explicitely set, SVG has no notion of "natural size".
    • The <pattern> viewBox attribute must be set to the image size. I've added a rectangle to illustrate the image borders.
    • While the pattern height attribute always needs to be 1, the width has to be set to the correct apect ratio.
    • If the viewBox on the on the inner <svg> has a value of "x 0 ws 1", and wp is the pattern width, then x = -(wp/2 + ws) - for my example, ws=0.1, wp=1.25 => x=-0.675.

Upvotes: 5

Related Questions