Reputation: 18908
I am trying to create an SVG shape that is one pattern-able path. The problem I am facing is that the ends need to have angles on them, and the elements need to be responsive (the angles remain the same, but the length of the element changes).
I originally went at this with just HTML, and CSS, but the angles have to be created with before and after elements which means that there is no way to get the patterns to line up. Hence, why I'm looking for an SVG solution.
Here is what the elements will look like:
My closest attempt is a rect
element that had a clip-path
reference that was using path. The problem is that the element has to be responsive, but the path cannot be positioned at the "far right".
I do have d3 available to me, but am unsure if that alleviates the complexity. How can I create this responsive patterned shape?
Upvotes: 2
Views: 1317
Reputation: 21725
Here's a HTML/CSS solution.
What we do is transform
(support) two elements with skew()
to create the pointed ends. Below you can see the red parent DIV creates one side of the point and the child element creates the other side by skewing in the opposite direction. In the final solution we remove the background from the parent element.
div {
height: 25px;
transform: skew( 25deg );
overflow: hidden;
position: relative;
background-color: indianred;
}
div:before {
content: '';
display: block;
height: 100%;
background-color: rebeccapurple;
transform: skew( -42deg );
}
<div></div>
Then we use a repeating lindear gradient
(support) to create the angled pinstripes.
div {
height: 25px;
transform: skew( 25deg );
overflow: hidden;
position: relative;
}
div:before {
content: '';
display: block;
height: 100%;
background: repeating-linear-gradient(
35deg,
transparent,
transparent 3px,
lightgray 3px,
lightgray 6px
);;
transform: skew( -42deg );
}
<div></div>
Upvotes: 1
Reputation: 101918
It's possible to do this in SVG using a trick with the <use>
element.
<svg width="100%" height="50px">
<defs>
<pattern id="stripes" patternUnits="userSpaceOnUse" width="50" height="50">
<path d="M-10,20 L20,-10
M-10,45 L45,-10
M0,60 L60,0
M25,60 L60,25" fill="none" stroke="lightgrey" stroke-width="10"/>
</pattern>
<clipPath id="leftarrow">
<path d="M15,0 L0,25,15,50,5000,50,5000,0 Z"/>
</clipPath>
<path id="rightarrowpath" d="M-15,0 L0,25,-15,50,-5000,50,-5000,0 Z"/>
<clipPath id="rightarrow">
<use xlink:href="#rightarrowpath" x="100%"/>
</clipPath>
</defs>
<g clip-path="url(#leftarrow)">
<rect width="100%" height="50" fill="url(#stripes)"
clip-path="url(#rightarrow)"/>
</g>
</svg>
How this works
First we define our SVG to be 100% width so it fills the container. We add a rectangle that is the same size (100% x 50px). The SVG doesn't have a viewBox
since we do not want any stretching going on.
Now we need to clip the rectangle into left and right arrow shapes. A left arrow is easy, since we can just define a really wide clipping path with the arrow part at x=0
. As long as it is wide enough, it should be fine.
<svg width="100%" height="50px">
<defs>
<pattern id="stripes" patternUnits="userSpaceOnUse" width="50" height="50">
<path d="M-10,20 L20,-10
M-10,45 L45,-10
M0,60 L60,0
M25,60 L60,25" fill="none" stroke="lightgrey" stroke-width="10"/>
</pattern>
<clipPath id="leftarrow">
<path d="M15,0 L0,25,15,50,5000,50,5000,0 Z"/>
</clipPath>
</defs>
<rect width="100%" height="50" fill="url(#stripes)"
clip-path="url(#leftarrow)"/>
</svg>
Unfortunately, the right hand arrow is not as straight forward. The reason is that we want the arrow to be positioned automatically at the right hand side of the SVG (ie. at 100% width). But <path>
definitions don't allow percentages. And we can't use a transform
to get it there either because you can't use percentages in transforms either.
Luckily there is a "loophole" technique. The <use>
element allows us to supply an offset (x
and y
) at which to position the element it references. And those attributes do allow percentages.
So what we do is define the right-arrow clip path to have its right hand edge at x=0, then we use a <use>
element to position it at 100%.
<svg width="100%" height="50px">
<defs>
<pattern id="stripes" patternUnits="userSpaceOnUse" width="50" height="50">
<path d="M-10,20 L20,-10
M-10,45 L45,-10
M0,60 L60,0
M25,60 L60,25" fill="none" stroke="lightgrey" stroke-width="10"/>
</pattern>
<path id="rightarrowpath" d="M-15,0 L0,25,-15,50,-5000,50,-5000,0 Z"/>
<clipPath id="rightarrow">
<use xlink:href="#rightarrowpath" x="100%"/>
</clipPath>
</defs>
<rect width="100%" height="50" fill="url(#stripes)"
clip-path="url(#rightarrow)"/>
</svg>
All we need to do is combine those two techniques to get our double-ended (and responsive) patterned arrow. However, since the rectangle can't have two clipping paths, we have to wrap it in a group, and apply one of the clipping paths to that.
The final result is the example at the top of this answer.
Upvotes: 4