I need to create something like the image below:
Where:
header
for exampleIt would be very easy, to just create the black element with some :pseudo-elements
, however that pattern on top of it has brought the whole thing to a standstill.
I've been reading about clip-path
prop. but I'm not sure I would be able to create a complex clip like this one (or maybe it seems complex to me).
The whole thing will be used on a iOS app, and so far it seems this clip-path property would be compatible with it.
Another thing to mention, the black element will have a fixed height, but has to be 100% width of its parent.
I've figured I'd get away with using svg
instead, but as it needs to be a fixed height, it seems like its distorting when its stretched.
UPDATE:
The right side has to stay the same width, I've figured maybe using a two svgs inside a <g>
tag and absolute position them, one would be fluid and the other would have a fixed width. However, I'm not sure if a filter
would cover both of them, or if the filter
can be applied at all to a <g>
tag, inside a svg
SVG sample below:
body {
background: cyan;
}
svg {
min-width: 100%;
height: 80px;
}
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 452 170" preserveAspectRatio="none">
<rect x="1" y="14" width="438" height="142" />
<path d="M0 0v170h452V0H0zM448 166H4V4h444V166z" />
<rect y="14" width="438" height="142" />
</svg>
Any tips or pointers are much appreciated!
SVG images can be used as background-image in CSS as well, just like PNG, JPG, or GIF. All the same awesomeness of SVG comes along for the ride, like flexibility while retaining sharpness. Plus you can do anything a raster graphic can do, like repeat.
The clip-path property is used to specify a clipping path that is to be applied to an element. Using clip-path , you can apply an SVG <clipPath> to an element by referencing that path in the property value. You can also define a clipping path using one of the basic shapes defined in the CSS Shapes module.
Scaling the clip-path The simplest way to do this is to go back to our image editing software and resize our SVG to have a maximum width/height of 1px . Here's the same SVG we saw earlier, resized. The 1px dot may be difficult to see but, most importantly, the values are all between 0 and 1 .
May be it would be a better solution go with masking ?
#test {
font-size: 100px;
position: relative;
display: inline-block;
margin: 40px;
}
#test:after {
content: "";
position: absolute;
left: 0px;
right: 0px;
top: 0px;
bottom: 0px;
z-index: -1;
background: repeating-linear-gradient(45deg, lightblue, tomato 100px);
-webkit-mask-image: linear-gradient(red, red),
linear-gradient(red, red),
linear-gradient(red, red),
linear-gradient(red, red),
linear-gradient(red, red),
linear-gradient(transparent, transparent);
-webkit-mask-size: 5% 100%, 5% 100%, 100% 5%, 100% 5%, 80% 80%;
-webkit-mask-position: left top, right top, center top, center bottom, center center ;
-webkit-mask-repeat: no-repeat;
}
body {
background-color: lightgreen;
}
<div id="test">Transparent frame</div>
replace the dimensions of the width of the borders with a fixed value in pixels. Use calc for the inner rectangle.
body, html {
width: 90%;
position: relative;
}
#test {
font-size: 100px;
position: relative;
display: inline-block;
margin: 40px;
width: 100%;
height: 40%;
}
#test:after {
content: "";
position: absolute;
left: 0px;
right: 0px;
top: 0px;
bottom: 0px;
z-index: -1;
background: repeating-linear-gradient(45deg, lightblue, tomato 100px);
-webkit-mask-image: linear-gradient(red, red),
linear-gradient(red, red),
linear-gradient(red, red),
linear-gradient(red, red),
linear-gradient(red, red),
linear-gradient(transparent, transparent);
-webkit-mask-size: 10px 100%, 10px 100%, 100% 10px, 100% 10px, calc(100% - 40px) calc(100% - 40px);
-webkit-mask-position: left top, right top, center top, center bottom, center center ;
-webkit-mask-repeat: no-repeat;
}
body {
background-color: lightgreen;
}
<div id="test">Transparent frame</div>
#test {
font-size: 100px;
position: relative;
display: inline-block;
margin: 40px;
border-radius: 50%;
}
#test:after {
content: "";
position: absolute;
left: 0px;
right: 0px;
top: 0px;
bottom: 0px;
z-index: -1;
border-radius: 50%;
background: repeating-linear-gradient(45deg, lightblue, tomato 100px);
-webkit-mask-image: radial-gradient(ellipse, red 55%, transparent 56%, transparent 65%, red 66%);
}
body {
background: lightgreen;
}
<div id="test">Transparent frame</div>
This can be achieved by making use of the approach described by Ana in this CSS Tricks article.
Using CSS Clip-path:
All we need to do is use a polygon
for clipping like in the below snippet and apply it on the container. Such a path would show the background image in the gap between the outermost box and the middle box, hide or clip the background image between the middle box and the innermost box.
div {
height: 200px;
width: 100%;
background: url(http://lorempixel.com/800/200/abstract/6);
}
#css-pattern {
-webkit-clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%, 0px 0px, 20px 20px, 20px calc(100% - 20px), calc(100% - 20px) calc(100% - 20px), calc(100% - 20px) 20px, 20px 20px, 40px 40px, 40px calc(100% - 40px), calc(100% - 40px) calc(100% - 40px), calc(100% - 40px) 40px, 40px 40px);
clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%, 0px 0px, 20px 20px, 20px calc(100% - 20px), calc(100% - 20px) calc(100% - 20px), calc(100% - 20px) 20px, 20px 20px, 40px 40px, 40px calc(100% - 40px), calc(100% - 40px) calc(100% - 40px), calc(100% - 40px) 40px, 40px 40px);
}
/* just for demo */
body {
background: radial-gradient(circle at center, aliceblue, mediumslateblue);
min-height: 100vh;
}
<h3>Pure CSS Clip-path with fixed width gap on all 4 sides</h3>
<div id='css-pattern'></div>
Using SVG Clip-path:
SVG clip-path
offers better browser support than the CSS version as it is supported by Firefox too. All we need to do is create a path
like in the below snippet and use it for clipping the container.
svg path {
fill: transparent;
stroke: black;
}
/* Just for fun */
path {
animation: draw 5s linear;
stroke-dasharray: 4450;
}
@keyframes draw {
from {
stroke-dashoffset: -4450;
}
to {
stroke-dashoffset: 0;
}
}
<svg width='600px' height='200px'>
<path d='M0,0 600,0 600,200 0,200 0,0 20,20 20,180 580,180 580,20 20,20 40,40 40,160 560,160 560,40 40,40 z' />
</svg>
SVG implementation would have been far easier if the dimensions of your container were static. Since they are not static, fraction values cannot be used as the value would differ based on the actual width of the element (whatever 100%
corresponds to). Say for example, a fraction value of 0.2 would mean 40px for a 200px wide element and would mean 80px for a 400px wide element. You can see how this affects the output in the snippet's first sample.
One way to overcome this would be to make use of JavaScript (or any other scripting library that you prefer), get the actual calculated width of the element in pixels and the calculate the coordinate values of the path's d
attribute based on it. The second sample in the below snippet uses this method.
Note: Clip-path is not supported by IE but since you are creating an iOS app, I think this should not be a major concern for you.
window.onload = function() {
setPathCoords();
};
window.onresize = function() {
setPathCoords();
};
function setPathCoords() {
var output = [],
borderWidth = '20';
var el = document.getElementById('percentage-pattern'),
path = document.querySelector('#clipper2 > path'),
origPath = 'M0,0 1,0 1,1 0,1 0,0 ';
height = el.clientHeight;
width = el.clientWidth;
for (var x = 1; x < 3; x++) {
point1 = (borderWidth * x) / width + "," + (borderWidth * x) / height;
point2 = (borderWidth * x) / width + "," + (height - (borderWidth * x)) / height;
point3 = (width - (borderWidth * x)) / width + "," + (height - (borderWidth * x)) / height;
point4 = (width - (borderWidth * x)) / width + "," + (borderWidth * x) / height;
output.push(point1);
output.push(point2);
output.push(point3);
output.push(point4);
output.push(point1);
}
document.querySelector('#clipper2 > path').setAttribute('d', origPath + output.join(' ') + 'z');
}
div {
height: 200px;
width: 100%;
background: url(http://lorempixel.com/800/200/abstract/6);
}
#percentage-pattern {
-webkit-clip-path: url(#clipper);
clip-path: url(#clipper);
}
#js-pattern {
-webkit-clip-path: url(#clipper2);
clip-path: url(#clipper2);
}
/* just for demo */
body {
background: radial-gradient(circle at center, aliceblue, mediumslateblue);
min-height: 100vh;
}
<svg width='0' height='0'>
<defs>
<clipPath id='clipper' clipPathUnits='objectBoundingBox'>
<path d='M0,0 1,0 1,1 0,1 0,0 0.1,0.1 0.1,0.9 0.9,0.9 0.9,0.1 0.1,0.1 0.2,0.2 0.2,0.8 0.8,0.8 0.8,0.2 0.2,0.2z' />
</clipPath>
<clipPath id='clipper2' clipPathUnits='objectBoundingBox'>
<path d='M0,0 1,0 1,1 0,1 0,0 ' />
</clipPath>
</defs>
</svg>
<h3>Output with JS</h3>
<div id='js-pattern'></div>
<h3>Pure SVG Clip-path</h3>
<div id='percentage-pattern'></div>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With