Making a moving border animation work on a square element - html

I am trying to get a moving border CSS animation to work on a square but I can't quite work out how to get it to work. It works fine on a circle as I just use the rotate transition with the key frames. This is my current markup.
.box {
width: 50px;
height: 50px;
margin: 50px auto;
border: 1px solid rgba(0, 0, 0, 0.1);
border-radius: 50%;
position: relative;
-webkit-transition: all 1s ease;
transition: all 1s ease;
}
.box .border {
position: absolute;
top: -4px;
left: -4px;
width: 50px;
height: 50px;
background: transparent;
border: 4px solid transparent;
border-top-color: orangered;
border-radius: 50%;
animation-name: border;
-webkit-animation-duration: 2s;
-webkit-animation-iteration-count: infinite;
-webkit-animation-timing-function: linear;
}
#-webkit-keyframes border {
from {
-webkit-transform: rotate(0deg);
}
to {
-webkit-transform: rotate(360deg);
}
<div class="box">
<div class="border"></div>
</div>

The animation in question is using a rotate transform with a stationary border to create the illusion of a moving border whereas it actually is not. With a square, you cannot use a similar model as when we rotate a square it doesn't stay the same like a circle does.
So the available options would be to make use of a SVG stroke-dashoffset based animation like in the below snippet. The stroke-dasharray property provides the length/width of the stroke (1st param) and the length/width of the space (2nd param). The stroke-dashoffset property specifies the offset from the start position at which the stroke should be painted.
polygon {
stroke: red;
stroke-width: 3;
stroke-dasharray: 50, 750;
stroke-dashoffset: 0;
fill: none;
animation: border 5s linear infinite;
}
#keyframes border {
to {
stroke-dashoffset: -800;
}
}
<svg width="210" height="210">
<polygon points="5,5 205,5 205,205 5,205" />
</svg>
If you want a pure CSS solution then you could make use of a linear-gradient based solution like in the below snippet. Here we create four strips of background images based on linear gradients which are of the same thickness of the border. These strips have the color for the required width and is then transparent for the rest. By animating the background-position , we can get something that is close to the effect that we are looking for.
Note that background-position animation works only with fixed pixel values and so the dimensions of the box need be known prior. Everytime the value changes, the background-position values need to be re-configured accordingly.
div {
height: 200px;
width: 200px;
box-sizing: border-box;
background-image: linear-gradient(to right, red 50px, transparent 50px), linear-gradient(to bottom, red 50px, transparent 50px), linear-gradient(to right, red 50px, transparent 50px), linear-gradient(to bottom, red 50px, transparent 50px);
background-size: 100% 3px, 3px 100%, 100% 3px, 3px 100%; /* one of the values is the border thickness, other is 100% */
background-repeat: no-repeat;
background-position: -50px 0px, right -50px, 200px bottom, 0px 200px; /* positions such that none of the images are visible at start */
animation: border 5s linear; /* add infinite if you need infinite animation */
}
#keyframes border {
/* animate position such that they come into view and go out of it one by one */
25% {
background-position: 200px 0px, right -50px, 200px bottom, 0px 200px;
}
50% {
background-position: 200px 0px, right 200px, 200px bottom, 0px 200px;
}
75% {
background-position: 200px 0px, right 200px, -50px bottom, 0px 200px;
}
100% {
background-position: 200px 0px, right 200px, -50px bottom, 0px -50px;
}
}
<div class='border-animation'></div>
If you want a pure CSS solution more closer to the SVG one then we can add more keyframes to the animation like the below snippet.
div {
height: 200px;
width: 200px;
box-sizing: border-box;
background-image: linear-gradient(to right, red 50px, transparent 50px), linear-gradient(to bottom, red 50px, transparent 50px), linear-gradient(to right, red 50px, transparent 50px), linear-gradient(to bottom, red 50px, transparent 50px);
background-size: 100% 3px, 3px 100%, 100% 3px, 3px 100%;
background-repeat: no-repeat;
background-position: -50px 0px, right -50px, 200px bottom, 0px 200px;
animation: border 5s linear;
}
#keyframes border {
20% {
background-position: 150px 0px, right -50px, 200px bottom, 0px 200px;
}
25% {
background-position: 200px 0px, right 0px, 200px bottom, 0px 200px;
}
45% {
background-position: 200px 0px, right 150px, 200px bottom, 0px 200px;
}
50% {
background-position: 200px 0px, right 200px, 150px bottom, 0px 200px;
}
70% {
background-position: 200px 0px, right 200px, 0px bottom, 0px 200px;
}
75% {
background-position: 200px 0px, right 200px, -50px bottom, 0px 150px;
}
95% {
background-position: 200px 0px, right 200px, -50px bottom, 0px 0px;
}
100% {
background-position: 200px 0px, right 200px, -50px bottom, 0px -50px;
}
}
<div class='border-animation'></div>
Here is an even more complete looking infinite animation using pure CSS:
div {
height: 200px;
width: 200px;
box-sizing: border-box;
background-image: linear-gradient(to right, red 50px, transparent 50px), linear-gradient(to bottom, red 50px, transparent 50px), linear-gradient(to right, red 50px, transparent 50px), linear-gradient(to bottom, red 50px, transparent 50px);
background-size: 100% 3px, 3px 100%, 100% 3px, 3px 100%;
background-repeat: no-repeat;
background-position: 0px 0px, right -50px, 200px bottom, 0px 200px;
animation: border 5s linear infinite;
}
#keyframes border {
20% {
background-position: 150px 0px, right -50px, 200px bottom, 0px 200px;
}
25% {
background-position: 200px 0px, right 0px, 200px bottom, 0px 200px;
}
45% {
background-position: 200px 0px, right 150px, 200px bottom, 0px 200px;
}
50% {
background-position: 200px 0px, right 200px, 150px bottom, 0px 200px;
}
70% {
background-position: 200px 0px, right 200px, 0px bottom, 0px 200px;
}
75% {
background-position: 200px 0px, right 200px, -50px bottom, 0px 150px;
}
95% {
background-position: 200px 0px, right 200px, -50px bottom, 0px 0px;
}
95.1% {
background-position: -50px 0px, right 200px, -50px bottom, 0px 0px;
}
100% {
background-position: 0px 0px, right 200px, -50px bottom, 0px -50px;
}
}
<div class='border-animation'></div>

