Trying to round part of shape - css

I know you can use border-radius to round objects with CSS, but I am trying to figure out how to round, or possibly hide, the pointed parts of a CSS shape when overlaying over a circle:
It's tough to explain without a Codepen:
http://codepen.io/cavanflynn/pen/gpEdJo
#circle:before {
position:absolute;
left: -10px;
top: -25px;
z-index: 100;
content: "";
border-right: 35px solid white;
border-top: 25px solid transparent;
border-bottom: 25px solid transparent;
border-left: 25px solid transparent;
}
In the Codepen you can see the circle and where parts of the white are overflowing the red boundary of it. The goal is to get rid of the white points and round the white perfectly with the red OR make the section of the circle that the white overlays completely transparent (like taking a slice from a pizza).

You can achieve this using a pseudo element, and using borders on the pseudo to manipulate the shape to your liking. This uses the transparent border color on the right side, with the rest with a solid color. A demo of this is shown below:
html {
background: url(http://lorempixel.com/800/900);
}
div {
position: relative;
height: 100px;
width: 100px;
border-radius: 50%;
background: gold;
margin: 150px auto;
}
div:before {
content: "";
position: absolute;
top: -50px;
left: -50px;
height: 100%;
width: 100%;
border-radius: 50%;
border: 50px solid red;
border-right-color: transparent;
}
<div></div>
If the angle here is too big for your liking, you could duplictate the pseudo element on an :after element, and using transform:rotate(x deg); to rotate to a specific angle
A demo of this can be seen when hovering below:
html {
background: url(http://lorempixel.com/800/900);
}
div {
position: relative;
height: 100px;
width: 100px;
border-radius: 50%;
background: gold;
margin: 150px auto;
}
div:before, div:after {
content: "";
position: absolute;
top: -50px;
left: -50px;
height: 100%;
width: 100%;
border-radius: 50%;
border: 50px solid red;
border-right-color: transparent;
transition:all 0.8s;
}
div:hover:after{
transform:rotate(45deg);
}
div:hover:before{
transform:rotate(-45deg);
}
<div></div>

Why does border-radius not work for my case?
Yes, border-radius property can be used to produce circles but it can produce a proper circle only when the height and width are the same. In your original sample, the height and width of the element is determined by the thickness of the border on the ::before element and since the border on one side is thicker than the rest, it produces a rectangle instead of a square. Because of this you would only get a oval at best and not a circle.
Even if you make the border thickness the same, the curvature of the round wouldn't match with the curvature of the outer circle (parent container) because the radii and center points are both different.
I have changed the border-color of the other three borders in the below snippet to help you visualize what is going on:
body {
background-color: black;
}
#circle {
border-right: 50px solid red;
border-left: 50px solid red;
border-top: 50px solid red;
border-bottom: 50px solid red;
-moz-border-radius: 50px;
-webkit-border-radius: 50px;
border-radius: 50px;
position: absolute;
left: 35px;
z-index: 100;
top: 50px;
}
#circle:after {
-moz-border-radius: 50px;
-webkit-border-radius: 50px;
border-radius: 50px;
position: absolute;
left: -25px;
top: -25px;
z-index: 100;
content: "";
border: 25px solid yellow;
}
#circle:before {
position: absolute;
left: -10px;
top: -25px;
z-index: 101;
content: "";
border-right: 35px solid white;
border-top: 25px solid cyan;
border-bottom: 25px solid cyan;
border-left: 25px solid cyan;
border-radius: 50%;
}
<div id="circle"></div>
One other method that is typically used to cut out the extraneous part is overflow: hidden but that also wouldn't work for your case because your outer circle is created only by border and it doesn't actually have any content height or content width. Because of this when you add overflow: hidden your pseudo elements would get totally hidden.
What are the other options that I could use?
Here is an alternate approach to create the same shape as you originally intended to with just a single element + two pseudo-elements.
The shape consists of the following components:
A container element which is converted into a circle by using border-radius: 50%.
One pseudo-element with dimensions half that of the parent and border-radius: 50% to produce the inner circle. A z-index: 1 is added to position this above the sliced area.
Another pseudo-element which has a transform: rotate(45deg) added to produce the slice.
Parent container has overflow: hidden which prevents the other parts of the pseudo-element from showing up.
Note: I assume you won't be having any concerns using transform because you had tagged CSS3.
body {
background-color: black;
}
#circle {
position: relative;
height: 200px;
width: 200px;
background: red;
border-radius: 50%;
overflow: hidden;
}
#circle:before, #circle:after {
position: absolute;
content: '';
height: 100px;
width: 100px;
}
#circle:before {
top: 25%;
left: 25%;
background: yellow;
border-radius: 50%;
z-index: 1;
}
#circle:after {
right: 0px;
background: white;
transform: rotate(45deg);
transform-origin: left bottom;
}
<div id="circle"></div>
How to get a transparent slice? (like the Colorado flag)
Alternately, if you want the slice to be transparent totally then you can use the below approach:
Here the container has a bit of padding and the background of the container is made small by restricting it to only the content-box using background-clip. This forms the inner yellow circle.
The outer red circle is made up of two pseudo-elements each of which have a background color only for half portion through linear-gradient. The other half is transparent.
The two pseudo-elements are rotated in opposing directions to make it look as though they leave a transparent cut in between.
body {
background-image: linear-gradient(to bottom, rgb(64, 64, 150) 33%, white 33%, white 66%, rgb(64, 64, 150) 66%);
background-repeat: no-repeat;
height: 260px;
}
#circle {
position: relative;
height: 100px;
width: 100px;
background: rgb(255, 243, 21);
border-radius: 50%;
padding: 50px;
margin-top: 60px;
margin-left: 50px;
background-clip: content-box;
}
#circle:after,
#circle:before {
position: absolute;
content: '';
top: 0px;
left: 0px;
height: 200px;
width: 200px;
border-radius: 50%;
z-index: -1;
}
#circle:before {
background: linear-gradient(to bottom, rgb(237, 51, 56) 50%, transparent 50%);
transform: rotate(-45deg);
}
#circle:after {
background: linear-gradient(to top, rgb(237, 51, 56) 50%, transparent 50%);
transform: rotate(45deg);
}
<div id="circle"></div>
If you don't want to use linear-gradient to produce semi-circles then you can create the same effect by using two pseudo-elements whose height is half their width and assign the appropriate border-radius to it.
body {
background-image: linear-gradient(to bottom, rgb(64, 64, 150) 33%, white 33%, white 66%, rgb(64, 64, 150) 66%);
background-repeat: no-repeat;
height: 260px;
}
#circle {
position: relative;
height: 100px;
width: 100px;
background: rgb(255, 243, 21);
border-radius: 50%;
padding: 50px;
margin-top: 60px;
margin-left: 50px;
background-clip: content-box;
}
#circle:after,
#circle:before {
position: absolute;
content: '';
top: 0px;
left: 0px;
height: 100px;
width: 200px;
background: rgb(237, 51, 56);
border-radius: 100px 100px 0px 0px;
transform-origin: 50% 100%;
z-index: -1;
}
#circle:before {
transform: rotate(-45deg);
}
#circle:after {
bottom: 0px;
transform: rotate(225deg);
}
<div id="circle"></div>

