2
votes

I'm trying to recreate this layout in HTML/CSS (cross-browser compatible back to IE9):

diagonally split background pattern

Basically, it's a diagonal line spanning the width of the viewport that divides two background patterns. It will have a fixed height, but it should stretch dynamically to the full width of its container.

I couldn't think of a way to achieve this using purely CSS, so my next thought was to use SVG. This isn't very difficult to do with solid colors:

http://codepen.io/troywarr/pen/EPXVRV?editors=110

But, I'm stumped on how to apply a repeating background pattern to the SVG shape. It will need to line up with the background pattern in the <section>s above and below, and the background fill shouldn't scale with the dimensions of the shape, or it will appear distorted.

Applying some background images in CSS, I'm getting closer:

http://codepen.io/troywarr/pen/OMgyoE?editors=110

I just need the dark background pattern in the filled portion of the SVG.

Using a more visible image as a test, I'm able to stretch it to the dimensions of my <polyline>:

http://codepen.io/troywarr/pen/BjZoEq?editors=110

But, there's that stretching that I don't want. I need to tile my pattern, or at least not distort its native dimensions (so I can use a large swatch of it, if needed), even if the shape itself has a fluid width. I've tried several different combinations of attribute values for the <pattern> element, but I've yet to find anything that works as intended, even following some guidance from related answers:

Any suggestions? I'd love to hear any ideas for non-SVG approaches as well. Thanks!


UPDATE:

Sorry, I just realized that the background patterns in my CodePen examples weren't working. I've updated them with working image URLs.

3

3 Answers

2
votes

This is one way to do it with just CSS. You can use the after pseudo-elements to help you get those angles and just a single png for the diagonal(or an element rotated if you want to avoid the element) and another for the repeating pattern. Since I didn't have your images I just made some real fast, but this should more or less be what you want.

html { height:100%; }
body {
  padding:0;
  margin:0;
  height:100%;
  background:#333;
}

.demo {
  width:100%;
  height:auto;
  position:absolute;
}

body:after {
  position:absolute;
  content:'';
  top:0;
  bottom:0;
  right:0;
  left:0;
  pointer-events:none;
  background: transparent url(http://i.imgur.com/iUhGezx.png) repeat top left;
}

.demo .top {
  min-height:100px;
  background:#FFF;
  position:relative;
}

.demo .bottom { min-height:60px; }

.demo .top:after {
  position:absolute;
  content:'';
  top:100%;
  left:0;
  right:0;
  height:100px;
  background: transparent url(http://i.imgur.com/iEubBd5.png) repeat top left;  
  background-size: 100% 100px;
}
<div class="demo">
   <div class="top"></div>
   <div class="bottom"></div>
</div>
2
votes

This is not currently possible with SVG. If you are stretching the SVG with preserveAspectRatio="none" then the entire contents of the SVG are affected. There is no way for some of the contents to opt out of the stretch transform.

In the future, there may be a way to do this in SVG2, but not with the current version of SVG.

Update

If you can live with it not working in IE, you can use a mask or a clip-path to achieve what you want. Below is an example of using clip-path.

body {
  margin: 0;
}

section {
  height: 50px;
}

main {
  background-image: url('http://mass-relevance-all-access.massrel.io/template-static-2e84fe3d1c7dc87710f58b990263ad6c29dacafc/img/bg-pattern-light.png');
}

.dark {
  background: #262729 url('http://mass-relevance-all-access.massrel.io/template-static-2e84fe3d1c7dc87710f58b990263ad6c29dacafc/img/bg-pattern-dark.png');
}

.diagonal {
  background: url(http://www.boogdesign.com/examples/svg/daisy-grass-repeating-background.jpg);
  -webkit-clip-path: url(#diagonalclip);
  clip-path: url(#diagonalclip);
}
<svg width="0" height="0">
  <defs>
    <clipPath id="diagonalclip" clipPathUnits="objectBoundingBox">
      <polyline points="0,1 1,0 1,1 0,1"/>
    </clipPath>
  </defs>
</svg>
<main>
  <section class="light"></section>
  <section class="diagonal"></section>
  <section class="dark"></section>
</main>
2
votes

Considering you need :

  • the slant width to be relative to viewport
  • a fixed height for the shape

There is a simple CSS approach you can use with border and viewport units :

body,html{padding:0;margin:0;}
div{
  border-bottom:50px solid rgba(0,0,0,.8);
  border-top: 50px solid transparent;
  background-image:url('http://i.imgur.com/iUhGezx.png');
}
div:before{
  content:'';
  display:block;
  border-right:100vw solid rgba(0,0,0,.8);
  border-top:50px solid transparent;
}
<div></div>

The pattern is repeated with the background-image property. The slant is made with the borders on the pseudo element.
The borders on the parent div are there just to make the top and bottom space around the slant.

Viewport related units (vw) are supported by IE9 and over (see canIuse for more info).


Update :

If you need to have a seperate background-image for both areas, there are 2 possible CSS approaches :

With transforms: supported by IE9 and over with vendor prefixes. The slant always has the same angle.

body,
html {
  padding: 0;
  margin: 0;
  overflow:hideden;
}
div{
  width:100%;height:150px;  
  position:absolute;
}
.top {
  padding-top:50px;
  background: #fff url('http://i.imgur.com/dzFT6wB.png');
}
.bot {
  transform-origin:100% 0;
  transform:rotate(-5deg);
  overflow:hidden;
  top:50px; right:0;
  width:110%;
}
.bot:after{
  content:'';
  position:absolute;
  right:0;top:0;
  width:100%;height:100%;
  transform-origin:inherit;
  transform:rotate(5deg) translatez(0px);
  background: #262729 url('http://i.imgur.com/LxTJ685.png');
}
<div class="top"></div>
<div class="bot"></div>

With the clip-path property: although it has low browser support, it will allow you to control the slant angle better :

body,html{padding:0;margin:0;}
div{
  position:relative;
  height:150px;
}
div:before, div:after{
  content:'';
  width:100%; height:100%;
  position:absolute;
}
div:before{
  background: url('http://i.imgur.com/dzFT6wB.png');
}
div:after{
  -webkit-clip-path:polygon(0% 60%, 100% 40%, 100% 100%, 0% 100%);
          clip-path:polygon(0% 60%, 100% 40%, 100% 100%, 0% 100%);
  background:#262729 url('http://i.imgur.com/LxTJ685.png');
}
<div></div>