Background SVG technique? - html

To create background patterns (triangle, trapezoid, etc.) I see a lot of devs relying on SVGs.
Today, I came across a technique that I don't quite understand.
By scaling a shape like this:
and applying height: 100% as well as transform-origin a triangle is created. The start-point of the triangle is always the lower-left corner of the containing element. The result is nice and responsive, but I have no idea why this works from a geometric perspective.
I created a Codepen to demonstrate.
.shape {
position: absolute;
width: 100%;
}
.shape-img {
padding-bottom: 10rem;
overflow: hidden;
background: yellow;
position: inherit;
width: inherit;
}
.shape-img > svg {
position: inherit;
height: 100%;
width: inherit;
transform: scale(2);
transform-origin: top center;
}
.position-relative {
position: relative;
}
<div class="position-relative">
<div class="shape">
<div class="shape shape-img">
<svg viewBox="0 0 100 50" preserveAspectRatio="none"><path d="M0 25h25L75 0h25v50H0z" fill="currentColor"></path></svg>
</div>
</div>
</div>
<br />
<br />
<!--
<svg viewBox="0 0 100 50" preserveAspectRatio="none"><path d="M0 25h25L75 0h25v50H0z" fill="currentColor"></path></svg>
-->
1. How does this approach ensure that the lower-left corner the bottom of the containing element?
2. How does this approach ensure that the user sees a triangle shape regardless of the screen-size?

Here is an easier idea with the same SVG and only one div:
.box {
height:200px;
background:
url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 50" preserveAspectRatio="none"><path d="M0 25h25L75 0h25v50H0z" fill="currentColor"></path></svg>')
top/ /* place it at the top center (no need "center" because it's by default) */
200% 200%, /* width height (twice bigger as the container*/
yellow; /* background color */
}
<div class="box"></div>
To understand the scale effect see the below:
.box {
border:5px solid red;
margin:50px auto;
width:200px;
height:100px;
position:relative;
}
.box svg {
position:absolute;
z-index:-1;
top:0;
left:0;
width:100%;
height:100%;
transform:scale(2);
transform-origin:top center;
}
<div class="box">
<svg viewBox="0 0 100 50" preserveAspectRatio="none"><path d="M0 25h25L75 0h25v50H0z" fill="currentColor"></path></svg>
</div>
By the way, you can use an easier SVG where you have only a triangle shape:
.box {
height:200px;
background:
url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1 1" preserveAspectRatio="none"><polygon points="0,1 1,0 1,1" fill="black"/></svg>'),
yellow;
}
<div class="box"></div>

Related

How to overlap image half way with container like example shown

I'm trying to create this view but I'm not sure how to get the image to overlap half way with the black background. I've got an svg with the full wide graphic of the car and line where the line breaks in color.
I'm using Bulma as a framework. How would I get the image to overlap a black container as well as the white container?
Here's an example of what I've got now: https://codesandbox.io/s/bulma-autocomplete-forked-kdu4h?file=/src/index.js
To make the img responsive you want it to keep its aspect ratio while filling the same width as the black element but you want it to be translated up enough that the break between the white and the black line always stays at the top of the container.
This snippet does that by having the img as a child of the black element and the same width as it but translated upwards by just the right % of its height that the black line starts just above the black element. This is almost at 50% of its height, actually just very slightly more.
body {
margin: 0;
padding: 0;
width: 100vw;
height: 100vh;
}
div {
width: 100vw;
height: 50vh;
margin: 0;
padding: 0;
position: relative;
top: 40%; /* just for this demo */
background-color: black;
}
img {
width: 100%;
height: auto;
transform: translateY(-52.5%);
margin: 0;
padding: 0;
position: absolute;
}
<div>
<img src="https://i.stack.imgur.com/mhA4r.png" />
</div>
You could have a svg wave with 2 colors like so
body {
background-color: teal;
}
<svg id="wave" width="740" height="110" viewBox="0 0 740 110" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1 61.4997C243.5 -30.5003 306.5 2.9997 367 48.9997C427.5 94.9997 592.5 142.999 737 61.4997" stroke="black" stroke-width="5"/>
<path d="M1 63.6579C244.159 -28.917 307.33 4.79235 367.995 51.0798C428.659 97.3672 594.107 145.667 739 63.6579" stroke="white" stroke-width="3"/>
</svg>
Then put that down of you top container
.block {
height: 150px;
width: 100%;
}
.black {
background-color: black;
position: relative;
}
#wave {
float:left;
transform: translatey(-50%);
}
<div class="block black"></div>
<svg id="wave" viewBox="0 0 740 110" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1 61.4997C243.5 -30.5003 306.5 2.9997 367 48.9997C427.5 94.9997 592.5 142.999 737 61.4997" stroke="black" stroke-width="5"/>
<path d="M1 63.6579C244.159 -28.917 307.33 4.79235 367.995 51.0798C428.659 97.3672 594.107 145.667 739 63.6579" stroke="white" stroke-width="3"/>
</svg>
<div class="block white"></div>

SVG to make a wave effect border and allow it to stretch horizontally only