You can change the approach. Stop using :before and :after, and use overflow: hidden plus z-index layering with multiple elements.
The new HTML:
<div class="circle">
<div class="inner-circle"></div>
<div class="triangle"></div>
</div>
The CSS:
.circle {
width: 200px;
height: 200px;
background: red;
position: relative;
top: 40px;
border-radius: 50%;
overflow: hidden;
z-index: 10;
}
.inner-circle {
width: 100px;
height: 100px;
border-radius: 50%;
background: black;
top: 50px;
left: 50px;
position: relative;
z-index: 10;
}
.triangle {
position:absolute;
left: 25px;
top: 25px;
border-right: 105px solid purple;
border-top: 75px solid transparent;
border-bottom: 75px solid transparent;
border-left: 75px solid transparent;
z-index: 9;
}
Check the demo: https://jsfiddle.net/ghv02ucr/1/

I've checked on your question, try this code on your #circle:before, and you will see the triangle aligned;
#circle:before {
position:absolute;
left: -18px;
top: -25px;
z-index: 100;
content: "";
border-right: 35px solid white;
border-top: 25px solid transparent;
border-bottom: 25px solid transparent;
border-left: 25px solid transparent;
}
Or you can eliminate all the #circle:before properties to get rid of the triangle.... hope it helped.

Related

How to change shape from pointing to top to point to right