You can pure css3 animated border to accomplish your task by just adding animated-border.min.css file. here is the code snippet.
<a href="ui-box top-leftStart">
<span class='ui-border-element'>
Animated Hyperlink
</span>
</a>
Include this css file : https://cdn.jsdelivr.net/gh/code-fx/Pure-CSS3-Animated-Border#V1.0/css/animated-border/animated-border.min.css
Demo link : https://code-fx.github.io/Pure-CSS3-Animated-Border/
I have created this demo page.

Related

Uneven Border on Corners

How could I create a border somewhere among the lines of this?
I've tried using linear gradients for backgrounds (found here) but can't seem to get it to draw the shape I'm looking for.
You could use before and after pseudo elements on the main element to create a background. One would be a red rectangle, and in front of it a white rectangle with CSS clip-path used to get the shape.
Here's an example. Obviously change the % values to be what you want (could be px if that is required).
body {
background: black;
width: 100vw;
height: 100vh;
}
div {
width: 30vmin;
height: 50vmin;
display: inline-block;
position: relative;
transform: translate(-50%, -50%);
top: 50%;
left: 50%;
}
div::before,
div::after {
position: absolute;
content: '';
left: 0;
right: 0;
width: 100%;
height: 100%;
z-index: -1;
}
div::before {
background: red;
}
div::after {
background: white;
clip-path: polygon(5% 5%, 50% 0, 95% 5%, 100% 30%, 100% 70%, 95% 95%, 70% 100%, 30% 100%, 5% 95%, 0 70%, 0 30%);
}
<div></div>
If you are looking for a gradient, here is an idea using conic-gradient. All you have to do is adjust a few variables to control the shape
.box {
--size: 15px;
--angle: 250deg;
--g: red var(--angle), lightblue 0; /* the colors here */
background:
conic-gradient(from calc(var(--angle)/-2 - 45deg)
at top var(--size) left var(--size),var(--g)) top left,
conic-gradient(from calc(var(--angle)/-2 + 45deg)
at top var(--size) right var(--size),var(--g)) top right,
conic-gradient(from calc(var(--angle)/-2 - 135deg)
at bottom var(--size) left var(--size),var(--g)) bottom left,
conic-gradient(from calc(var(--angle)/-2 + 135deg)
at bottom var(--size) right var(--size),var(--g)) bottom right;
background-size: 51% 51%;
background-repeat: no-repeat;
width: 300px;
height: 300px;
display: inline-block;
}
<div class="box"></div>
<div class="box" style="--size:10px; --angle: 255deg"></div>

How can I combine a circle in a polygon using clip-path and add a shadow

