Make one side of svg rounded - html

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

Related

Background SVG technique?

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>

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>

centering an SVG inside a div

I want to display an SVG image inside a position:fixed div. I have
<div class="main">
<svg class="svg" viewBox="0 0 180 100">
<rect height="100%" width="100%" fill="#003300"></rect>
</svg>
</div>
and style
.main {
position:fixed;
left: 100px;
height: 100%;
width:100%;
background: #33AAAA;
}
.svg {
display: block;
height: 100%;
width: 100%;
position:static;
}
I want to center the SVG horizontally and vertically. I get a strange behavior. Changing the size of the browser window, shows that when the svg is smaller than available width, it is weirdly placed. For example: there is more space on the left than on the right.
Codepen (including CSS reset): Codepen
You are setting the width to 100%, then shifting it over by 100px. The width is still calculated as whatever the 100% width is. To center it the way you want, you will need to subtract 100px from the width or nest things differently.
.main {
position:fixed;
left:100px;
height: 100%;
width:calc(100% - 100px);
background: #33AAAA;
}
It looks like its because you have the left: 100px in your main class. If you take that out it centers correctly.
here is the main class that should work:
.main {
position:fixed;
left:100px;
height: 100%;
right: 0;
top:0;
bottom:0;
background: #33AAAA;
}

CSS triangle to fit variable sized div elements