I want to change the shape of the CSS from pointing to top to point to right. This is what I have now:
And this is what I want to have:
This is my current CSS:
.base {
background: red;
display: inline-block;
height: 55px;
margin-left: 20px;
margin-top: 55px;
position: relative;
width: 100px;
}
.base: before {
border-bottom: 35px solid red;
border-left: 50px solid transparent;
border-right: 50px solid transparent;
content: "";
height: 0;
left: 0;
position: absolute;
top: -35px;
width: 0;
}
Please with below CSS
.base{
background: red;
display: inline-block;
height: 60px;
margin-left: 20px;
margin-top: 55px;
position: relative;
width: 100px;
}
.base:before {
border-left: 30px solid red;
border-top: 30px solid transparent;
border-bottom:30px solid transparent;
content: "";
height: 0;
left:100%;
position: absolute;
top:0;
width: 0;
}
It is simpler nowadays to use the CSS clip path facility rather than have to use borders and pseudo elements.
Clip path let’s you define a polygon in terms of percentages which means it is good for responsiveness, altering automatically to fit the dimensions of the element.
Here’s an example. Change the % values to suit the look you want.
.shape {
width: 200px;
height: 200px;
clip-path: polygon(0% 0%, 50% 0%, 100% 50%, 50% 100%, 0% 100%);
background: red;
}
<div class="shape"></div>
Caveat: not supported in IE

Create this shape in CSS (half pipe shape)

