user852974
user852974

Reputation: 2282

Transparent half circle cut out of a div

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 :

rectangle with cut out half circle

Upvotes: 20

Views: 24664

Answers (8)

Ana
Ana

Reputation: 37169

You can do it really easily with a radial gradient.

DEMO

Result:

shape

HTML:

<div class='shape'></div>

Relevant CSS:

.shape {
  margin: 0 auto;
  width: 10em; height: 16em;
  /* WebKit browsers, old syntax, DON'T use it in 2024 anymore *
  background: -webkit-radial-gradient(50% 0, circle, transparent 30%, black 30%);/**/
  
  /* 2013: IE10, current versions of Firefox and Opera */
  /* 2024: cross-browser */
  background: radial-gradient(circle at 50% 0, #0000 30%, #900 calc(30% + 1px));
}

2013: see http://caniuse.com/#feat=css-gradients for detailed info on compatibility. 2024: everything's well supported cross-browser.

The 1px difference serves to avoid jagged edges.

Upvotes: 11

Igbanam
Igbanam

Reputation: 6082

Kyle Sevenokas did some good work. And I built off of that.

HTML:

<div class="rectangle">&nbsp;</div>
<div class="circle">&nbsp;</div>

CSS:

div
{
    position: absolute;
}

.circle
{
    top: -50px;
    width: 0px;
    height: 0px;
    border: 50px solid white;
    border-radius: 50px;
    background: transparent;
}

.rectangle
{
    height: 200px;
    width: 100px;
    background: #000;
}

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?

Upvotes: 1

sandeep
sandeep

Reputation: 92803

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">&nbsp;<span class="circle"></span></div>

View on JSFiddle

Upvotes: 22

jodacame
jodacame

Reputation: 81

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" >

Upvotes: 3

Pieter-Jan De Bruyne
Pieter-Jan De Bruyne

Reputation: 123

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/

Upvotes: 0

Harry
Harry

Reputation: 89760

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>

Upvotes: 13

web-tiki
web-tiki

Reputation: 103770

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>

Transparent cut out half circle

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>

Upvotes: 14

MartijnCMT
MartijnCMT

Reputation: 69

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.

Upvotes: -2

Related Questions