I have used https://getwaves.io/ to create a wave SVG.
So I have added this svg to my header element:
.page{
height:400px;
width:100%;
background: green;
}
.pls-sticky-header{
position: relative;
height: 150px;
background-color: red;
}
.wave{
position: absolute;
bottom: 0;
left: 0;
width: 100%;
}
<div class="page">
<div class="pls-sticky-header">
<svg viewBox="0 0 1440 200" class="wave">
<path fill="#ffffff" fill-opacity="1" d="M0,128L40,117.3C80,107,160,85,240,90.7C320,96,400,128,480,154.7C560,181,640,203,720,192C800,181,880,139,960,106.7C1040,75,1120,53,1200,58.7C1280,64,1360,96,1400,112L1440,128L1440,320L1400,320C1360,320,1280,320,1200,320C1120,320,1040,320,960,320C880,320,800,320,720,320C640,320,560,320,480,320C400,320,320,320,240,320C160,320,80,320,40,320L0,320Z"></path>
</svg>
</div>
<div class="content"></div>
</div>
```
Currently as the window gets larger in size - waves get more space in height - but I don't want such behavior.
I want to make waves get 30% of the header in height, and 100% of width (make them stretch only horizontally), but I'm struggling with it.
Maybe there is an option to make such border for a DIV vlock if it not possible to achieve using SVG.
Simply add preserveAspectRatio="none"
.page {
height: 400px;
width: 100%;
background: green;
}
.pls-sticky-header {
position: relative;
height: 150px;
background-color: red;
}
.wave {
position: absolute;
bottom: 0;
height:30%;
left: 0;
width: 100%;
}
<div class="page">
<div class="pls-sticky-header">
<svg viewBox="0 0 1440 200" class="wave" preserveAspectRatio="none">
<path fill="#ffffff" fill-opacity="1" d="M0,128L40,117.3C80,107,160,85,240,90.7C320,96,400,128,480,154.7C560,181,640,203,720,192C800,181,880,139,960,106.7C1040,75,1120,53,1200,58.7C1280,64,1360,96,1400,112L1440,128L1440,320L1400,320C1360,320,1280,320,1200,320C1120,320,1040,320,960,320C880,320,800,320,720,320C640,320,560,320,480,320C400,320,320,320,240,320C160,320,80,320,40,320L0,320Z"></path>
</svg>
</div>
<div class="content"></div>
You can give a height attribute to the svg. Right now it is modifying the height to match the width. Don't use percentages for the height. because it will change with screen size.

Make one side of svg rounded

I want to make one side of my svg to be rounded.
I have svg below and I want to rounded this part:
How can I do this?
My svg size must be 100% of it's container.
.wrapper {
width: 100%;
height: 500px;
}
svg {
height: 100%;
width: 100%;
}
polygon {
fill: black;
}
<div class="wrapper">
<svg viewBox="0 0 40 100" preserveAspectRatio="none">
<polygon points="10,0 40,0 40,100 10,80"/>
</svg>
</div>
skew transformation with border radius can easily do this:
.wrapper {
height: 500px;
position:relative;
overflow:auto;
margin:20px;
}
.wrapper:before {
content:"";
position:absolute;
top:0;
left:0;
right:0;
bottom:0;
transform-origin:right;
transform:skewY(10deg);
background:black;
border-bottom-left-radius:50px;
}
<div class="wrapper">
</div>
If you create SVG-file, then use a graphical editor.
If you create the element in CSS, then:
border-top-left-radius: 60px 100%; // no slash on individual radius properties, mix-and-match with pixel and percent measures
border-top-right-radius: 10% 40%; // border will sometimes reflow to fit curve
border-bottom-left-radius: 300px 100px; // radius measurements larger than the shape itself can be declared
border-bottom-right-radius: 10%; // you can mix and match with regular radius statements

How to create this shape (quadilateral with rounded corners) in CSS?

I am building a widget in React Js, and in the design, this image is in the background.
My problem is the background color is dynamic and the width and height may change according to the devices. I tried using inline SVG(I can control fill color in this way but not the size) and also SVG inside img tag (I can control size in this way but not the color), but I cannot control both color and size.
Edit - inline SVG code snippet -
<svg width="360" height="349" viewBox="0 0 300 349" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M0 20C0 8.9543 8.95431 0 20 0H280C291.046 0 300 8.95431 300 20V187.023C300 194.606 295.711 201.537 288.925 204.921L0 349V20Z" fill="#5795fa"></path></svg>
I tried changing that widht, but the svg is created for that particular width, so it's not changing.
It will be great if someone can help me to create this shape using CSS or any other way in which I can control both color and size.
Any help is appreciated.
Here is my solution
You can change outer width as to check (Responsive).
.outer {
width: 300px;
}
.upper-box {
width: 100%;
height: 150px;
background: blue;
border-radius: 15px 15px 15px 0;
}
.lower-box {
width: calc(100% - 12px);
height: 110px;
background: linear-gradient(to bottom right, blue 50%, transparent 50%);
}
<div class="outer">
<div class="upper-box"></div>
<div class="lower-box"></div>
</div>
Just remove width, height and fill attributes and use css:
svg {
width: 360px;
fill: #5795fa;
}
<svg viewBox="0 0 300 349" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M0 20C0 8.9543 8.95431 0 20 0H280C291.046 0 300 8.95431 300 20V187.023C300 194.606 295.711 201.537 288.925 204.921L0 349V20Z"></path></svg>
Here is a different idea using pseudo element where you only need to adjust the width/height of the main element to control the size:
.box {
width:150px;
height:200px;
border-radius:10px 10px 10px 0;
overflow:hidden;
position:relative;
}
.box::before {
content:"";
position:absolute;
top:0;
left:0;
right:0;
bottom:0;
background:lightblue;
transform:skewY(-25deg);
transform-origin:left;
border-bottom-right-radius:inherit;
}
<div class="box">
</div>
If you want to control the color from the main element you can consider gradient:
.box {
width:150px;
height:200px;
display:inline-block;
border-radius:10px 10px 10px 0;
overflow:hidden;
position:relative;
background-size:0 0;
}
.box::before {
content:"";
position:absolute;
top:0;
left:0;
right:0;
bottom:0;
background-image:inherit;
transform:skewY(-25deg);
transform-origin:left;
border-bottom-right-radius:inherit;
}
<div class="box" style="background-image:linear-gradient(red,red)">
</div>
<div class="box" style="background-image:linear-gradient(green,green)">
</div>
Or CSS variables:
.box {
width:150px;
height:200px;
display:inline-block;
border-radius:10px 10px 10px 0;
overflow:hidden;
position:relative;
}
.box::before {
content:"";
position:absolute;
top:0;
left:0;
right:0;
bottom:0;
background:var(--c);
transform:skewY(-25deg);
transform-origin:left;
border-bottom-right-radius:inherit;
}
<div class="box" style="--c:red">
</div>
<div class="box" style="--c:green">
</div>
I will prefer to wrap this svg into a block <div> element, casue you use the viewBox attribute in this svg it will grow or shrink proportionaly.
Take a look on this code snap:
<div class="wrap">
<svg viewBox="0 0 300 349" xmlns="http://www.w3.org/2000/svg">
<path class="path" fill-rule="evenodd" clip-rule="evenodd"
d="M0 20C0 8.9543 8.95431 0 20 0H280C291.046 0 300 8.95431 300 20V187.023C300 194.606 295.711 201.537 288.925 204.921L0 349V20Z"></path>
</svg>
</div>
I remove the svg's width and height attribute, and removed path's fill attribute and assign a class attribute so that you can change wraper's size and path color by:
.wrap {
width: 500px; /* the height will proportionaly grow or shrink complied with the viewBox */
}
.path {
fill: red; /* specify the color as you wish */
}
Here below is the css shap, not perfect but very close to that svg:
.box {
width: 300px;
height: 200px;
background-color: #5795fa;
border-top-left-radius: 20px;
border-top-right-radius: 20px;
border-bottom-left-radius: 0px;
border-bottom-right-radius: 0px;
position: relative;
}
.box::after {
content: " ";
display: block;
position: absolute;
left: 0px;
top: 100%;
height: 0;
border-top: 30px solid #5795fa;
border-left: 150px solid #5795fa;
border-bottom: 30px solid transparent;
border-right: 150px solid transparent;
}
<div class="box"></div>

How to scale a polygon svg with an image fill to the container's height?

I'd like to scale an SVG with a polygon shape to the full height of the container. Setting the SVG's height to 100% wouldn't work.
Relevant jsFiddle: https://jsfiddle.net/12yktprj/
Following line is causing me trouble:
aside svg {
height: 100%; /* somehow not working */
width: 100%; /* somehow not working */
}
The svg element need to have a viewBox attribute and no width and height. For the viewBox attribute I'm taking the size of the polygon.
Also in this case (flex-direction:row - the default) instead of declaring the width of the flex items I'm declaring the [flex property]
The aside has position:relative; and the svg has position:absolute; and overflows the aside. I hope this is what you were asking.
(https://developer.mozilla.org/en-US/docs/Web/CSS/flex)
*{padding:0,margin:0}
body {
height: 300px;
width: 900px;
border: 3px solid green;
padding: 0;
display: flex;
justify-content: space-between;
align-items: stretch;
position:relative;
background:#ddd;
}
aside {
position:relative;
flex: 1 1 25%;
height: 100%;
border: 1px solid blue;
}
aside svg {
position:absolute;
height:100%
}
article {
border: 2px solid orange;
flex: 1 1 75%;
height: 100%;
padding: 2px;
}
<body>
<aside>
<svg viewBox="0 0 100 100">
<defs>
<pattern id="pattern1" height="100%" width="100%" patternContentUnits="objectBoundingBox">
<image height="1" preserveAspectRatio="slice" xlink:href="https://i.imgur.com/8OtgM8B.jpg" />
</pattern>
</defs>
<polygon fill="url(#pattern1)" points="0,0 70,0 100,100 0,100"/>
</svg>
</aside>
<article>
<h1>Title</h1>
<p>Sample Text</p>
</article>
</body>