Related
I would like to make a transparent cut out half circle shape using only CSS3. The only requirement is that all the elements that form the shape must be black or transparent.
I cannot use a black rectangle with a white circle on top of it because the half circle has to be transparent and let the background show through.
Desired shape :
May be can do it with CSS :after pseudo property like this:
body {
background: green;
}
.rect {
height: 100px;
width: 100px;
background: rgba(0, 0, 0, 0.5);
position: relative;
margin-top: 100px;
margin-left: 100px;
}
.circle {
display: block;
width: 100px;
height: 50px;
top: -50px;
left: 0;
overflow: hidden;
position: absolute;
}
.circle:after {
content: '';
width: 100px;
height: 100px;
-moz-border-radius: 100px;
-webkit-border-radius: 100px;
border-radius: 100px;
background: rgba(0, 0, 0, 0);
position: absolute;
top: -100px;
left: -40px;
border: 40px solid rgba(0, 0, 0, 0.5);
}
<div class="rect"> <span class="circle"></span></div>
View on JSFiddle
You can use box-shadows to make the transparent cut out circle :
body {
background: url(http://i.imgur.com/qi5FGET.jpg) no-repeat;
background-size: cover;
}
div {
display: inline-block;
width: 300px; height: 300px;
position: relative;
overflow: hidden;
}
div:before {
content: '';
position: absolute;
bottom: 50%;
width: 100%; height: 100%;
border-radius: 100%;
box-shadow: 0px 300px 0px 300px #000;
}
.transparent {
opacity: 0.5;
}
<div></div>
<div class="transparent"></div>
This can be responsive with percentage lengths:
body {
background: url(http://lorempixel.com/output/people-q-c-640-480-1.jpg) no-repeat;
background-size: cover;
}
div {
width: 40%; height: 300px;
position: relative;
overflow: hidden;
}
div:before {
content: '';
position: absolute;
bottom: 50%;
width: 100%; height: 100%;
border-radius: 100%;
box-shadow: 0px 300px 0px 300px #000;
}
.transparent {
opacity: 0.5;
}
<div class="transparent"></div>
Using SVG:
Here is an alternate solution using SVG (though you haven't tagged it). Advantages of using SVG are:
It has better browser support when compared to radial-gradients.
SVG can support images inside the shape unlike the box-shadow approach.
While SVG is not supported by <= IE8 whereas box-shadow is, fallbacks can be provided.
svg {
height: 150px;
width: 150px;
}
polygon {
fill: black;
}
/* Just for demo */
body {
background-image: radial-gradient(circle, #3F9CBA 0%, #153346 100%);
}
<!-- Sample 1 - Using Clip Path -->
<svg viewBox='0 0 100 100' preserveAspectRatio='none'>
<defs>
<clipPath id='clipper'>
<path d='M0,0 a50,50 0 1,0 100,0 l 0,100 -100,0' />
</clipPath>
</defs>
<polygon points='0,0 100,0 100,100 0,100' clip-path='url(#clipper)' />
</svg>
<!-- Sample 2 - Using Path -->
<svg viewBox='0 0 100 100' preserveAspectRatio='none'>
<pattern id='bg' width='100' height='100' patternUnits='userSpaceOnUse'>
<image xlink:href='http://lorempixel.com/100/100/nature/1' height='100' width='100' />
</pattern>
<path d='M0,0 a50,50 0 1,0 100,0 l 0,100 -100,0 0,-100' fill='url(#bg)' />
</svg>
Using CSS:
CSS also has clip-path specifications and we can try something like in the below snippet.
.shape {
position: relative;
width: 100px;
height: 100px;
background-color: purple;
}
.shape:after {
position: absolute;
content: '';
top: 0px;
left: 0px;
height: 100%;
width: 100%;
background: white;
-webkit-clip-path: ellipse(50% 20% at 50% 0%);
clip-path: ellipse(50% 20% at 50% 5%);
}
.shape.image{
background: url(http://lorempixel.com/100/100);
}
#shape-2 {
width: 100px;
height: 100px;
background-color: purple;
-webkit-clip-path: ellipse(50% 20% at 50% 20%);
clip-path: ellipse(50% 20% at 50% 20%);
}
/* Just for demo */
.shape{
float: left;
margin: 20px;
}
#shape-2 {
margin: 150px 20px 0px;
}
<div class="shape"></div>
<div class="shape image"></div>
<br/>
<div id="shape-2"></div>
But unlike SVG clip-path, the pure CSS version (that is, without using an inline or external SVG) doesn't seem to be able to support a path. It only supports shapes and so in this case, if you use the clip-path on the parent directly it would just produce an ellipse (like shown in the snippet). To overcome this, we would have to put the clip-path on a child (or a pseudo element) and this would mean that the clipped area would not be transparent.
Using Canvas:
The same can be done using Canvas also. Canvas commands are pretty similar to SVG and their advantages are also pretty similar. However, Canvas are raster based and hence doesn't scale as well as SVG does.
window.onload = function() {
/* Canvas example with path */
var canvas = document.getElementById('canvas');
if (canvas.getContext) {
var ctx = canvas.getContext('2d');
var img = new Image();
img.src = 'http://lorempixel.com/150/300';
ctx.beginPath();
ctx.moveTo(110, 0);
ctx.arc(60, 0, 50, 0, 3.14, false);
ctx.lineTo(10, 145);
ctx.lineTo(110, 145);
ctx.closePath();
ctx.fill();
/* Use below for using image as a fill */
/*img.onload = function(){
var ptrn = ctx.createPattern(img,'no-repeat');
ctx.fillStyle = ptrn;
ctx.fill();
}*/
}
/* Canvas example with clip path */
var canvasClip = document.getElementById('canvas-clip');
if (canvasClip.getContext) {
var ctxClip = canvasClip.getContext('2d');
ctxClip.beginPath();
ctxClip.moveTo(10, 145);
ctxClip.lineTo(10, 0);
ctxClip.arc(60, 0, 50, 0, Math.PI * 2, true);
ctxClip.lineTo(110, 145);
ctxClip.lineTo(10, 145);
ctxClip.clip();
ctxClip.fillStyle = 'tomato';
ctxClip.fill();
}
}
canvas {
height: 150px;
width: 300px;
}
/* Just for demo */
body {
background-image: radial-gradient(circle, #3F9CBA 0%, #153346 100%);
}
<canvas id='canvas'></canvas>
<canvas id='canvas-clip'></canvas>
Using Masks:
This shape can be created by using CSS (or) SVG masks also. CSS masks have very poor support and work currently only in Webkit powered browsers but SVG masks have much better support and should work in IE9+.
/* CSS Mask */
.shape {
width: 150px;
height: 150px;
background-color: black;
-webkit-mask-image: radial-gradient(circle closest-corner at 50% 0%, transparent 98%, white 99%);
mask-image: radial-gradient(circle closest-corner at 50% 0%, transparent 98%, white 99%);
}
/* End of CSS Mask */
svg {
height: 150px;
width: 150px;
}
polygon#shape {
fill: black;
mask: url(#masker);
}
/* Just for demo */
body {
background-image: radial-gradient(circle, #3F9CBA 0%, #153346 100%);
}
<!-- CSS Mask -->
<div class='shape'></div>
<!-- SVG Mask -->
<svg viewBox='0 0 100 100' preserveAspectRatio='none'>
<defs>
<mask id='masker' x='0' y='0' width='100' height='100'>
<polygon points='0,0 100,0 100,100 0,100' fill='#fff' />
<circle r='50' cx='50' cy='0' fill='#000' />
</mask>
</defs>
<polygon points='0,0 100,0 100,100 0,100' id='shape' />
</svg>
You can do it really easily with a radial gradient.
DEMO
Result:
HTML:
<div class='shape'></div>
Relevant CSS:
.shape {
margin: 0 auto;
width: 10em; height: 16em;
/* WebKit browsers, old syntax */
background: -webkit-radial-gradient(50% 0, circle, transparent 30%, black 30%);
/* IE10, current versions of Firefox and Opera */
background: radial-gradient(circle at 50% 0, transparent 30%, black 30%);
}
See http://caniuse.com/#feat=css-gradients for detailed info on compatibility.
Try this.
body{
background-color:#333;
passing:0px;
height:0px;
}
#app{
background:#333 url('https://source.unsplash.com/random') no-repeat;
background-size:cover;
width:360px;
height:560px;
position:relative;
overflow:hidden;
}
.app-bar{
width:100%;
height:50px;
position:absolute;
bottom:0px;
left:0;
}
.app-bar .bar{
line-height:50px;
position:relative;
width:100%;
height:50px;
background-image: radial-gradient(circle 35px at 315px 0, transparent 700px, #f44336 50px);
}
.app-bar .bar i{
color:#FFF;
display:block;
line-height:50px;
float:left;
width:50px;
text-align:center;
cursor:pointer;
margin-top:0px;
}
.app-bar .bar i:hover{
background-color:rgba(0,0,0,.1);
}
.app-bar .bar button{
padding:0px;
box-sizing:border;
text-align:center;
margin:0px;
bordeR:0px;
outline:0px;
width:60px;
height:60px;
line-height:60px;
cursor:pointer;
color:#FFFFFF;
display:block;
border-radius:50%;
position:absolute;
top:-30px;
left:100%;
margin-left:-75px;
background-color:#f44336;
transition: all .2s ease;
}
.app-bar .bar button span{
line-height:60px;
font-size:30px;
}
.app-bar .bar button:hover{
transform:rotate(45deg);
transition: all .2s ease;
}
<div id="app">
<div class="app-bar">
<div class="bar">
<i class="material-icons">menu</i>
<i class="material-icons">search</i>
<button class="button">
<span class="material-icons">add</span>
</button>
</div>
</div>
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/material-design-icons/3.0.1/iconfont/material-icons.min.css" >
Kyle Sevenokas did some good work. And I built off of that. Checkout the http://jsfiddle.net/FcaVX/1/
I basically collapsed the white div for the circle and gave it white borders. The OP question talked about the colors elements that make up the shape; nothing about its borders right?
I needed rounded corners only on the bottom of a responsive image. I started from #sandeep fiddle and improved it for my needs:
.rect
{
height: 85vh;
position: relative;
background-color: red;
width: 60vw;
}
.circle-helper{
display: block;
width: 100%;
padding-bottom: 50%;
bottom: 0;
left: 0;
overflow: hidden;
position: absolute;
background-color: transparent;
}
.circle{
display: block;
width: 100%;
padding-bottom: 100%;
// height: 500px;
bottom: 0;
left: 0;
overflow: hidden;
position: absolute;
background-color: transparent;
}
.circle:after{
box-sizing: content-box;
content: '';
width: 100%;
height: 100%;
-moz-border-radius: 50%;
-webkit-border-radius: 50%;
border-radius: 50%;
background: rgba(0,0,0,0);
position: absolute;
transform: translate(-50%, -50%);
top: 50%;
left: 50%;
border: 300px solid blue;
}
top: 50%
left: 50%
border: 300px solid blue
https://jsfiddle.net/mop00j22/
Right now, the only way I can think of would be to use a lot of 1-pixel wide black divs next to eachother with varying height. It's technically possible this way but should be deeply frowned upon. Also; you won't have anti-aliassing unless you want to go through the trouble of adding 1x1 pixel divs and do the anti-aliassing manually.
It might be more helpful if you gave an example of how you wanted to use this. Why does it need to be black/transparent only? As stated by omarello, the best solution on most circumstances is probably a simple GIF or PNG image with transparency.
I would like to make a transparent cut out half circle shape using only CSS3. The only requirement is that all the elements that form the shape must be black or transparent.
I cannot use a black rectangle with a white circle on top of it because the half circle has to be transparent and let the background show through.
Desired shape :
May be can do it with CSS :after pseudo property like this:
body {
background: green;
}
.rect {
height: 100px;
width: 100px;
background: rgba(0, 0, 0, 0.5);
position: relative;
margin-top: 100px;
margin-left: 100px;
}
.circle {
display: block;
width: 100px;
height: 50px;
top: -50px;
left: 0;
overflow: hidden;
position: absolute;
}
.circle:after {
content: '';
width: 100px;
height: 100px;
-moz-border-radius: 100px;
-webkit-border-radius: 100px;
border-radius: 100px;
background: rgba(0, 0, 0, 0);
position: absolute;
top: -100px;
left: -40px;
border: 40px solid rgba(0, 0, 0, 0.5);
}
<div class="rect"> <span class="circle"></span></div>
View on JSFiddle
You can use box-shadows to make the transparent cut out circle :
body {
background: url(http://i.imgur.com/qi5FGET.jpg) no-repeat;
background-size: cover;
}
div {
display: inline-block;
width: 300px; height: 300px;
position: relative;
overflow: hidden;
}
div:before {
content: '';
position: absolute;
bottom: 50%;
width: 100%; height: 100%;
border-radius: 100%;
box-shadow: 0px 300px 0px 300px #000;
}
.transparent {
opacity: 0.5;
}
<div></div>
<div class="transparent"></div>
This can be responsive with percentage lengths:
body {
background: url(http://lorempixel.com/output/people-q-c-640-480-1.jpg) no-repeat;
background-size: cover;
}
div {
width: 40%; height: 300px;
position: relative;
overflow: hidden;
}
div:before {
content: '';
position: absolute;
bottom: 50%;
width: 100%; height: 100%;
border-radius: 100%;
box-shadow: 0px 300px 0px 300px #000;
}
.transparent {
opacity: 0.5;
}
<div class="transparent"></div>
Using SVG:
Here is an alternate solution using SVG (though you haven't tagged it). Advantages of using SVG are:
It has better browser support when compared to radial-gradients.
SVG can support images inside the shape unlike the box-shadow approach.
While SVG is not supported by <= IE8 whereas box-shadow is, fallbacks can be provided.
svg {
height: 150px;
width: 150px;
}
polygon {
fill: black;
}
/* Just for demo */
body {
background-image: radial-gradient(circle, #3F9CBA 0%, #153346 100%);
}
<!-- Sample 1 - Using Clip Path -->
<svg viewBox='0 0 100 100' preserveAspectRatio='none'>
<defs>
<clipPath id='clipper'>
<path d='M0,0 a50,50 0 1,0 100,0 l 0,100 -100,0' />
</clipPath>
</defs>
<polygon points='0,0 100,0 100,100 0,100' clip-path='url(#clipper)' />
</svg>
<!-- Sample 2 - Using Path -->
<svg viewBox='0 0 100 100' preserveAspectRatio='none'>
<pattern id='bg' width='100' height='100' patternUnits='userSpaceOnUse'>
<image xlink:href='http://lorempixel.com/100/100/nature/1' height='100' width='100' />
</pattern>
<path d='M0,0 a50,50 0 1,0 100,0 l 0,100 -100,0 0,-100' fill='url(#bg)' />
</svg>
Using CSS:
CSS also has clip-path specifications and we can try something like in the below snippet.
.shape {
position: relative;
width: 100px;
height: 100px;
background-color: purple;
}
.shape:after {
position: absolute;
content: '';
top: 0px;
left: 0px;
height: 100%;
width: 100%;
background: white;
-webkit-clip-path: ellipse(50% 20% at 50% 0%);
clip-path: ellipse(50% 20% at 50% 5%);
}
.shape.image{
background: url(http://lorempixel.com/100/100);
}
#shape-2 {
width: 100px;
height: 100px;
background-color: purple;
-webkit-clip-path: ellipse(50% 20% at 50% 20%);
clip-path: ellipse(50% 20% at 50% 20%);
}
/* Just for demo */
.shape{
float: left;
margin: 20px;
}
#shape-2 {
margin: 150px 20px 0px;
}
<div class="shape"></div>
<div class="shape image"></div>
<br/>
<div id="shape-2"></div>
But unlike SVG clip-path, the pure CSS version (that is, without using an inline or external SVG) doesn't seem to be able to support a path. It only supports shapes and so in this case, if you use the clip-path on the parent directly it would just produce an ellipse (like shown in the snippet). To overcome this, we would have to put the clip-path on a child (or a pseudo element) and this would mean that the clipped area would not be transparent.
Using Canvas:
The same can be done using Canvas also. Canvas commands are pretty similar to SVG and their advantages are also pretty similar. However, Canvas are raster based and hence doesn't scale as well as SVG does.
window.onload = function() {
/* Canvas example with path */
var canvas = document.getElementById('canvas');
if (canvas.getContext) {
var ctx = canvas.getContext('2d');
var img = new Image();
img.src = 'http://lorempixel.com/150/300';
ctx.beginPath();
ctx.moveTo(110, 0);
ctx.arc(60, 0, 50, 0, 3.14, false);
ctx.lineTo(10, 145);
ctx.lineTo(110, 145);
ctx.closePath();
ctx.fill();
/* Use below for using image as a fill */
/*img.onload = function(){
var ptrn = ctx.createPattern(img,'no-repeat');
ctx.fillStyle = ptrn;
ctx.fill();
}*/
}
/* Canvas example with clip path */
var canvasClip = document.getElementById('canvas-clip');
if (canvasClip.getContext) {
var ctxClip = canvasClip.getContext('2d');
ctxClip.beginPath();
ctxClip.moveTo(10, 145);
ctxClip.lineTo(10, 0);
ctxClip.arc(60, 0, 50, 0, Math.PI * 2, true);
ctxClip.lineTo(110, 145);
ctxClip.lineTo(10, 145);
ctxClip.clip();
ctxClip.fillStyle = 'tomato';
ctxClip.fill();
}
}
canvas {
height: 150px;
width: 300px;
}
/* Just for demo */
body {
background-image: radial-gradient(circle, #3F9CBA 0%, #153346 100%);
}
<canvas id='canvas'></canvas>
<canvas id='canvas-clip'></canvas>
Using Masks:
This shape can be created by using CSS (or) SVG masks also. CSS masks have very poor support and work currently only in Webkit powered browsers but SVG masks have much better support and should work in IE9+.
/* CSS Mask */
.shape {
width: 150px;
height: 150px;
background-color: black;
-webkit-mask-image: radial-gradient(circle closest-corner at 50% 0%, transparent 98%, white 99%);
mask-image: radial-gradient(circle closest-corner at 50% 0%, transparent 98%, white 99%);
}
/* End of CSS Mask */
svg {
height: 150px;
width: 150px;
}
polygon#shape {
fill: black;
mask: url(#masker);
}
/* Just for demo */
body {
background-image: radial-gradient(circle, #3F9CBA 0%, #153346 100%);
}
<!-- CSS Mask -->
<div class='shape'></div>
<!-- SVG Mask -->
<svg viewBox='0 0 100 100' preserveAspectRatio='none'>
<defs>
<mask id='masker' x='0' y='0' width='100' height='100'>
<polygon points='0,0 100,0 100,100 0,100' fill='#fff' />
<circle r='50' cx='50' cy='0' fill='#000' />
</mask>
</defs>
<polygon points='0,0 100,0 100,100 0,100' id='shape' />
</svg>
You can do it really easily with a radial gradient.
DEMO
Result:
HTML:
<div class='shape'></div>
Relevant CSS:
.shape {
margin: 0 auto;
width: 10em; height: 16em;
/* WebKit browsers, old syntax */
background: -webkit-radial-gradient(50% 0, circle, transparent 30%, black 30%);
/* IE10, current versions of Firefox and Opera */
background: radial-gradient(circle at 50% 0, transparent 30%, black 30%);
}
See http://caniuse.com/#feat=css-gradients for detailed info on compatibility.
Try this.
body{
background-color:#333;
passing:0px;
height:0px;
}
#app{
background:#333 url('https://source.unsplash.com/random') no-repeat;
background-size:cover;
width:360px;
height:560px;
position:relative;
overflow:hidden;
}
.app-bar{
width:100%;
height:50px;
position:absolute;
bottom:0px;
left:0;
}
.app-bar .bar{
line-height:50px;
position:relative;
width:100%;
height:50px;
background-image: radial-gradient(circle 35px at 315px 0, transparent 700px, #f44336 50px);
}
.app-bar .bar i{
color:#FFF;
display:block;
line-height:50px;
float:left;
width:50px;
text-align:center;
cursor:pointer;
margin-top:0px;
}
.app-bar .bar i:hover{
background-color:rgba(0,0,0,.1);
}
.app-bar .bar button{
padding:0px;
box-sizing:border;
text-align:center;
margin:0px;
bordeR:0px;
outline:0px;
width:60px;
height:60px;
line-height:60px;
cursor:pointer;
color:#FFFFFF;
display:block;
border-radius:50%;
position:absolute;
top:-30px;
left:100%;
margin-left:-75px;
background-color:#f44336;
transition: all .2s ease;
}
.app-bar .bar button span{
line-height:60px;
font-size:30px;
}
.app-bar .bar button:hover{
transform:rotate(45deg);
transition: all .2s ease;
}
<div id="app">
<div class="app-bar">
<div class="bar">
<i class="material-icons">menu</i>
<i class="material-icons">search</i>
<button class="button">
<span class="material-icons">add</span>
</button>
</div>
</div>
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/material-design-icons/3.0.1/iconfont/material-icons.min.css" >
Kyle Sevenokas did some good work. And I built off of that. Checkout the http://jsfiddle.net/FcaVX/1/
I basically collapsed the white div for the circle and gave it white borders. The OP question talked about the colors elements that make up the shape; nothing about its borders right?
I needed rounded corners only on the bottom of a responsive image. I started from #sandeep fiddle and improved it for my needs:
.rect
{
height: 85vh;
position: relative;
background-color: red;
width: 60vw;
}
.circle-helper{
display: block;
width: 100%;
padding-bottom: 50%;
bottom: 0;
left: 0;
overflow: hidden;
position: absolute;
background-color: transparent;
}
.circle{
display: block;
width: 100%;
padding-bottom: 100%;
// height: 500px;
bottom: 0;
left: 0;
overflow: hidden;
position: absolute;
background-color: transparent;
}
.circle:after{
box-sizing: content-box;
content: '';
width: 100%;
height: 100%;
-moz-border-radius: 50%;
-webkit-border-radius: 50%;
border-radius: 50%;
background: rgba(0,0,0,0);
position: absolute;
transform: translate(-50%, -50%);
top: 50%;
left: 50%;
border: 300px solid blue;
}
top: 50%
left: 50%
border: 300px solid blue
https://jsfiddle.net/mop00j22/
Right now, the only way I can think of would be to use a lot of 1-pixel wide black divs next to eachother with varying height. It's technically possible this way but should be deeply frowned upon. Also; you won't have anti-aliassing unless you want to go through the trouble of adding 1x1 pixel divs and do the anti-aliassing manually.
It might be more helpful if you gave an example of how you wanted to use this. Why does it need to be black/transparent only? As stated by omarello, the best solution on most circumstances is probably a simple GIF or PNG image with transparency.
I'm trying to make a corner block, to create a one-page as in the photo below. But I ran into a problem.
I tried to make div slopes, but when looking at different resolutions it looked crooked.
What i need screen
(there was also a problem in that before these inclined divs there was a background image and some holes that left this div, the picture showed through.)My Fail Screen
.tri-index-right {
background: #fff;
height: 150px;
width: 100%;
transform: skewY(4deg);
overflow: hidden;
position: relative;
z-index: 2; /*fail method*/
}
I can not understand how to extend this angle using the CSS method at width 100%.
.1 {
min-width: 500px;
}
#triangle-left {
width: 0;
height: 0;
border-top: 10px solid transparent;
border-right: 100px solid red;
border-bottom: 100% solid transparent;
}
<div class="1">
<div id="triangle-left"></div>
</div>
I will be very grateful for the help
You can use vw for full width or use svg
.one {
width: 100%;
height: 200px;
background: url('https://imgur.com/a/kA3XA') center center no-repeat;
background-size: cover;
}
#triangle-left {
width: 0;
height: 0;
border-top: 100px solid transparent;
border-right: 100vw solid red;
}
<div class="one">
<div id="triangle-left"></div>
</div>
you can also use svg for this
.main {
position: relative;
min-height: 200px;
}
.svg-container svg {
width: 100%;
height: 150px;
fill: #333; /* change color to white since */
}
<div class="main">
<!-- main image -->
</div>
<div class="svg-container">
<svg xmlns="https://www.w3.org/2000/svg" version="1.1" class="separator" viewBox="0 0 100 100" preserveAspectRatio="none">
<path d="M0 100 L100 0 L100 100 Z"></path>
</svg>
</div>
you can also use multiple background image including a sharp gradient :
header {
min-height: 4em;
background:
/* first the mask */
linear-gradient(to bottom right, transparent 49.5%, white 50.5%) bottom left no-repeat,
/* then the background image */
url(http://lorempixel.com/400/300/abstract/1) 0 0;
/* finally resize each image, in particular the mask */
background-size: 100% 4em, cover;
padding: 1em 2em 4em;
color: white;
}
body {
margin: 0;
}
div {
padding: 1em;
}
<header>
<h1>whatever</h1>
</header>
<div>next content</div>
I was trying to accomplish this border for two divs with CSS:
I tried just using border-radius, but the two partial circles aren't pressed together: http://jsfiddle.net/uwz6L79w/
.left {
position: absolute;
left: 0;
top: 0;
width: 100px;
height: 100px;
border-width: 4px;
border-color: black white black black;
border-style: solid;
border-radius: 60px
}
.right {
position: absolute;
left: 104px;
top: 0;
width: 100px;
height: 100px;
border-width: 4px;
border-color: black black black white;
border-style: solid;
border-radius: 60px;
}
<div class="left"></div>
<div class="right"></div>
I could just press them together further, but I'd have to have one div overlap the other, like this: http://jsfiddle.net/uwz6L79w/1/.
.left {
position: absolute;
left: 0;
top: 0;
width: 100px;
height: 100px;
border-width: 4px;
border-color: black white black black;
border-style: solid;
border-radius: 60px
}
.right {
position: absolute;
left: 70px;
top: 0;
width: 100px;
height: 100px;
border-width: 4px;
border-color: black black black white;
border-style: solid;
border-radius: 60px;
background: #f2f2f2;
}
<div class="left"></div>
<div class="right"></div>
Does anyone know how I could accomplish this without having the divs overlap?
SVG
This is also possible using SVG.
The SVG version is very short as it mainly only requires an Arc command to control its shape, size and position.
<svg width="50%" viewbox="0 0 100 50">
<path d="M50,35
a20,20 0 1,0 0,-20
a20,20 0 1,0 0,20z"
fill="white"
stroke="black">
</path>
</svg>
SVG stands for Scalable Vector Graphic. The web browser views it as an image but you can add text and normal HTML elements within an SVG.
It is well supported across all browsers as viewable here: CanIUse
SVG | MDN
Using Borders: Recommended
You could do it the same way as in your second snippet and use positioning like in the below snippet to avoid the two div elements from overlapping. Here the circles are produced by pseudo-elements and the overlapping part is cut out using overflow: hidden on their parents.
One thing to note here is that any hover effect should be added on the pseudo-elements and not the parent elements. This is because if the :hover is attached to parent then it would be triggered even when hovering outside the circle (because the parent is still a square).
Out of all the three solutions provided in this answer, this is the one that has the best browser support and would work even in IE8. Hence, this is the recommended one.
.left, .right {
position: relative;
float: left;
height: 200px;
width: 200px;
/* border: 1px solid; uncomment to see that they aren't overlapped */
overflow: hidden;
}
.left:after, .right:after {
position: absolute;
content: '';
height: calc(100% - 12px); /* 12px because of 6px border on either side */
width: calc(100% - 12px); /* 12px because of 6px border on either side */
border-radius: 50%;
border: 6px solid gray;
}
.left:after { right: -20px; }
.right:after { left: -20px; }
<div class='left'></div>
<div class='right'></div>
Using Radial Gradients:
If you don't want to use pseudo-elements and a overflow: hidden on the parent then you could also make use of radial-gradient background images to produce the circle and position them such that they end up producing the required effect. Below is a sample snippet for this approach.
The downside of this approach is the low browser support for radial-gradient. It would not work in IE9 and lower. Plus, the circles produced by radial gradients are generally jagged (rough edges) and when we modify the color stop positions to make it smoother, it gives a slightly blurred appearance.
.left, .right {
float: left;
height: 200px;
width: 200px;
/*border: 1px solid; uncomment to see that they aren't overlapped */
}
/* generally the below code should be enough to produce 6px thick circular border
.left {
background: radial-gradient(circle at 70% 50%, transparent calc(50% - 3px), gray calc(50% - 3px), gray calc(50% + 3px), transparent calc(50% + 3px));
}
.right {
background: radial-gradient(circle at 30% 50%, transparent calc(50% - 3px), gray calc(50% - 3px), gray calc(50% + 3px), transparent calc(50% + 3px));
}
*/
/* but it produces jagged edges and so we can change the color stops a bit like below
this produces smoother circles but the disadvantage is that they'd look a bit blurred */
.left {
background: radial-gradient(circle at 70% 50%, transparent calc(50% - 4px), gray calc(50% - 2px), gray calc(50% + 2px), transparent calc(50% + 4px));
}
.right {
background: radial-gradient(circle at 30% 50%, transparent calc(50% - 4px), gray calc(50% - 2px), gray calc(50% + 2px), transparent calc(50% + 4px));
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<div class='left'></div>
<div class='right'></div>
Using Clip Paths (CSS/SVG):
Another approach that could be used is to use clip-path. The advantage of this approach is that the hover effects would be triggered only when the cursor is within the circle (as can be seen in snippet). This is because the unnecessary portions are clipped.
Downside is again the poor browser support. CSS version of clip-path is supported only in Webkit but not in Firefox, IE whereas the SVG version (using inline SVG) is supported in Webkit, Firefox but not IE.
.left, .right {
float: left;
height: 200px;
width: 200px;
border-radius: 50%;
border: 6px solid gray;
}
/* CSS Clip Path - not supported by FF and IE */
.left.css-clip {
clip-path: polygon(0% 0%, 80% 0%, 80% 100%, 0% 100%);
}
.right.css-clip {
margin-left: -86px; /* 20% width * 2 (which is the clipped space) - border width */
clip-path: polygon(20% 0%, 100% 0%, 100% 100%, 20% 100%);
}
/* SVG Clip Path - supported by Webkit, FF but not IE */
.left.svg-clip {
clip-path: url(#clipper-left);
}
.right.svg-clip {
margin-left: -86px; /* 20% width * 2 (which is the clipped space) - border width */
clip-path: url(#clipper-right);
}
/* Just for demo */
h3{ clear: both; }
.left:hover, .right:hover{ background: red; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<h3>CSS Clip Path</h3>
<div class='left css-clip'></div>
<div class='right css-clip'></div>
<h3>SVG Clip Path</h3>
<div class='left svg-clip'></div>
<div class='right svg-clip'></div>
<!-- Inline SVG for SVG Clip Path -->
<svg width='0' height='0'>
<defs>
<clipPath id='clipper-left' clipPathUnits='objectBoundingBox'>
<path d='M0,0 .8,0 .8,1 0,1z' />
</clipPath>
<clipPath id='clipper-right' clipPathUnits='objectBoundingBox'>
<path d='M.2,0 1,0 1,1 .2,1z' />
</clipPath>
</defs>
</svg>
Here's a solution using just a single <div>.
.shape is a transparent circle with a 10px red border.
.shape::before is an opaque white circle with a 10px red border.
.shape::after is an opaque white circle (no border).
.shape {
margin: 6px auto;
}
.shape, .shape::before, .shape::after {
display: block;
position: relative;
width: 160px;
height: 160px;
border-radius: 160px;
}
.shape, .shape::before {
border: 10px solid #f00;
}
.shape::before, .shape::after {
content: "";
background-color: rgba(255, 255, 255, 1);
}
.shape::before {
top: -10px;
left: -150px;
}
.shape::after {
top: -180px;
}
<div class="shape"></div>
Here's a quick example I came up with. I haven't tested it in different browsers but it should be fairly well-supported.
HTML:
<div class="one"></div>
<div class="two"></div>
CSS:
div {
background: #fff;
border-radius: 50%;
float: left;
height: 100px;
position: relative;
width: 100px;
}
.one:after,
.two:after{
/* adjust this to set the border color */
background: #666;
border-radius: 50%;
content: "";
position: absolute;
z-index: -1;
/* adjust these to set the border width */
top: -5px;
right: -5px;
bottom: -5px;
left: -5px;
}
.two {
/* adjust this to set the overlap of the circles */
margin-left: -20px;
}
Live Demo
I'm coming back to this question (after 6 weeks), purely because the top-voted answer piqued my academic curiosity in svg, which I've rarely come across and never taken the time to learn.
Since I'm now learning svg, this question (which sent me off on my quest to learn it in the first place) seemed like the ideal challenge against which to try out some new skills.
So here is an alternative svg solution, the equivalent of my single <div> css solution above:
svg {
width: 310px;
height: 180px;
}
svg circle {
stroke: rgb(255,0,0);
stroke-width: 10;
fill: rgb(255,255,255);
}
svg circle:nth-of-type(3) {
stroke: rgb(255,255,255);
}
<svg viewbox="0 0 310 180">
<circle cx="90" cy="90" r="80" />
<circle cx="220" cy="90" r="80" />
<circle cx="90" cy="90" r="70" />
</svg>
I want to be able to draw a circle with a segment of it another colour, I would like the amount of a segment covered to be able to be increased in increments of 10% from 0% to 100%.
Any examples on Google are all sectors not segments.
So far this is the best I have been able to come up with:
div.outerClass {
position: absolute;
left: 10px;
top: 10px;
height: 2.5px;
overflow: hidden;
-ms-transform: rotate(270deg); /* IE 9 */
-webkit-transform: rotate(270deg); /* Chrome, Safari, Opera */
transform: rotate(270deg);
}
div.innerClass {
width: 10px;
height: 10px;
border: 5px solid green;
border-radius: 36px;
}
<div class="outerClass">
<div class="innerClass"></div>
</div>
0%, 50% and 100% I can all do.
You can do it using linear-gradient
.circle{
position:absolute;
width:80px;
height:80px;
border-radius:50%;
background: linear-gradient(
to right,
yellow 0%, yellow 10%,
orange 10%, orange 20%,
yellow 20%, yellow 30%,
orange 30%, orange 40%,
yellow 40%, yellow 50%,
orange 50%, orange 60%,
yellow 60%, yellow 70%,
orange 70%, orange 80%,
yellow 80%, yellow 90%,
orange 90%, orange 100%
);
}
<div class="circle"></div>
otherwise you can put 10 child elements inside your overflow:hidden circle parent:
.circle{
position:absolute;
width:80px;
height:80px;
border-radius:50%;
overflow:hidden;
}
.circle > span{
width:10%;
height:100%;
float:left;
}
.circle > span:nth-child(1){ background: yellow;}
.circle > span:nth-child(2){ background: orange;}
.circle > span:nth-child(3){ background: blue;}
.circle > span:nth-child(4){ background: green;}
.circle > span:nth-child(5){ background: fuchsia;}
.circle > span:nth-child(6){ background: orange;}
.circle > span:nth-child(7){ background: gold;}
.circle > span:nth-child(8){ background: tan;}
.circle > span:nth-child(9){ background: navy;}
.circle > span:nth-child(10){background: brown;}
<div class="circle">
<span></span><span></span><span></span><span></span><span></span>
<span></span><span></span><span></span><span></span><span></span>
</div>
The cross-browser solution:
JSFiddle
.circle {
border-radius: 50%;
background: gray;
width: 300px;
height: 300px;
overflow: hidden;
}
.segment {
float: left;
width: 10%;
height: 100%;
}
.segment_1 {
background: red;
}
.segment_2 {
background: green;
}
.segment_3 {
background: yellow;
}
.segment_4 {
background: blue;
}
<div class="circle">
<div class="segment segment_1"></div>
<div class="segment segment_2"></div>
<div class="segment segment_3"></div>
<div class="segment segment_4"></div>
</div>
BOX SHADOW
Another approach could be using one element and box-shadows.
The main element is a circle (border-radius: 50%;) and has an aspect ratio of 1:1.
The pseudoelement is positioned left: -100%;, or just left of the main element.
10 box shadows are applied to the pseudoelement, with different colour and different abscissae. I have put abscissae as 30px, as 30px is 10% of 300px ...
10% of width was chosen because 10 stripes are needed.
div {
height: 300px;
width: 300px;
border: 1px solid black;
position: relative;
border-radius: 50%;
overflow: hidden;
}
div:before {
position: absolute;
content: '';
height: inherit;
width: inherit;
left: -100%;
background: red;
box-shadow:
30px 0 0 chocolate,
60px 0 0 hotpink,
90px 0 0 indigo,
120px 0 0 orangered,
150px 0 0 gold,
180px 0 0 deepskyblue,
210px 0 0 springgreen,
240px 0 0 darkslategray,
270px 0 0 gold,
300px 0 0 navy;
}
<div></div>
Another approach would be to use SVG. The segments are made with <rect /> elements and they are clipped to a circle using the <clipPath/> element :
svg{width:40%;display:block;margin:0 auto;}
use:hover{fill:#000;}
<svg viewBox="0 0 10 10">
<defs>
<clipPath id="circle">
<circle cx="5" cy="5" r="5" />
</clipPath>
<rect id="seg" y="0" width="1" height="10" />
</defs>
<g clip-path="url(#circle)">
<use xlink:href="#seg" x="0" fill="pink"/>
<use xlink:href="#seg" x="1" fill="green" />
<use xlink:href="#seg" x="2" fill="orange" />
<use xlink:href="#seg" x="3" fill="teal" />
<use xlink:href="#seg" x="4" fill="tomato"/>
<use xlink:href="#seg" x="5" fill="gold"/>
<use xlink:href="#seg" x="6" fill="darkorange" />
<use xlink:href="#seg" x="7" fill="pink" />
<use xlink:href="#seg" x="8" fill="red" />
<use xlink:href="#seg" x="9" fill="yellow" />
</g>
</svg>