Linear Gradient with Round corners - css

I am creating a background image using linear gradients. How to to add round corners for each linear gradient.
Please provide solution without any changes in html (cant use more than one div)
.myStyle {
height:500px;
width: 900px;
background-image:
linear-gradient(lightgrey , blue),
linear-gradient(lightgrey , blue),
linear-gradient(lightgrey , blue),
linear-gradient(lightgrey , blue);
background-repeat: no-repeat;
background-size:
100px 40px,
500px 60px,
250px 50px,
250px 60px;
background-position:
0 0,
0 80px,
0 160px,
0 220px;
}
<div class="myStyle"></div>

Not really sure what is your goal but if you want gradient with solid color to have radius you can build it using multiple linear-gradient and radial gradient.
Here is an example where I am using CSS variable to easily define the position, size and radius. This is one of your gradient. You need to repeat the code for all the gradient and adjust the different values.
.box {
--w:200px; /*Gradient width*/
--h:100px; /*Gradient height*/
--r:10px; /*Gradient radius*/
--x:50px; /*Gradient position x*/
--y:40px; /*Gradient position y*/
--c:grey; /*Gradient color*/
margin:0;
height:100vh;
background:
radial-gradient(farthest-side,var(--c) 98%,transparent 100%) var(--x) var(--y) / calc(2*var(--r)) calc(2*var(--r)),
radial-gradient(farthest-side,var(--c) 98%,transparent 100%) calc(var(--x) + var(--w) - 2*var(--r)) var(--y) / calc(2*var(--r)) calc(2*var(--r)),
radial-gradient(farthest-side,var(--c) 98%,transparent 100%) var(--x) calc(var(--y) + var(--h) - 2*var(--r)) / calc(2*var(--r)) calc(2*var(--r)),
radial-gradient(farthest-side,var(--c) 98%,transparent 100%) calc(var(--x) + var(--w) - 2*var(--r)) calc(var(--y) + var(--h) - 2*var(--r)) / calc(2*var(--r)) calc(2*var(--r)),
linear-gradient(var(--c),var(--c)) calc(var(--x) + var(--r)) var(--y) / calc(var(--w) - 2*var(--r)) var(--h),
linear-gradient(var(--c),var(--c)) var(--x) calc(var(--y) + var(--r)) / var(--w) calc(var(--h) - 2*var(--r));
background-repeat:no-repeat;
width:300px;
height:200px;
display:inline-block;
border:1px solid;
}
<div class="box"></div>
<div class="box" style="--w:80px;--r:30px;--c:red;"></div>
<div class="box" style="--h:80px;--r:40px;--x:5px;--y:5px;--c:blue"></div>

The cleanest might actually be to use svg for this instead of css-gradients.
You'll load it as a data-uri in the background-image property.
To make the rounded corner, you can use the rx and ry attributes of the <rect> element.
To make the gradients, you can use svg's <linearGradient> elements.
.mystyle {
height: 900px;
width: 500px;
background-image: url("data:image/svg+xml,<svg xmlns='http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg' width='500' height='900' viewBox='0 0 500 900'><defs><linearGradient id='blue-grad' gradientTransform='rotate(90)'><stop stop-color='lightgrey' offset='0%'/><stop stop-color='blue' offset='100%'/></linearGradient></defs><rect x='0' y='0' width='100' height='40' rx='15' fill='url(%23blue-grad)'/><rect x='0' y='80' width='500' height='60' rx='15' fill='url(%23blue-grad)'/><rect x='0' y='160' width='250' height='50' rx='15' fill='url(%23blue-grad)'/><rect x='0' y='220' width='250' height='60' rx='15' fill='url(%23blue-grad)'/></svg>");
background-size: cover;
background-repeat: no-repeat;
}
/*
SVG Image unminified:
<svg xmlns="http://www.w3.org/2000/svg" width="500" height="900">
<defs>
<linearGradient id="blue-grad" gradientTransform="rotate(90)">
<stop stop-color="lightgrey" offset="0%"/>
<stop stop-color="blue" offset="100%"/>
</linearGradient>
</defs>
<rect x="0" y="0" width="100" height="40" rx="15" fill="url(#blue-grad)"/>
<rect x="0" y="80" width="500" height="60" rx="15" fill="url(#blue-grad)"/>
<rect x="0" y="160" width="250" height="50" rx="15" fill="url(#blue-grad)"/>
<rect x="0" y="220" width="250" height="60" rx="15" fill="url(#blue-grad)"/>
</svg>
*/
<div class="mystyle"></div>