Please refer to my fiddle. I was aiming to create a triangle (to be placed inside a div), and make it fit exactly (corner to corner).
Here are the rules outlined:
Place the triangle inside all the div elements.
The bottom left corner of the triangle should fit the bottom left corner inside all the divs.
The top right corner of the triangle should fit the top right corner inside all the divs.
The divs has fixed width and height BUT in real life they are all unknown, inherited from a parent.
The angle of the diagonal will be different for every div but that is ok.
Use borders, gradients, transform or SVG to solve the problem. I would not like to use fixed pixel solutions like canvas or PNG.
.one {
width: 100px;
/* Unknown */
height: 30px;
/* Unknown */
background: #ccc;
}
.two {
width: 40px;
/* Unknown */
height: 90px;
/* Unknown */
background: #aaa;
}
.three {
width: 70px;
/* Unknown */
height: 70px;
/* Unknown */
background: #aaa;
}
.triangle {
width: 0;
height: 0;
border-style: solid;
border-width: 0 0 50px 50px;
border-color: transparent transparent #007bff transparent;
}
<div class="one"></div>
<br>
<div class="two"></div>
<br>
<div class="three"></div>
<br>
<div class="triangle"></div>
JSFiddle Reference
Achieving this effect with border will not be possible for dynamically sized containers because they cannot take percentage values or adapt based on a change in dimension of the container. They can only use either pixel or viewport units. Both those wouldn't be of much use for a dynamic container.
Transforms can be used by placing a pseudo-element on top of the containers but they would need calculations for height and width of the element based on trigonometric equations. The simpler ones would be the gradient and SVG approaches.
Using Gradient:
You can do this using a gradient with to [side] [side] syntax. This is responsive and would work for all container sizes. The only drawback is that there would be jagged lines in some cases where the width or height is too large compared to the other.
One advantage of this is that it doesn't require any extra elements (SVG or HTML, not even pseudos) but the drawback will be when hover and click effects are required for the triangle alone (restricted to the triangle's boundaries). Since the element is still a rectangle/square, the hover or click effect will be triggered even when the mouse is outside the triangle but within the container.
.one {
width: 100px;
height: 30px;
background-color: #ccc;
}
.two {
width: 40px;
height: 90px;
background-color: #aaa;
}
.three {
width: 70px;
height: 70px;
background-color: #aaa;
}
div {
background-image: linear-gradient(to top left, blue 50%, transparent 51%);
}
<div class="one"></div>
<br>
<div class="two"></div>
<br>
<div class="three"></div>
<br>
Using SVG:
You could also do it with SVG path element like in the below snippet. The SVG has to be positioned absolutely with respect to the container and have 100% of the parent's width and height.
The advantage of using SVG for the triangle over gradients is that hover and click effects can be added to the triangle alone.
.one {
width: 100px;
height: 30px;
background-color: #ccc;
}
.two {
width: 40px;
height: 90px;
background-color: #aaa;
}
.three {
width: 70px;
height: 70px;
background-color: #aaa;
}
div{
position: relative;
}
div > svg {
position: absolute;
height: 100%;
width: 100%;
}
svg path{
fill: #0007bf;
}
svg path:hover{
fill: crimson;
}
<div class="one">
<svg viewBox='0 0 100 100' preserveAspectRatio='none'>
<path d='M100,0 L100,100 0,100z' />
</svg>
</div>
<br>
<div class="two">
<svg viewBox='0 0 100 100' preserveAspectRatio='none'>
<path d='M100,0 L100,100 0,100z' />
</svg>
</div>
<br>
<div class="three">
<svg viewBox='0 0 100 100' preserveAspectRatio='none'>
<path d='M100,0 L100,100 0,100z' />
</svg>
</div>
<br>
in gradient
style
.triangle {
width: 100%;
height: 100%;
background: linear-gradient(to bottom right, rgba(0,0,0,0) 0%, rgba(0,0,0,0) 50%, #007bff 50%, #007bff 100%)
}
html
<div class="one">
<div class="triangle"></div>
</div><br>
<div class="two">
<div class="triangle"></div>
</div><br>
<div class="three">
<div class="triangle"></div>
</div>

CSS: make div width proportional to height

This is a little tricky to explain, but: I want a responsive-height div (height: 100%) that will scale the width proportional to the height (not vice versa).
I know of this method utilising a padding-top hack to make the height proportional to the width, but I need it to work the other way around. Having said that, I'm not hugely keen on the additional requirement of absolutely-positioned elements for the content in that method, so I realise I may well be asking for the moon on a stick here.
To help visualise, here is an image:
...and here is a jsFiddle, illustrating pretty much the same thing.
It is worth noting that I am already using the :before and :after pseudo-elements to vertically-align the content of the box I want to scale proportionally.
I would really enjoy not having to revert to jQuery, just because there's going to be an inherent requirement for resize handlers and generally more debugging all round... but if that's my only choice, then fiat.
I've been wondering about a pure-css solution to this problem for a while. I finally came up with a solution using ems, which can be progressively enhanced using vws:
See codepen link for full working demo and explanation:
http://codepen.io/patrickkunka/pen/yxugb
Simplified version:
.parent {
font-size: 250px; // height of container
height: 1em;
}
.child {
height: 100%;
width: 1em; // 100% of height
}
Oh,you could probably use that "padding-top" trick.
width: 50%;
height: 0;
padding-bottom: 50%;
http://absolide.tumblr.com/post/7317210512/full-css-fluid-squares
Or:
.square-box{
position: relative;
width: 50%;
overflow: hidden;
background: #4679BD;
}
.square-box:before{
content: "";
display: block;
padding-top: 100%;
}
http://codeitdown.com/css-square-rectangle/
The vertical padding in CSS is related to the width of the element, not the height.
The font solution requires that the height is known. I have found a solution for making an element proportional inside a parent div with unknown widths and heights. Here is a demo.
The trick I'm using is to have an image used as a spacer. The code explained:
<div class="heightLimit">
<img width="2048" height="2048" class="spacer"
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAA
P///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7">
<div class="filler">
<div class="proportional">
</div>
</div>
</div>
So it is not the prettiest with two extra divs and a useless image. But it could be worse. The image element needs to have width and height with the desired dimensions. Width and height need to be as large as the maximum size allowed (a feature!).
The css:
.heightLimit {
position: absolute;
top: 0;
left: 0;
height: 100%;
width: auto;
max-width: 100%;
overflow: hidden;
}
This element is to limit the height, but to expand horizontally (width: auto) although never beyond the parent (max-width). Overflow needs to be hidden because some children will protrude outside the div.
.spacer {
width: auto;
max-height: 100%;
visibility: hidden;
}
This image is invisible and scaled proportionally to the height, while the width is adjusted and forces the width of the parent to also be adjusted.
.filler {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
}
This element is required to fill the space with an absolutely positioned container.
.proportional {
position: relative;
width: 100%;
height: 0;
padding-bottom: 100%;
}
And here our proportional element gets a height proportional to the width with the familiar padding-bottom trick.
Unfortunately, there is a bug in Chrome and IE so if you modify the parent element using Javascript, such as in my demo, the dimensions will not be updated. There is a hack that can be applied to solve that, as shown in my demo.
You can use view height (vh) as the unity for the width.
Here is an example with the 20px margin you asked for.
.parent {
margin : 20px;
}
.child {
width: calc(100vh - 40px);
height : calc(100vh - 40px);
margin:0 auto;
background: red;
box-sizing:border-box;
padding:10px;
}
See the fiddle :
https://jsfiddle.net/svobczp4/
Based off of #kunkalabs's answer (which is really smart) I've come up with a solution that lets you preserve the inherited font-size.
HTML:
<div id='rect'>
<div id='content'>Text</div>
</div>
CSS:
#rect {
font-size: 1000%;
height: 1em;
width: 1em;
position: relative;
}
#content {
font-size: 10%;
}
So basically the font-size of #content is (100 / $rectFontSize) * 100 percent of the rectangle. If you need a definite pixel size for the rectangle, you can set the #rect's parent's font-size…otherwise just adjust the font-size until it's about where you want it to be (and enrage your designer in the process).
You can achieve that by using SVG.
It depends on a case, but in some it is really usefull. As an example - you can set background-image without setting fixed height or use it to embed <iframe> with ratio 16:9 and position:absolute.
For 3:2 ratio set viewBox="0 0 3 2" and so on.
Example:
div{width:35%;background-color:red}
svg{width:100%;display:block;visibility:hidden}
<div>
<svg viewBox="0 0 3 2"></svg>
</div>
On newer browsers, we can use aspect-ratio with a fixed height, and the width will be calculated accordingly.
img {
aspect-ratio: 1.2;
height: 250px;
max-width: 500px;
}
But the browser support for aspect-ratio is not good enough. I liked the SVG solution proposed by #Jakub Muda, except for the fact that it requires modifying the markup. I have moved the SVG to CSS by including it using content property. On newer browsers, it disables the SVG hack and switches to aspect-ratio property.
document.querySelector('.nav').addEventListener('click', function(e) {
var index = parseInt(e.target.dataset.index);
if (!index) {
return;
}
var elements = document.querySelectorAll('.box');
for (var i = elements.length; i > 0; i--) {
elements[i - 1].classList.toggle('hide', i !== index);
}
});
.wrapper {
max-width: 500px;
margin: 0 auto;
width: 100%;
height: 250px;
text-align: center;
background: green;
}
.box {
display: inline-flex;
position: relative;
max-width: 100%;
}
/* SVG Hack */
.box::before {
display: block;
line-height: 0;
max-width: 100%;
content: 'test';
}
[data-aspect-ratio="1"]::before {
content: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1 1' height='250'></svg>");
}
[data-aspect-ratio="2"]::before {
content: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 2 1' height='250'></svg>");
}
[data-aspect-ratio="3"]::before {
content: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 3 1' height='250'></svg>");
}
#supports (aspect-ratio1: 1) {
/* Modern browsers */
.box {
height: 100%;
background: green;
}
.box::before {
display: none;
}
[data-aspect-ratio="1"] {
aspect-ratio: 1;
}
[data-aspect-ratio="2"] {
aspect-ratio: 2;
}
[data-aspect-ratio="3"] {
aspect-ratio: 2;
}
}
.content {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
.content>svg {
display: block;
width: 100%;
position: absolute;
top: 50%;
left: 50%;
height: auto;
transform: translate(-50%, -50%);
}
.nav {
text-align: center;
}
.hide {
display: none;
}
<!doctype html>
<html lang="en">
<head>
<title>Width proportional to height in CSS</title>
</head>
<body>
<div class="wrapper">
<div class="box" data-aspect-ratio="1">
<div class="content">
<svg viewBox="0 0 100 100" width="100" height="100" xmlns="http://www.w3.org/2000/svg"><rect x="2" y="2" width="96" height="96" style="fill:#DEDEDE;stroke:#555555;stroke-width:2"/><text x="50%" y="50%" font-size="18" text-anchor="middle" alignment-baseline="middle" font-family="monospace, sans-serif" fill="#555555">100×100</text></svg>
</div>
</div>
<div class="box hide" data-aspect-ratio="2">
<div class="content">
<svg viewBox="0 0 200 100" width="200" height="100" xmlns="http://www.w3.org/2000/svg"><rect x="2" y="2" width="196" height="96" style="fill:#DEDEDE;stroke:#555555;stroke-width:2"/><text x="50%" y="50%" font-size="18" text-anchor="middle" alignment-baseline="middle" font-family="monospace, sans-serif" fill="#555555">200×100</text></svg>
</div>
</div>
<div class="box hide" data-aspect-ratio="3">
<div class="content">
<svg viewBox="0 0 300 100" width="300" height="100" xmlns="http://www.w3.org/2000/svg"><rect x="2" y="2" width="296" height="96" style="fill:#DEDEDE;stroke:#555555;stroke-width:2"/><text x="50%" y="50%" font-size="18" text-anchor="middle" alignment-baseline="middle" font-family="monospace, sans-serif" fill="#555555">300×100</text></svg>
</div>
</div>
</div>
<div class="nav">
<button data-index="1">1</button>
<button data-index="2">2</button>
<button data-index="3">3</button>
</div>
</body>
</html>
Make the parent DIV behave like a table cell and align the child element vertically. No need to do any padding tricks.
HTML
<div class="parent">
<img src="foo.jpg" />
</div>
CSS
.parent { width:300px; height:300px; display:table-cell; vertical-align:middle; }