I am new to using the css property clip-path and have created a shape that almost fits the requirement I have.
I am looking to create the following shape however struggling to convert the squares I have to circles.
.ticket {
background-color: blue;
height: 100px;
width: 200px;
border-radius: 10px;
box-shadow: 0 0.5rem 1rem rgb(0 0 0 / 15%);
clip-path: polygon(
0 0,
0% 42%,
5% 42%,
5% 58%,
0 58%,
0 100%,
100% 100%,
100% 58%,
95% 58%,
95% 42%,
100% 42%,
100% 0
);
}
<div class="ticket"></div>
Is this possible using this property? If not, how could I achieve this using a SVG instead? Is it also possible to add a drop shadow to this clipped mask? As you can see in the snippet the shadow doesn't really work.
If it's only a solid coloration, background can do it:
.ticket {
background:
radial-gradient(20px at right, #0000 97%,blue) right,
radial-gradient(20px at left , #0000 97%,blue) left;
background-size: 51% 100%;
background-repeat: no-repeat;
height: 100px;
width: 200px;
border-radius: 10px;
filter: drop-shadow(0 0.5rem 0.2rem rgb(0 0 0 / 50%));
}
<div class="ticket"></div>
It is possible to 'cut holes' using the mask-image property and radial-gradients.
This snippet uses your code but replacing the clip-path with circle radial-gradient masks. Obviously you can change the percentages depending on hole-size required.
body {
background: cyan;
}
.ticket {
background-color: blue;
height: 100px;
width: 200px;
border-radius: 10px;
box-shadow: 0 0.5rem 1rem rgb(0 0 0 / 15%);
--mask1: radial-gradient(circle at 0 50%, transparent 0, transparent 5%, black 5%, black 90%, transparent 90%, transparent);
--mask2: radial-gradient(circle at 100% 50%, transparent 0, transparent 5%, black 5%, black 90%, transparent 90%, transparent);
/* webkit needed for Chrome */
-webkit-mask-image: var(--mask1), var(--mask2);
mask-image: var(--mask1), var(--mask2);
}
<div class="ticket"></div>
(body has been given a background just to prove that holes have been cut rather than white circles drawn which is what would have happened with pseudo elements).
The box shadow is more problematic as it gets masked (or clipped as in the question's code). Box-shadow on element with -webkit-mask-image has ideas on putting a shadow on a containing element which has the mask image(s) as background images(s) but putting a shadow into the holes is still a problem. Perhaps just putting a slightly bigger container with gradient gray/transparent backgrounds would do enough, with the 'holes' varying transparent grays rather than just transparent. Seems hacky though.
Here is my solution for both contained and outlined coupons with mask-image and radial-gradient .
In order to draw an outlined coupon, I use two backgrounds and masks, each of which is only a half part to avoid overlapping of radial-gradient.
.wrapper {
display: flex;
gap: 30px;
--coupon-side-radius: 6px;
--coupon-background-color: #c39f76;
--coupon-border-color: #c39f76;
--coupon-border-width: 1px;
}
.coupon {
width: 100px;
height: 100px;
border: var(--coupon-border-width, 1px) solid var(--coupon-border-color);
border-radius: 6px;
box-sizing: border-box;
background: radial-gradient(
circle at center left,
transparent 0px var(--coupon-side-radius),
var(--coupon-border-color) var(--coupon-side-radius)
calc(var(--coupon-side-radius) + var(--coupon-border-width, 0.5px)),
var(--coupon-background-color) calc(var(--coupon-side-radius) + var(--coupon-border-width) + 0.5px)
)
border-box,
radial-gradient(
circle at center right,
transparent 0px var(--coupon-side-radius),
var(--coupon-border-color) var(--coupon-side-radius)
calc(var(--coupon-side-radius) + var(--coupon-border-width, 0.5px)),
var(--coupon-background-color) calc(var(--coupon-side-radius) + var(--coupon-border-width, 0.5px) + 0.5px)
)
border-box;
background-size: 50% 100%, 50% 100%;
background-position: 0% 100%, 100% 100%;
background-repeat: no-repeat, no-repeat;
-webkit-mask-image: radial-gradient(
circle at center left,
transparent 0,
transparent var(--coupon-side-radius),
#000 calc(var(--coupon-side-radius) + 0.5px)
),
radial-gradient(
circle at center right,
transparent 0,
transparent var(--coupon-side-radius),
#000 calc(var(--coupon-side-radius) + 0.5px)
);
-webkit-mask-size: 50% 100%, 50% 100%;
-webkit-mask-position: 0% 100%, 100% 100%;
-webkit-mask-repeat: no-repeat, no-repeat;
}
.coupon1 {
--coupon-side-radius: 6px;
--coupon-background-color: #c39f76;
--coupon-border-color: #c39f76;
--coupon-border-width: 1px;
}
.coupon2 {
--coupon-side-radius: 6px;
--coupon-border-color: red;
--coupon-border-width: 1px;
--coupon-background-color: #c39f76;
}
.coupon3 {
--coupon-side-radius: 6px;
--coupon-background-color: transparent;
--coupon-border-color: red;
--coupon-border-width: 1px;
}
.coupon4 {
--coupon-side-radius: 6px;
--coupon-background-color: transparent;
--coupon-border-color: red;
--coupon-border-width: 2px;
}
.coupon5 {
--coupon-side-radius: 6px;
--coupon-background-color: transparent;
--coupon-border-color: red;
--coupon-border-width: 0.5px;
border: none !important;
position: relative;
}
.coupon5::before{
content: "";
position: absolute;
top: 0px;
left: 0px;
box-sizing: border-box;
width: 200%;
height: 200%;
transform: scale(0.5);
transform-origin: left top;
border: 1px solid red;
border-radius: 16px;
opacity: 0.7;
}
.coupon-demo {
width: 100px;
height: 100px;
border: 2px solid red;
border-radius: 15px;
background: radial-gradient(
circle at center left,
transparent 0px 6px,
red 6px 8px,
#fff 9px
)
border-box,
radial-gradient(
circle at center right,
transparent 0px 6px,
red 6px 8px,
#c39f76 9px
)
border-box;
background-size: 51% 100%, 50% 100%;
background-position: 0% 100%, 100% 100%;
background-repeat: no-repeat, no-repeat;
-webkit-mask-image: radial-gradient(
circle at center left,
transparent 0,
transparent 6px,
red 7px
),
radial-gradient(
circle at center right,
transparent 0,
transparent 6px,
red 7px
);
-webkit-mask-size: 50% 100%, 50% 100%;
-webkit-mask-position: 0% 100%, 100% 100%;
-webkit-mask-repeat: no-repeat, no-repeat;
}
<div class="wrapper">
<div class="coupon coupon1">1. Contained</div>
<div class="coupon coupon2">2. Contained + Outlined</div>
<div class="coupon coupon3">3. Outlined</div>
<div class="coupon coupon4">4. Border 2px</div>
<div class="coupon coupon5">5. Border 0.5px </div>
<div class="coupon-demo">6. For debug purpose </div>
<div>

How to get a border around this polygon?

I have created a shape with 5 corners using polygon as shown below.
This is the css needed to make it:
div {
width: 280px;
height: 280px;
background: #1e90ff;
-webkit-clip-path: polygon(75% 0%, 100% 50%, 75% 100%, 0% 100%, 0 48%, 0% 0%);
clip-path: polygon(75% 0%, 100% 50%, 75% 100%, 0% 100%, 0 48%, 0% 0%);
border: 3px solid black;
border-bottom-left-radius: 15px;
border-top-left-radius: 15px;
}
Unfortunately I cannot get it to add a black border all around the shape (it is missing on the right side). How would I do that?
I have created a fiddle here.
The border property goes around the outside of an element, and the clip-path property applies a mask to an element. So, as far as other CSS rules are concerned, you're still dealing with a rectangle. Because of this, you can't simply apply a border.
It's not impossible to get very close to the effect you want, however. Using (and abusing) CSS pseudo-elements, borders, and filters you can create the same shape plus an outline with only a single HTML div.
div {
position: relative;
width: 210px;
height: 280px;
background: #1e90ff;
border-bottom-left-radius: 15px;
border-top-left-radius: 15px;
filter:
drop-shadow( 0px 3px 0 black)
drop-shadow( 0px -3px 0 black)
drop-shadow( 3px 0px 0 black)
drop-shadow(-3px 0px 0 black);
-webkit-filter:
drop-shadow( 0px 3px 0 black)
drop-shadow( 0px -3px 0 black)
drop-shadow( 3px 0px 0 black)
drop-shadow(-3px 0px 0 black);
}
div::after {
position: absolute;
display: block;
content: '';
width: 0;
height: 0;
left: 210px;
top: 0;
border-left: 70px solid #1e90ff;
border-right: 70px solid transparent;
border-top: 140px solid transparent;
border-bottom: 140px solid transparent;
}
<div>
</div>
So, what's going on here?
The main div element is just the rectangular portion of the shape (with rounded top-left and bottom-left corners). It also has an ::after pseudo-element which creates the triangle shape. The triangle shape is done using the CSS border-triangle hack.
Okay, so that creates the shape without having to mask off any of the element, but a border still can't be applied directly, since I've already (ab)used the border to create the triangle. Using a CSS outline or box-shadow would be the next logical choice, but both properties go all the way around the element's bounding-box... ignoring features like rounded corners or hacky transparent borders.
Enter the CSS filter property. This provides a family of post-processing filters. The important thing to note is that they treat the element as a transparency mask when being applied, rather than respecting the element's bounding-box... and there is a drop-shadow filter!
Unfortunately, it's not quite as flexible as the box-shadow property in that it doesn't have a "spread" parameter which can be used to create solid shapes that are larger than the element. To get around this, we need to cast a drop-shadow in every direction: up, down, right, and left. That's where this monstrosity comes in:
filter:
drop-shadow( 0px 3px 0 black)
drop-shadow( 0px -3px 0 black)
drop-shadow( 3px 0px 0 black)
drop-shadow(-3px 0px 0 black);
Ta-da!
Expanding on this: this works on any shape you can manage to create (as long as it done without clipping). Just apply a drop-shadow filter to the element, or to a parent/wrapper div (if it's a multi-element shape) to get a border.
I'm on a bit of a pseudo kick here, but You can always recreate the element with a black color and throw it behind the original, giving the impression of an outline. Suitable for most purposes, the proposal is demonstrated in this codepen: http://codepen.io/anon/pen/MeJorM
CSS in the codepen has been changed up a bit. Your original is ".orig".
div.orig {
position:relative;
width: 280px;
height: 280px;
background: #1e90ff;
-webkit-clip-path: polygon(75% 0%, 100% 50%, 75% 100%, 0% 100%, 0 48%, 0% 0%);
clip-path: polygon(75% 0%, 100% 50%, 75% 100%, 0% 100%, 0 48%, 0% 0%);
border: 1px solid black;
border-bottom-left-radius: 15px;
border-top-left-radius: 15px;
display:block;
}
div.abc {
position:relative;
width: 280px;
height: 280px;
background: #000;
-webkit-clip-path: polygon(75% 0%, 100% 50%, 75% 100%, 0% 100%, 0 48%, 0% 0%);
clip-path: polygon(75% 0%, 100% 50%, 75% 100%, 0% 100%, 0 48%, 0% 0%);
border: 1px solid black;
border-bottom-left-radius: 15px;
border-top-left-radius: 15px;
display:block;
}
div.abc div.def{
top:-0.02em;
left:-0.2em;
position:absolute;
display:block;
width: 278px;
height: 280px;
background: #1e90ff;
-webkit-clip-path: polygon(75% 0%, 100% 50%, 75% 100%, 0% 100%, 0 48%, 0% 0%);
clip-path: polygon(75% 0%, 100% 50%, 75% 100%, 0% 100%, 0 48%, 0% 0%);
border: 1px solid black;
border-bottom-left-radius: 15px;
border-top-left-radius: 15px;
}

Keyframe animation appearing from the center

I am creating a keyframe transition sequence. I am wanting the circle to appear for two seconds and then the star to appear for the other two seconds. I am running into a couple of issues.
Why is my star turning into a rectangle at the end of the animation?
How can I get the star to appear from the center rather than the top-left corner sliding in diagonally?
Why does my red circle disappear for a second or two and then the star appear?
Does anyone know what I am doing wrong?
body {
background-color: #F5F5F5;
color: #555;
font-size: 1.1em;
font-family: 'Lato', sans-serif;
}
.star {
background-color: #f1c40f;
color: white;
width: 250px;
height: 250px;
margin: 30px auto;
text-align: justify;
-webkit-animation-name: example; /* Chrome, Safari, Opera */
-webkit-animation-duration: 4s; /* Chrome, Safari, Opera */
-webkit-animation-iteration-count: 1 forwards; /* Chrome, Safari, Opera */
animation-name: example;
animation-duration: 4s;
animation-iteration-count: 1 forwards;
}
/* Chrome, Safari, Opera */
#-webkit-keyframes example {
0%, 49% {
background-color: red;
left: 0px;
top: 0px;
height: 50px;
width: 50px;
border-radius: 50%;
}
50%,
100% {
shape-inside: polygon(125px 0, 175px 85px, 250px 90px, 190px 160px, 225px 250px, 125px 210px, 25px 250px, 60px 160px, 0px 90px, 75px 85px);
shape-padding: 10px;
/*transition: all 1s ease; */
-webkit-clip-path: polygon(125px 0, 175px 85px, 250px 90px, 190px 160px, 225px 250px, 125px 210px, 25px 250px, 60px 160px, 0px 90px, 75px 85px);
}
/* Standard syntax */
#keyframes example {
0%, 49% {
background-color: red;
left: 0px;
top: 0px;
height: 50px;
width: 50px;
border-radius: 50%;
}
50%,
100% {
shape-inside: polygon(125px 0, 175px 85px, 250px 90px, 190px 160px, 225px 250px, 125px 210px, 25px 250px, 60px 160px, 0px 90px, 75px 85px);
shape-padding: 10px;
/* transition: all 1s ease; */
-webkit-clip-path: polygon(125px 0, 175px 85px, 250px 90px, 190px 160px, 225px 250px, 125px 210px, 25px 250px, 60px 160px, 0px 90px, 75px 85px);
}
}
<div class="star">
</div>
Why is my star turning into a rectangle at the end of the animation?
That's because what probably is a typo error in the below line. You have set forwards to the iteration count property and so the animation-fill-mode takes its default value (which is none). This makes the div.star to snap back to its original shape (the one before start of the animation, a square) once the animation has completed. Removing the forwards from the below line and setting it to the correct property will solve this issue.
animation-iteration-count: 1 forwards;
How can I get the star to appear from the center rather than the top-left corner sliding in diagonally?
Well, getting the star to appear from center (as though its growing) is going to be almost impossible. I will explain the why part a bit later but why the star looks like it is sliding in diagonally is rather simple to explain. The element's initial dimension is 250x250, once the animation starts it is 50x50 and stays that way till 49% of the animation. At 50% no height or width is specified and so the element starts to grow gradually from 50x50 to its original size, which is. 250x250 (this growth will complete at 100%). Since the element has margin: 0 auto, it is always center aligned with respect to the container and so when it grows to its full size, it looks like the top-center point (50%, 0%) point is fixed and element expands towards right, left and bottom. Now this coupled with the clip-path produces the diagonal movement effect.
Snippet showing how the element grows without clip-path:
body {
background-color: #F5F5F5;
color: #555;
font-size: 1.1em;
font-family: 'Lato', sans-serif;
}
.star {
background-color: #f1c40f;
color: white;
width: 250px;
height: 250px;
margin: 30px auto;
text-align: justify;
animation-name: example;
animation-duration: 4s;
animation-iteration-count: 1;
animation-fill-mode: forwards;
}
#keyframes example {
0%, 49% {
height: 50px;
width: 50px;
}
50%,
100% {}
}
<div class="star">
</div>
Snippet showing the clip-paths effect at 5 stages during the growth:
Below snippet would make the reason for the slide more clear as you can see how the shape looks at 5 stages during the growth (from 50x50 to 250x250)
body {
background-color: #F5F5F5;
color: #555;
font-size: 1.1em;
font-family: 'Lato', sans-serif;
}
.star {
background-color: #f1c40f;
color: white;
margin: 30px auto;
text-align: justify;
-webkit-clip-path: polygon(125px 0, 175px 85px, 250px 90px, 190px 160px, 225px 250px, 125px 210px, 25px 250px, 60px 160px, 0px 90px, 75px 85px);
}
.dim-50 {
height: 50px;
width: 50px;
}
.dim-100 {
height: 100px;
width: 100px;
}
.dim-150 {
height: 150px;
width: 150px;
}
.dim-200 {
height: 200px;
width: 200px;
}
.dim-250 {
height: 250px;
width: 250px;
}
<div class="star dim-50">
</div>
<div class="star dim-100">
</div>
<div class="star dim-150">
</div>
<div class="star dim-200">
</div>
<div class="star dim-250">
</div>
Why does my red circle disappear for a second or two and then the star appear?
This is partly because of the clip-path and a lack of height and width setting within 50%, 100% keyframe. Since the element is only gradually growing from 50x50 to 250x250 (and it reaches its full size only by the end), the clip-path that you've designed based on original size (250x250) in mind actually starts working only at around 68.75% mark. This is because of the pixel values used in the clip-path. For example, the first point is 125,0 but the element's width is only 50px at 49% and so its width becomes 125px only at 68.75% (200px increase in 50% duration would mean 18.75% time for 75px increase assuming a linear timing function, for ease it'd be a bit longer but you get the point). Because of this, from the 50% mark approximately till the 68.75% mark you get to see nothing.
Another reason for the disappearance can also be attributed to the lack of a clip-path setting in the 0%, 49% keyframes. Because of this, the clip-path of the element is slowly animated from no clip at the start to the actual clip-path at 50% mark.
Solutions:
There are two solutions and they are as follows:
Use your original approach, add height: 250px, width: 250px and border-radius: 0% to the 50%, 100% keyframes. Set a dummy clip-path on the element at 0%, 49% keyframes.
body {
background-color: #F5F5F5;
color: #555;
font-size: 1.1em;
font-family: 'Lato', sans-serif;
}
.star {
background-color: #f1c40f;
color: white;
width: 250px;
height: 250px;
margin: 30px auto;
text-align: justify;
animation-name: example;
animation-duration: 4s;
animation-iteration-count: 1;
animation-fill-mode: forwards;
}
#keyframes example {
0%, 49% {
background-color: red;
height: 50px;
width: 50px;
border-radius: 50%;
-webkit-clip-path: polygon(0 0, 50px 0, 50px 50px, 0 50px, 0 0, 0 0, 0 0, 0 0, 0 0, 0 0);
}
50%,
100% {
height: 250px;
width: 250px;
border-radius: 0%;
shape-inside: polygon(125px 0, 175px 85px, 250px 90px, 190px 160px, 225px 250px, 125px 210px, 25px 250px, 60px 160px, 0px 90px, 75px 85px);
shape-padding: 10px;
-webkit-clip-path: polygon(125px 0px, 175px 85px, 250px 90px, 190px 160px, 225px 250px, 125px 210px, 25px 250px, 60px 160px, 0px 90px, 75px 85px);
}
}
<div class="star">
</div>
Set the element's height and width as 250px at the start of the animation itself, use a circular clip-path with 25px radius to produce the circle. This way we can avoid the need for a dummy clip-path. I prefer this approach just because it needs no dummy clip-path.
body {
background-color: #F5F5F5;
color: #555;
font-size: 1.1em;
font-family: 'Lato', sans-serif;
}
.star {
background-color: #f1c40f;
color: white;
width: 250px;
height: 250px;
margin: 30px auto;
text-align: justify;
animation-name: example;
animation-duration: 4s;
animation-iteration-count: 1;
animation-fill-mode: forwards;
}
#keyframes example {
0%, 49% {
background-color: red;
height: 250px;
width: 250px;
-webkit-clip-path: circle(25px at center);
}
50%,
100% {
height: 250px;
width: 250px;
shape-inside: polygon(125px 0, 175px 85px, 250px 90px, 190px 160px, 225px 250px, 125px 210px, 25px 250px, 60px 160px, 0px 90px, 75px 85px);
shape-padding: 10px;
-webkit-clip-path: polygon(125px 0, 175px 85px, 250px 90px, 190px 160px, 225px 250px, 125px 210px, 25px 250px, 60px 160px, 0px 90px, 75px 85px);
}
}
<div class="star">
</div>

How to achieve chamfered CSS Border Corners rather than rounded corners?

With the CSS border-radius property I can have a curvy, rounded border corner at the end.
.boxLeft{
border-right: 1px dashed #333;
border-bottom: 1px dashed #333;
border-radius: 0 0 10px 0;
}
.boxRight{
border-left: 1px dashed #333;
border-bottom: 1px dashed #333;
border-radius: 0 0 0 10px;
}
But I want a border corner like the image below. If I have two boxes (Yellow & Pink) meeting each other and I want a harsh corner at the bottom meeting point (dotted corner), what should I do?
Is that possible using CSS?
CSS3 Gradients can do the trick:
Try this, Here's a Fiddle.
div {
background: #c00;
/* fallback */
background: -moz-linear-gradient(45deg, transparent 10px, #c00 10px), -moz-linear-gradient(135deg, transparent 10px, #c00 10px), -moz-linear-gradient(225deg, transparent 10px, #c00 10px), -moz-linear-gradient(315deg, transparent 10px, #c00 10px);
background: -o-linear-gradient(45deg, transparent 10px, #c00 10px), -o-linear-gradient(135deg, transparent 10px, #c00 10px), -o-linear-gradient(225deg, transparent 10px, #c00 10px), -o-linear-gradient(315deg, transparent 10px, #c00 10px);
background: -webkit-linear-gradient(45deg, transparent 10px, #c00 10px), -webkit-linear-gradient(135deg, transparent 10px, #c00 10px), -webkit-linear-gradient(225deg, transparent 10px, #c00 10px), -webkit-linear-gradient(315deg, transparent 10px, #c00 10px);
}
div {
background-position: bottom left, bottom right, top right, top left;
-moz-background-size: 50% 50%;
-webkit-background-size: 50% 50%;
background-size: 50% 50%;
background-repeat: no-repeat;
}
/* Ignore the CSS from this point, it's just to make the demo more presentable */
div {
float: left;
width: 50px;
margin: 15px auto;
padding: 15px;
color: white;
line-height: 1.5;
}
<div>Div 1</div>
<div>Div 2</div>
Here's a way, although it does have some shortcomings, like no borders and it isn't transparent:
.left,
.right {
width: 100px;
height: 100px;
float: left;
position: relative;
}
.left {
background: lightpink;
}
.right {
background: lightblue;
}
.right::after,
.left::after {
width: 0px;
height: 0px;
background: #fff;
content: '';
position: absolute;
bottom: 0;
}
.right::after {
left: 0;
border-top: 10px solid lightblue;
border-right: 10px solid lightblue;
border-left: 10px solid white;
border-bottom: 10px solid white;
}
.left::after {
right: 0;
border-top: 10px solid lightpink;
border-right: 10px solid white;
border-left: 10px solid lightpink;
border-bottom: 10px solid white;
}
<div class="left"></div>
<div class="right"></div>
RESULT:
Here's a fiddle.
This is also possible using "clip-path".
-webkit-clip-path: polygon(20% 0%, 80% 0%, 100% 20%, 100% 80%, 80% 100%, 20% 100%, 0% 80%, 0% 20%);
clip-path: polygon(20% 0%, 80% 0%, 100% 20%, 100% 80%, 80% 100%, 20% 100%, 0% 80%, 0% 20%);
div {
width: 200px;
height: 200px;
background: red;
-webkit-clip-path: polygon(20% 0%, 80% 0%, 100% 20%, 100% 80%, 80% 100%, 20% 100%, 0% 80%, 0% 20%);
clip-path: polygon(20% 0%, 80% 0%, 100% 20%, 100% 80%, 80% 100%, 20% 100%, 0% 80%, 0% 20%);
}
<div></div>
Source Codepen
Support for clip-path can be found here... http://caniuse.com/#search=clip-path
I first tested #thordarson solution with position: 'absolute'.
position: 'absolute',
top: '2.9rem',
left: '2.6rem',
borderLeft: '1rem solid #6CAEC6',
borderBottom: '0.7rem solid white',
This worked fine on most devices as shown in the first picture but when used on iPhones or tablets weird lines started showing up:
As #Collins answer I then started using clip-path: polygon but I had quite a hard time getting the correct shapes. I then found a site that really helped me:
https://bennettfeely.com/clippy/
They offer ready shapes that can then be dragged to a desired shape.
For the corner that I needed I could then copy the correct values from the website.
A requirement for us was a 35° angle and to get that right I used the site:
https://www.ginifab.com/feeds/angle_measurement/
I have no affiliation with any of the sites, they just really helped me get what I wanted. With clip-path: polygon and -webkit-clip-path: polygon it worked on all devices and browsers that we had as a requirement.
Compatibility check:
https://caniuse.com/#feat=css-clip-path
This is what you need, transparency and everything
.left,
.right {
width: 100px;
height: 100px;
float: left;
position: relative;
overflow: hidden;
}
.right::after,
.left::after {
content: '';
width: 200px;
height: 200px;
position: absolute;
-moz-transform: rotate(45deg);
-webkit-transform: rotate(45deg);
-o-transform: rotate(45deg);
-ms-transform: rotate(45deg);
transform: rotate(45deg);
}
.right::after {
background: lightblue;
left: -40px;
top: -100px;
}
.left::after {
background: lightpink;
left: -60px;
top: -100px;
}
<div class="left"></div>
<div class="right"></div>
A good The best way to archive this: border-images. In combination with .svg a good solution...
++ Includes Westworld Style UI in CSS ++
I've updated AlphaMale's awesome answer to hack chamfered borders as originally requested. It basically uses one chamfered div with a slightly smaller on inside it. The outer div's background colour becomes the border colour when the rest of it is covered up by the inner div with matching chamfers.
Tested in Edge, Chrome and Firefox.
I found this page while looking to duplicate something like the Westworld User Interface which has unequal chamfered corners. See the JS fiddle for how I've cobbled this together along with a colour scheme and example box from the Westworld speech chaining scene.
Code on JSFiddle (CSS below): http://jsfiddle.net/S2nqK/345/
Westworld UI pic at: https://qph.ec.quoracdn.net/main-qimg-44c9f03b2abfe9f3833763eece1b0cc4?convert_to_webp=true
body {background-color: #353535;
font-family: 'Open Sans';}
.div-outer {
/* Chrome / Safari */
background:
-webkit-linear-gradient(45deg, transparent 0px, #6ea1a1 0px), /* bottom left */
-webkit-linear-gradient(135deg, transparent 14px, #6ea1a1 14px), /* bottom right */
-webkit-linear-gradient(225deg, transparent 0px, #6ea1a1 0px), /* top right */
-webkit-linear-gradient(315deg, transparent 5px, #6ea1a1 5px); /* top left */
/* Firefox */
background:
-moz-linear-gradient(45deg, transparent 0px, #6ea1a1 0px), /* bottom left */
-moz-linear-gradient(135deg, transparent 14px, #6ea1a1 14px), /* bottom right */
-moz-linear-gradient(225deg, transparent 0px, #6ea1a1 0px), /* top right */
-moz-linear-gradient(315deg, transparent 5px, #6ea1a1 5px); /* top left */
/* Opera */
background:
-o-linear-gradient(45deg, transparent 0px, #6ea1a1 0px), /* bottom left */
-o-linear-gradient(135deg, transparent 14px, #6ea1a1 14px), /* bottom right */
-o-linear-gradient(225deg, transparent 0px, #6ea1a1 0px), /* top right */
-o-linear-gradient(315deg, transparent 5px, #6ea1a1 5px); /* top left */
padding: 2px;
color: #fff;
}
.div-inner {
background:
-webkit-linear-gradient(45deg, transparent 0px, #000 0px),
-webkit-linear-gradient(135deg, transparent 14px, #000 14px),
-webkit-linear-gradient(225deg, transparent 0px, #000 0px),
-webkit-linear-gradient(315deg, transparent 5px, #000 5px);
background:
-moz-linear-gradient(45deg, transparent 0px, #000 0px),
-moz-linear-gradient(135deg, transparent 14px, #000 14px),
-moz-linear-gradient(225deg, transparent 0px, #000 0px),
-moz-linear-gradient(315deg, transparent 5px, #000 5px);
background:
-o-linear-gradient(45deg, transparent 0px, #000 0px),
-o-linear-gradient(135deg, transparent 14px, #000 14px),
-o-linear-gradient(225deg, transparent 0px, #000 0px),
-o-linear-gradient(315deg, transparent 5px, #000 5px);
padding: 10px;
height: 92px;
text-align: center;
}
.div-outer, .div-inner {
background-position: bottom left, bottom right, top right, top left;
-moz-background-size: 50% 50%;
-webkit-background-size: 50% 50%;
background-size: 50% 50%;
background-repeat: no-repeat;
}
.contain {
width: 180px;
}
.title {background-color: #76ffff;
padding: 6px;
color: #000;
border-radius: 2px;
font-weight: bold;
text-align-last: justify;
text-align: justify;
}
.font-large {font-size: 34pt;}
.font-tiny {font-size: 10pt;}
.cyan {color: #76ffff;}
/* Ignore the CSS from this point, it's just to make the demo more presentable */
.arrow-right {
width: 0;
height: 0;
border-top: 8px solid transparent;
border-bottom: 8px solid transparent;
border-left: 8px solid #fff;
display: inline-block;
vertical-align: middle;
}
p:first-of-type { margin-top: 0 }
p:last-of-type { margin-bottom: 0}
Ok, so I made a JS library to automate creating chamfered borders.
It has two methods for creating the chamfers:
Method 1: it creates a chamfered background using Canvas API and set it as the CSS background-image of the element.
Method 2: it appends 4 CSS based triangle DOM elements around the target, making the chamfer.
You will stick with method 1 when you can let the library set the background-image, and you will need method 2 when your target already has a background, like in <img>'s.
The usage is simple, just call ChamferBg for using method 1, or ChamferEnvelop to use method 2:
var el = document.getElementById('box');
ChamferBg(el, {
size: 20,
sw: 6,
sc: '#447aec',
fc: '#21ceff',
tl: false,
br: false,
resize_observe: true
});
The options and their defaults are:
{
size: 5, // chamfer size
sw: 1, // stroke width
sc: 'black', // stroke color,
fc: undefined, // fill color
fp: undefined, // URL of an image to use as fill pattern
tl: true, // chamfer top-left corner?
tr: true, // chamfer top-right corner?
bl: true, // chamfer bottom-left corner?
br: true, // chamfer bottom-right corner?
resize_observe: false
// turn on resize_observe observer?
// this will observer whenever the element
// resizes and will refresh the background
}
You will need to set resize_observe to true if you use method 1 and your element may change its size at runtime, because then it will need to recreate the chamfered background every time it resizes.