Maybe try this approach instead of making one div output multiple gradient boxes?
.myStyle {
width:150px;
height:100px;
background:linear-gradient(black,purple);
border-radius:20px;
}
<div class="myStyle"></div>

Related

How to use clip-path to remove, or punch through the gradient? [duplicate]

Is it possible to create an inset circle clip path so that the clip path would effectively cut a hole through the div in the center opposed to only showing the center?
The div should all be shown apart from a hole cut out in the center to create something like this:
I would like to use clip path or something similar so that I can have stuff (images and content) behind the div and the clip path will be used to reveal this. So the div (blue div from my jsfiddle) will disappear from the center using a transition to show the content behind it.
div {
background: blue;
width: 200px;
height: 200px;
-webkit-clip-path: circle(50px at center);
}
<div></div>
https://jsfiddle.net/pm4yvbxn/
I don't think you can achieve this with clip-path but you can certainly cut a hole in a div using the radial-gradient background images. This has much better browser support than clip-path too.
Note: This approach (and box-shadow ) will work only when the element that is covering the content below has a colored fill. If instead of sandybrown color, there needs to be another image on top then these approaches will not work because they don't actually cut a hole, they just mimic that effect.
.div-with-hole {
height: 100vh;
background: radial-gradient(circle at center, transparent 25%, sandybrown 25.5%);
background-size: 100% 100%;
background-position: 50% 50%;
transition: all 2s ease;
}
.div-with-hole:hover {
background-size: 400% 400%; /* should be 100% * (100 / transparent % of radial gradient */
}
body {
background: url(http://lorempixel.com/800/800/nature/1);
min-height: 100vh;
margin: 0;
padding: 0;
}
<div class='div-with-hole'></div>
You can create hole in clip-path with this approach:
let precision = 64;
let radius = 25;
let c = [...Array(precision)].map((_, i) => {
let a = -i/(precision-1)*Math.PI*2;
let x = Math.cos(a)*radius + 50;
let y = Math.sin(a)*radius + 50;
return `${x}% ${y}%`
})
document.querySelector('div').style.clipPath =
`polygon(100% 50%, 100% 100%, 0 100%, 0 0, 100% 0, 100% 50%, ${c.join(',')})`;
div {
background: blue;
width: 200px;
height: 200px;
}
<div></div>
or symply use resulting clip string:
div {
background: blue;
width: 200px;
height: 200px;
}
<div style="clip-path: polygon(100% 50%, 100% 100%, 0px 100%, 0px 0px, 100% 0px, 100% 50%, 75% 50%, 74.8758% 47.5108%, 74.5043% 45.0463%, 73.8893% 42.6311%, 73.0369% 40.2891%, 71.9555% 38.0437%, 70.656% 35.917%, 69.1511% 33.9303%, 67.4559% 32.1033%, 65.5872% 30.4542%, 63.5637% 28.9994%, 61.4053% 27.7532%, 59.1335% 26.7282%, 56.771% 25.9344%, 54.3412% 25.3798%, 51.8683% 25.0699%, 49.3767% 25.0078%, 46.8914% 25.194%, 44.437% 25.6268%, 42.0378% 26.3018%, 39.7178% 27.2124%, 37.5% 28.3494%, 35.4064% 29.7015%, 33.4579% 31.2555%, 31.6737% 32.9957%, 30.0717% 34.9049%, 28.6677% 36.9641%, 27.4758% 39.1529%, 26.5077% 41.4495%, 25.7731% 43.8311%, 25.2792% 46.2739%, 25.0311% 48.7539%, 25.0311% 51.2461%, 25.2792% 53.7261%, 25.7731% 56.1689%, 26.5077% 58.5505%, 27.4758% 60.8471%, 28.6677% 63.0359%, 30.0717% 65.0951%, 31.6737% 67.0043%, 33.4579% 68.7445%, 35.4064% 70.2985%, 37.5% 71.6506%, 39.7178% 72.7876%, 42.0378% 73.6982%, 44.437% 74.3732%, 46.8914% 74.806%, 49.3767% 74.9922%, 51.8683% 74.9301%, 54.3412% 74.6202%, 56.771% 74.0656%, 59.1335% 73.2718%, 61.4053% 72.2468%, 63.5637% 71.0006%, 65.5872% 69.5458%, 67.4559% 67.8967%, 69.1511% 66.0697%, 70.656% 64.083%, 71.9555% 61.9563%, 73.0369% 59.7109%, 73.8893% 57.3689%, 74.5043% 54.9537%, 74.8758% 52.4892%, 75% 50%);"></div>
mask can do this and it will work with any kind of background:
div {
background: linear-gradient(blue, red);
width: 200px;
height: 200px;
-webkit-mask: radial-gradient(50px, #0000 98%, #000);
mask: radial-gradient(50px, #0000 98%, #000);
}
<div></div>
Can also be animated:
div {
background: linear-gradient(blue,red);
width: 200px;
height: 200px;
-webkit-mask:
radial-gradient(farthest-side,#000 98%,#0000) center/50px 50px no-repeat,
linear-gradient(#000 0 0);
-webkit-mask-composite:destination-out;
mask:
radial-gradient(farthest-side,#000 98%,#0000) center/50px 50px no-repeat,
linear-gradient(#000 0 0);
mask-composite:exclude;
transition:0.5s;
}
div:hover {
-webkit-mask-size:290px 290px,auto;
mask-size:290px 290px,auto;
}
<div></div>
You could also do this with box-shadow on :after pseudo-element
div {
position: relative;
width: 300px;
height: 200px;
overflow: hidden;
background: url('http://planetcompas.com/live/wp-content/uploads/2013/04/2015-01-Beautiful-Planet-And-Space-4-Cool-Wallpapers-HD.jpg');
background-size: cover;
background-position: center;
}
div:after {
width: 50px;
height: 50px;
content: '';
border-radius: 50%;
background: transparent;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
box-shadow: 0px 0px 0px 300px lightblue;
transition: all 0.3s linear;
}
div:hover:after {
opacity: 0;
}
<div></div>
SVG mask solution
A circle is used as a mask, and its radius is animated.
The animation will start after clicking on the image
<svg id="svg1" version="1.1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" width="300" height="300" viewBox="0 0 600 600" >
<defs>
<!-- Multicolor radial gradient -->
<radialGradient id="grad" x1="0" y1="0" x2="100%" y2="0">
<stop offset="10%" stop-color="#48afc1" />
<stop offset="10%" stop-color="#b4c63b" />
<stop offset="20%" stop-color="#ef5b2b" />
<stop offset="20%" stop-color="#503969" />
<stop offset="30%" stop-color="#ab6294" />
<stop offset="30%" stop-color="#1cb98f" />
<stop offset="40%" stop-color="#48afc1" />
<stop offset="40%" stop-color="#b4c63b" />
<stop offset="50%" stop-color="#ef5b2b" />
<stop offset="50%" stop-color="#503969" />
<stop offset="60%" stop-color="#ab6294" />
<stop offset="60%" stop-color="#1cb98f" />
<stop offset="70%" stop-color="#48afc1" />
<stop offset="70%" stop-color="#b4c63b" />
<stop offset="80%" stop-color="#ef5b2b" />
<stop offset="80%" stop-color="#503969" />
<stop offset="90%" stop-color="#ab6294" />
<stop offset="90%" stop-color="#1cb98f" />
<stop offset="100%" stop-color="#48afc1" />
</radialGradient>
<!-- Mask -->
<mask id="msk1" >
<rect width="100%" height="100%" fill="black" />
<circle cx="300" cy="300" r="0" fill="white" >
<!-- Animation of a mask cutting through the image of a dragon and showing a radial gradient -->
<animate attributeName="r" begin="svg1.click" dur="8s" values="0;300;300;0;0" fill="freeze" repeatCount="3" />
</circle>
</mask>
</defs>
<!-- Radial gradient background image -->
<circle cx="300" cy="300" r="300" fill="url(#grad)" />
<image xlink:href="https://i.stack.imgur.com/6kywq.png" x="-140" y="-60" mask="url(#msk1)" width="800" height="780" />
</svg>
Based on Stranger in the Q's answer I created a dynamic solution for this problem.
My method works with rem, em, px, and percent as well also uses attributes on the element.
function parseUnitsToPercent(str, divider){
var match = str.match(/^calc\((.+)\);?$/);
if(match){
var val = [...match[1].matchAll(/((?:\d(?:\.\d)?)+(?:px|rem|em|%)?)(?:\s([\+|\-|\*|\/])\s)?/g)].map(e=>e.slice(1)).flat().filter(e=>!!e);
val = val.map(e=>{
if(['+','-','*','/'].includes(e)){
return e;
}
return convertUnitsToPercent(e, divider);
});
try {
str = eval(val.join(' '));
} catch(e){
str = 0;
}
}
return convertUnitsToPercent(str, divider);
}
function convertUnitsToPercent(str, divider){
if(str.toString().endsWith('rem')) {
str = parseFloat(str) * parseFloat(getComputedStyle(document.documentElement).fontSize) + 'px';
}
if(str.toString().endsWith('em')) {
str = parseFloat(str) * parseFloat(getComputedStyle(elem).fontSize) + 'px';
}
if(str.toString().endsWith('px')) {
str = parseFloat(str)/divider*100;
}
if(str.toString().endsWith('%')) {
str = parseFloat(str);
}
return str;
}
document.querySelectorAll('[clip-x][clip-y][clip-size]').forEach(elem=>{
if(elem.getAttribute('width')) elem.style.width = elem.getAttribute('width') + 'px';
if(elem.getAttribute('height')) elem.style.height = elem.getAttribute('height') + 'px';
var x = elem.getAttribute('clip-x');
var y = elem.getAttribute('clip-y');
var size = elem.getAttribute('clip-size');
var elem_size = elem.getBoundingClientRect();
x = parseUnitsToPercent(x, elem_size.width);
y = parseUnitsToPercent(y, elem_size.height);
var radius_x = parseUnitsToPercent(size, elem_size.width);
var radius_y = parseUnitsToPercent(size, elem_size.height);
var precision = parseFloat(elem.getAttribute('clip-precision') || 64);
var c = [...Array(precision)].map((_, i) => {
var a = -i/(precision-1)*Math.PI*2;
var _x = Math.cos(a)*radius_x + x;
var _y = Math.sin(a)*radius_y + y;
return `${_x}% ${_y}%`
});
elem.style.clipPath = `polygon(100% 50%, 100% 100%, 0 100%, 0 0, 100% 0, 100% 50%, ${c.join(',')})`;
});
div {
background: blue;
}
<div clip-x="50%" clip-y="calc(50% + 20px)" clip-size="50px" clip-precision="64" width="400" height="200"></div>
I know this question is really old, but I found it really useful so I modified it for myself. I decided to share with you my result.
My code supports calc() as well (Please note: It uses eval() which makes it insecure for user-input codes!)
You can do it by adding an elements in <div>.
I have used <span>. Here is the code
HTML
<div>
<span></span>
</div>
CSS
div{
background: blue;
width: 200px;
height: 200px;
-webkit-clip-path: circle(50px at center);
position:relative;
}
div span{
position:absolute;
display:block;
width:30px;
height:30px;
border-radius:100%;
background:#fff;
top:50%;
left:50%;
transform:translate(-50%,-50%)
}
example : https://jsfiddle.net/pm4yvbxn/2/
You can also use border-radius in div for rounded borders.

Can I create a stright line having circle at both ends with Clip path CSS?

I will like to achieve something like this
I have tried using clip path, but I am struggling achieving the desired result. Any help will be appreciated
You need mask for this:
.box {
--h: 50px; /* height of the element */
--b: 60%; /* height of the bar */
width: 200px;
height: var(--h);
background: linear-gradient(90deg,red, blue);
-webkit-mask:
linear-gradient(#000 0 0)
50%/calc(100% - var(--h)) var(--b) no-repeat,
radial-gradient(calc(var(--h)/2) at calc(var(--h)/2) 50%, #000 96%, #0000)
0 50%/calc(100% - var(--h)) 100% repeat-x;
}
<div class="box"></div>
<div class="box" style="width:300px;--b:45%;"></div>
Honestly, you'd probably be better off using an SVG (https://developer.mozilla.org/en-US/docs/Web/SVG) instead of a clip-path if you need something like that. Here's one I did really quickly in Illustrator but you can make SVGs in several other apps as well. Not saying you necessarily couldn't use a clip-path to accomplish this but it seems like it would be more work than the 5 minutes it took to make the SVG and map the gradient.
svg {
fill: url(#gradient);
}
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="500px" height="250px" viewBox="0 0 500 250">
<defs>
<linearGradient id="gradient">
<stop offset="0%" stop-color="#00ff77" />
<stop offset="100%" stop-color="#ffef00" />
</linearGradient>
</defs>
<path d="M350.333,84.055c-15.52,0-28.956,8.881-35.531,21.833H105.531C98.957,92.937,85.52,84.055,70,84.055
c-22,0-39.833,17.834-39.833,39.833c0,22,17.834,39.834,39.833,39.834c15.52,0,28.956-8.881,35.531-21.833h209.271
c6.574,12.952,20.011,21.833,35.53,21.833c21.999,0,39.833-17.834,39.833-39.834C390.166,101.889,372.332,84.055,350.333,84.055z" />
</svg>

Having Striped Dashed lines as background

Is it possible to have this striped and dashed background with CSS only?
Background is created by Chrome when inspecting flex elements, and I find it really cool.
You can use repeating-linear-gradient like this:
body {
padding: 0;
margin: 0;
height: 100vh;
width: 100w;
background: repeating-linear-gradient(
45deg,
tomato 0px,
tomato 2px,
transparent 2px,
transparent 9px
);
}
div {
height: 100vh;
width: 100vw;
background: repeating-linear-gradient(
-45deg,
white 0px,
white 4px,
transparent 4px,
transparent 12px
);
}
<div></div>
Tweak with the code
These few lines do produce a somewhat similar pattern, but it won't look good on a low DPI screen. So, in my opinion, it's better to use an SVG pattern instead of pure CSS.
You can use repeating-linear-gradient but i couldn't make it dashed:
//Example
body, html {
background: repeating-linear-gradient(
-55deg,
#606dbc,
#606dbc 5px,
#465298 5px,
#465298 10px
);
}
Here's the SVG solution to my problem. CSS doesn't look to good.
<svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg">
<!-- Let's define the pattern -->
<!-- The width and height should be double the size of a single checker -->
<pattern id="pattern-checkers" x="0" y="0" width="100%" height="15" patternUnits="userSpaceOnUse" patternTransform="rotate(45)">
<!-- Two instances of the same checker, only positioned apart on the `x` and `y` axis -->
<!-- We will define the `fill` in the CSS for flexible use -->
<line x1="0" y1="7" x2="100%" y2="7" stroke="#F3817F"
stroke-dasharray="8 4" />
</pattern>
<!-- Define the shape that will contain our pattern as the fill -->
<rect x="0%" y="0" width="100%" height="100%" fill="url(#pattern-checkers)"></rect>
</svg>
I suggest to use patterns for creating wonderful backgrounds: http://projects.verou.me/css3patterns/

SVG with radialGradient not work in browsers

Problem:
The following svg code not work in browsers:
<svg width="207" height="209" viewBox="0 0 207 209" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M96.2318 8.29356C149.379 4.30837 195.684 44.2918 199.657 97.599C203.631 150.906 163.767 197.351 110.62 201.336C57.473 205.321 11.1677 165.338 7.19452 112.031C3.2213 58.7234 43.0847 12.2787 96.2318 8.29356Z" stroke="url(#paint0_angular)" stroke-width="2"/>
<defs>
<radialGradient id="paint0_angular" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(103.426 104.815) rotate(-94.2626) scale(96.7891 96.5016)">
<stop stop-color="#FF7870"/>
<stop offset="1" stop-color="#FF7870" stop-opacity="0"/>
</radialGradient>
</defs>
</svg>
If replace stroke atribute in path fragment of svg with simple color (for example #f00) - it works, but with radial gradient - not works.
Question:
Is there a way to make this svg valid for browsers?
OR
Is there a way to make this element with HTML & CSS?
All information, that I've found not solves the problems, because:
Background of circle must be transparent
Gradient has grades around the circle (not from top to bottom)
P. S. Expected view of svg:
You can do this using mask and conic-gradient
.box {
width: 200px;
height: 200px;
margin: 20px auto;
border-radius: 50%;
background: conic-gradient(#0000, red);
-webkit-mask: radial-gradient(farthest-side, #0000 calc(100% - 10px), #000 calc(100% - 9px));
mask: radial-gradient(farthest-side, #0000 calc(100% - 10px), #000 calc(100% - 9px));
}
body {
background: url(https://picsum.photos/id/100/1000/1000) center/cover;
}
<div class="box">
</div>

Use svg pattern in css

I have a codepne here - https://codepen.io/mt-ttmt/pen/vvOoJe
I have used css fill to add this pattern as a fill in another svg.
I also need to use the same pattern as a background in a div.
I have url-encoded the pattern svg and used it as the background-image of the div but the pattern does not display show.
How can I use the svg patteren as the background of the div.
.block{
border: 1px solid lightgrey;
height: 66px;
width: 200px;
background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' version='1.1' height='4' width='4' %3E%3Cdefs%3E%3Cpattern id='diagonalHatching' width='3' height='3' patternTransform='rotate(45 0 0)' patternUnits='userSpaceOnUse'%3E%3Cline x1='4' x2='4' y1='0' y2='10' style='stroke:red; stroke-width:5' /%3E%3C/pattern%3E%3C/defs%3E%3C/svg%3E");
}
You can draw a rectangle in your background image and set its width/height, same as the <svg> element, to 100%. The content of the data uri would then look like this:
<svg xmlns="http://www.w3.org/2000/svg" height="100%" width="100%">
<defs>
<pattern id="diagonalHatching" width="3" height="3" patternTransform="rotate(45 0 0)" patternUnits="userSpaceOnUse">
<line x1="4" x2="4" y1="0" y2="10" style="stroke:red; stroke-width:5"/>
</pattern>
</defs>
<rect width="100%" height="100%" fill="url(#diagonalHatching)"/>
</svg>
Applied to the div:
.block{
border: 1px solid lightgrey;
height: 66px;
width: 200px;
background-image:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' height='100%' width='100%'><defs><pattern id='diagonalHatching' width='3' height='3' patternTransform='rotate(45 0 0)' patternUnits='userSpaceOnUse'><line x1='4' x2='4' y1='0' y2='10' style='stroke:red; stroke-width:5'/></pattern></defs><rect width='100%' height='100%' fill='url(%23diagonalHatching)'/></svg>");
}
<div class="block"></div>

Resources