I've been trying to make this shape in CSS, but unfortunately could not find a way how to. It's half pipe like shaped:
The pixelated corner should be smooth (it's a zoomed in image).
Anyone knows how to create this? Or can get me on the right tracks?
You will need to use pseudo element :after for the inner block and then apply border-radius for curved corner.
div {
height: 60px;
width: 60px;
border: solid red;
position: relative;
background: red;
border-width: 0 10px 10px 0;
box-sizing: border-box;
}
div:after {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
border-bottom-right-radius: 10px;
background: #fff;
}
<div></div>
simple
.shape {
width: 140px;
height: 200px;
background-color: gray;
}
.shape:after {
content: '';
position: absolute;
width: 100px;
height: 160px;
background-color: #fff;
border-bottom-right-radius: 50px;
}
<div class="shape"></div>
I assume that the problem here is to create the "outer" curve, on the arbitrary background. It's achievable by the trick with clipping the needed part from the thick rounded border of the pseudo-element:
div {
width: 50%;
min-height: 4em;
margin: auto;
border: #888 solid;
border-width: 0 1em 1em 0;
position: relative;
}
div::after {
content: '';
border: #888 solid;
border-width: 0 1em 1em 0;
border-radius: 0 0 100% 0;
position: absolute;
right: -1em;
bottom: -1em;
width: 1em;
height: 1em;
clip: rect(0 1em 1em 0);
}
div:hover::after {
border-color: red; /* highlight the curved part */
}
body {
/* just as a background example */
background: repeating-linear-gradient(-45deg, #ddd, #ddd 1px, transparent 1px, transparent 10px);
min-height: 90vh;
}
<div></div>
You can do this with one element and with transparency like this:
.box {
width:80px;
height:100px;
border-right:20px solid grey;
border-bottom:20px solid grey;
box-sizing:border-box;
background:
radial-gradient(farthest-side at top left,transparent 98%,grey ) bottom right/20px 20px no-repeat;
}
body {
background:pink;
}
<div class="box">
</div>

CSS: Circle with half one color and the other half another color?

Is it possible to do something like this with CSS? Basically make half the circle one color and the other half another color?
A linear-gradient will do that, and use border-radius to make it a circle.
div {
width: 50vw;
height: 50vw;
background: linear-gradient( -45deg, blue, blue 49%, white 49%, white 51%, red 51% );
border-radius: 50%;
}
<div></div>
You can do something like this:
div {
border-radius: 50px;
border-right-color: red;
border-top-color: blue;
border-bottom-color: red;
border-left-color: blue;
border-width: 50px;
border-style: solid;
height: 0px;
width: 0px;
}
<div>
</div>
You can use :before and :after pseudo-elements for each half of circle and also add transform: rotate() on parent element.
.circle {
display: inline-block;
position: relative;
width: 200px;
height: 200px;
border-radius: 50%;
overflow: hidden;
transform: rotate(25deg);
}
.circle:after, .circle:before {
content: '';
position: absolute;
height: 100%;
width: 50%;
}
.circle:after {
background: #02FBFD;
left: -2px;
}
.circle:before {
background: #FE0103;
right: -2px;
}
<div class="circle"></div>

Creating a curved shadow with a color gradient

Here is a shadow that I am trying to replicate using just CSS and I just cannot work out how to do it. I have spent hours trying. I think I need to create 2 shadow elements but I'm not sure how to proceed.
The closest thing I get is with this (an abysmal attempt - I know):
.type-product:before, .type-product:after{
z-index: -1;
position: absolute;
content: "";
bottom: 25px;
left: 21px;
width: 50%;
top: 80%;
max-width:300px;
background: #777;
box-shadow: 0 35px 20px #777;
transform: rotate(-8deg);
}
.type-product:after{
transform: rotate(8deg);
right: 20px;
left: auto;
}
Most appreciative if any CSS gurus could provide any help.
NOTE: I don't think that this link covers my problem fully. It just discusses the curve - whilst I need a curve with a color-gradient...
To me that looks like something that can be achieved using a couple of elements like shown below. The shadow is actually a linear-gradient on top of which a white circle is placed. The drawback of this approach is that it would work only with a solid background (because the circle that is overlayed would need a solid color).
That just doesn't look like it could be possible using a box-shadow because the shadow itself seems like a gradient which goes from transparent or white on the left to black in the middle to transparent or white again on the right.
The output is responsive and can adapt itself to all dimensions of the parent container. Just :hover the container in the snippet to see it in action :)
.wrapper {
position: relative;
height: 200px;
width: 200px;
overflow: hidden;
}
.content {
height: 85%;
width: 100%;
border: 1px solid;
}
.wrapper:before {
position: absolute;
content: '';
bottom: 0px;
left: 0px;
height: 15%;
width: 100%;
background: linear-gradient(to right, transparent 2%, #444, transparent 98%);
}
.wrapper:after {
position: absolute;
content: '';
bottom: -186%;
/* height of before - height of after - 1% buffer for the small gap */
left: -50%;
height: 200%;
width: 200%;
border-radius: 50%;
background: white;
}
* {
box-sizing: border-box;
}
/* just for demo */
.wrapper {
transition: all 1s;
}
.wrapper:hover {
height: 300px;
width: 400px;
}
<div class='wrapper'>
<div class='content'></div>
</div>
You can do this with :before pseudo element and box-shadow
div {
width: 200px;
height: 100px;
border: 1px solid #aaa;
position: relative;
background: white;
}
div:before {
content: '';
border-radius: 50%;
height: 100%;
width: 100%;
position: absolute;
z-index: -1;
left: 0;
transform: translateY(103%);
box-shadow: 0px -54px 13px -47px #000000, -4px -45px 35px -28px #999999;
}
<div></div>
Aside from the answers, this could also be a good box shadow for your class as well. (This is just preference & similar to what you want).
.box {
width: 70%;
height: 200px;
background: #FFF;
margin: 40px auto;
}
.type-product {
position: relative;
}
.type-product:before {
z-index: -1;
position: absolute;
content: "";
bottom: 17px;
left: 10px;
width: 50%;
top: 70%;
max-width: 300px;
background: #777;
box-shadow: 0 18px 20px #777;
transform: rotate(-8deg);
}
.type-product:after {
z-index: -1;
position: absolute;
content: "";
bottom: 17px;
right: 10px;
width: 50%;
top: 80%;
max-width: 300px;
background: #777;
box-shadow: 0 18px 20px #777;
transform: rotate(8deg);
}
<div class="type-product box">
</div>
Hope you like it.

How do I make a div triangle with concave left border?

I'm trying to make this shape in CSS. I haven´t been able to get it perfectly.
Check this out, I have done with the :before pseudo class. We can tweak the below snippet to make it look like what you need:
.triangle {
width: 0;
height: 0;
border-style: solid;
border-width: 50px 0 50px 86.6px;
border-color: transparent transparent transparent #f00;
}
.triangle:before {
display: block;
content: " ";
position: absolute;
height: 100px;
width: 10px;
left: 3px;
top: 8px;
background: #fff;
border-radius: 100%;
}
<div class="triangle"></div>
Another try:
.triangle {
width: 0;
height: 0;
border-style: solid;
border-width: 50px 0 50px 86.6px;
border-color: transparent transparent transparent #f00;
}
.triangle:before {
display: block;
content: " ";
position: absolute;
height: 180px;
width: 110px;
left: -90px;
top: -30px;
background: #fff;
border-radius: 200%;
}
<div class="triangle"></div>
This solution relies soley on CSS generated content, meaning no extra markup. The only caveat, is that ::after background color must match parent element background color.
div::before {
content:'';
position:absolute;
width: 0;
height: 0;
border-style: solid;
border-width: 50px 0 50px 100px;
border-color: transparent transparent transparent #007bff;
}
div::after{
content:'';
display:block;
width:50px;
background:#fff;
height:100px;
position:absolute;
border-radius:0 100% 100% 0;
transform: scaleX(0.4);
transform-origin:top left;
}
Demo here

Resources