How do I create a cut-out hexagon shape? - html

How can I create a cut-out hexagon shape using CSS?
By cut-out hexagon shape I mean something like this:
I was able to create a hexagon with a background image, but I need it to be like in the image.
.hexagon {
position: relative;
width: 300px;
height: 173.21px;
margin: 86.60px 0;
background-image: url('https://placeimg.com/300/400/any');
background-size: auto 346.4102px;
background-position: center;
}
.hexTop,
.hexBottom {
position: absolute;
z-index: 1;
width: 212.13px;
height: 212.13px;
overflow: hidden;
-webkit-transform: scaleY(0.5774) rotate(-45deg);
-ms-transform: scaleY(0.5774) rotate(-45deg);
transform: scaleY(0.5774) rotate(-45deg);
background: inherit;
left: 43.93px;
}
/* Counter transform the background image on the caps */
.hexTop:after,
.hexBottom:after {
content: "";
position: absolute;
width: 300.0000px;
height: 173.20508075688775px;
-webkit-transform: rotate(45deg) scaleY(1.7321) translateY(-86.6025px);
-ms-transform: rotate(45deg) scaleY(1.7321) translateY(-86.6025px);
transform: rotate(45deg) scaleY(1.7321) translateY(-86.6025px);
-webkit-transform-origin: 0 0;
-ms-transform-origin: 0 0;
transform-origin: 0 0;
background: inherit;
}
.hexTop {
top: -106.0660px;
}
.hexTop:after {
background-position: center top;
}
.hexBottom {
bottom: -106.0660px;
}
.hexBottom:after {
background-position: center bottom;
}
.hexagon:after {
content: "";
position: absolute;
top: 0.0000px;
left: 0;
width: 300.0000px;
height: 173.2051px;
z-index: 2;
background: inherit;
}
<div class="hexagon">
<div class="hexTop"></div>
<div class="hexBottom"></div>
</div>

For this transparent cut-out hexagon, I would suggest using an inline SVG with the path element:
svg{
display: block;
width: 70%;
height: auto;
margin: 0 auto;
}
path{
transition: fill .5s;
fill: #E3DFD2;
}
path:hover{
fill: pink;
}
body{background:url('https://farm9.staticflickr.com/8760/17195790401_ceeeafcddb_o.jpg');background-position:center;background-size:cover;}
<svg viewbox="-10 -2 30 14">
<path d=" M-10 -2 H30 V14 H-10z M2.5 0.66 L0 5 2.5 9.33 7.5 9.33 10 5 7.5 0.66z" />
</svg>
Hexagon mask point calculations:
The hexagon coordiantes are pretty easy to calculate. For a regular hexagon in the above orientation:
width = height / sin(60deg)
sin(60deg) ~=0.866
If width is 10 (like in the above example) the coordinates are:
You can find these coordinate in the d attribute after the second M.
Why use SVG?
The main advantages of using SVG in this case are:
Maintainability (example: imagine you need to change the color of the mask. In SVG it is clear what you need to change and there is only one attribute to change.)
Shorter code
You can easily use an image or gradient to fill the mask
Maintain the boundaries of the shape and trigger mouse envents only over the fill respecting the mask (hover the transparent hexagon in the example).
Original example with the mask element:
body{background:url('https://farm9.staticflickr.com/8760/17195790401_ceeeafcddb_o.jpg');background-position:center;background-size:cover;}
svg{
display: block;
width: 70%;
height: auto;
margin: 0 auto;
}
<svg viewbox="-10 -2 30 14" >
<defs>
<mask id="mask" x="0" y="0" width="10" height="10">
<rect x="-10" y="-2" width="40" height="16" fill="#fff"/>
<polygon points="2.5 0.66 7.5 0.66 10 5 7.5 9.33 2.5 9.33 0 5" />
</mask>
</defs>
<rect x="-10" y="-5" width="30" height="20" mask="url(#mask)" fill="#E3DFD2"/>
</svg>

This type of shape can be achieved by filling the outer part of the hexagon using elements. Different transform:rotate(xdeg) should be applied to each element to achieve this effect.
Here is a snippet creating this effect.
Note: The below snippet is supposed to be responsive, so if it appears broken, see the one below it.
* {
margin: 0;
padding: 0;
}
body, html {
width: 100%;
height: 100%;
}
body {
display: flex;
align-items: center;
background: url('https://placeimg.com/800/600/any');
background-size: cover;
background-attachment: fixed;
}
.container {
width: 50%;
height: 50%;
position: relative;
margin: 0 auto;
overflow: hidden;
border: 10px solid #009688;
}
.cut:after {
position: absolute;
content: "";
width: 100%;
height: 100%;
background: #009688;
transform-origin: 0% 100%;
transform: rotate(-60deg);
top: 0;
}
.cut:before {
position: absolute;
content: "";
width: 100%;
height: 100%;
background: #009688;
transform-origin: 0% 0%;
transform: rotate(60deg);
top: 0;
}
.container:after {
position: absolute;
content: "";
width: 100%;
height: 100%;
background: #009688;
transform-origin: 100% 0%;
transform: rotate(-60deg);
top: 0;
}
.container:before {
position: absolute;
content: "";
width: 100%;
height: 100%;
background: #009688;
transform-origin: 100% 100%;
transform: rotate(60deg);
top: 0;
}
<div class="container">
<div class="cut"></div>
</div>
With fixed height and width (better viewed in full screen):
* {
margin: 0;
padding: 0;
}
body, html {
width: 100%;
height: 100%;
}
body {
display: flex;
align-items: center;
background: url('https://placeimg.com/800/600/any');
background-size: cover;
background-attachment: fixed;
}
.container {
width: 500px;
height: 300px;
position: relative;
margin: 0 auto;
overflow: hidden;
border: 10px solid #009688;
}
.cut:after {
position: absolute;
content: "";
width: 100%;
height: 100%;
background: #009688;
transform-origin: 0% 100%;
transform: rotate(-60deg);
top: 0;
}
.cut:before {
position: absolute;
content: "";
width: 100%;
height: 100%;
background: #009688;
transform-origin: 0% 0%;
transform: rotate(60deg);
top: 0;
}
.container:after {
position: absolute;
content: "";
width: 100%;
height: 100%;
background: #009688;
transform-origin: 100% 0%;
transform: rotate(-60deg);
top: 0;
}
.container:before {
position: absolute;
content: "";
width: 100%;
height: 100%;
background: #009688;
transform-origin: 100% 100%;
transform: rotate(60deg);
top: 0;
}
<div class="container">
<div class="cut"></div>
</div>
This is how the cut-out hexagon works:

SVG is the best tool for such things and the biggest contributing factor towards that is that it is easier to create and maintain such shapes as SVG.
But these can be done with CSS transform in another way with simpler transforms also. All we need to do is make use of skew transform and set skew angle based on the shape that is required.
For hexagons, the angle between each side is 120 degrees and so the elements have to be skewed by +/- 30 degrees. For pentagons, the angle between each side is 108 degrees and so skew angles on the bottom half would be +/- 18 degrees but the top half would have +/- 36 degrees. For diamond, the angle between each side is 90 degrees and so the skew angles would be +/-45 degrees.
A few positive points of this approach are: (not that SVG doesn't have these)
The shapes created using this approach are responsive (try hovering on the shapes in demo)
Transforms are pretty well supported given that IE8 is on the way out (Microsoft themselves are stopping support for IE8 from Jan '16). This is not bad when compared with SVG because SVG has the same browser support.
There are quite a few drawbacks of using CSS though:
Extra elements are required in-order to produce the shape.
These would work only in IE9+ (that is, browsers that support transforms). The drawback is not in comparison with SVG but in general.
Fill for the area other than the cut-out cannot be a gradient or an image. It can only be solid color.
Hover effects can be added (as shown in the demo) but it will triggered when the mouse is over the cut-out area also because it is still a part of the container even though it is transparent.
.shape {
position: relative;
height: 100px;
border: 20px solid palevioletred;
overflow: hidden;
}
.shape.hexagon {
width: calc(100px + (100px * 0.577)); /* width = height + (height * tan 30) for hexagon */
}
.shape.pentagon {
width: calc(100px * 1.051); /* width = height * 1.618/1.539 for pentagon (Source: Wiki - https://en.wikipedia.org/wiki/Pentagon */
}
.shape.diamond {
width: 100px; /* height = width for diamond */
}
.hexagon .inner, .pentagon .inner, .diamond .inner {
position: absolute;
height: 100%;
width: 50%;
top: 0px;
left: 85%;
}
.diamond .inner {
left: 100%;
}
.shape:after, .shape:before {
position: absolute;
content: '';
height: 50%;
width: 50%;
left: -35%;
background: palevioletred;
}
.shape.diamond:before, .shape.diamond:after {
left: -50%;
}
.hexagon .inner:after, .hexagon .inner:before, .pentagon .inner:after,
.pentagon .inner:before, .diamond .inner:after, .diamond .inner:before {
position: absolute;
content: '';
height: 50%;
width: 100%;
left: 0px;
background: palevioletred;
}
.shape.hexagon:before, .hexagon .inner:after {
transform: skew(-30deg);
}
.shape.hexagon:after, .hexagon .inner:before {
transform: skew(30deg);
}
.shape.pentagon:before {
transform: skew(-36deg);
}
.shape.pentagon:after{
transform: skew(18deg);
}
.shape.diamond:before, .diamond .inner:after {
transform: skew(-45deg);
}
.shape.diamond:after, .diamond .inner:before {
transform: skew(45deg);
}
.pentagon .inner:before {
transform: skew(36deg);
}
.pentagon .inner:after {
transform: skew(-18deg);
}
.shape:before, .inner:before {
top: 0px;
transform-origin: right bottom;
}
.shape:after, .inner:after {
bottom: 0px;
transform-origin: right top;
}
/* just for demonstrating responsiveness */
.shape {
float: left;
margin: 10px;
transition: all 1s linear;
}
.shape:hover{ height: 150px; }
.shape.hexagon:hover { width: calc(150px + (150px * 0.577)); }
.shape.pentagon:hover { width: calc(150px * 1.051); }
.shape.diamond:hover { width: 150px; }
body {
background: url(http://lorempixel.com/500/500/nature/6) fixed;
background-size: cover;
}
<div class='shape hexagon'>
<div class='inner'></div>
</div>
<div class='shape pentagon'>
<div class='inner'></div>
</div>
<div class='shape diamond'>
<div class='inner'></div>
</div>

The SVG approach is obviously good! But I tried getting it done via CSS! Somehow I managed to get it till here...
* {
box-sizing: border-box;
margin: 0;
padding: 0
}
.relative {
position: relative;
}
.absolute {
position: absolute;
}
body {
background: url('http://lorempicsum.com/up/627/300/4') no-repeat top left;
background-size: cover;
padding-top: 10%;
}
.parent {
margin: 0 auto;
display: table;
width: 400px;
height: 230px;
text-align: center;
table-layout: fixed;
}
.orange {
display: table-cell;
vertical-align: middle;
background: transparent;
width: 100%;
height: 230px;
margin: 0 auto;
overflow: hidden;
position: relative;
border-left: 137px solid orange;
border-right: 137px solid orange;
}
.one,
.two {
position: relative;
width: 126px;
height: auto;
display: block;
border-left: 28px solid orange;
border-right: 28px solid orange;
margin: 0 auto;
}
.one {
border-top: 60px solid transparent;
border-bottom: 60px solid orange;
}
.two {
border-top: 60px solid orange;
border-bottom: 60px solid transparent;
}
<div class="parent">
<div class="orange">
<div class="two"></div>
<div class="one"></div>
</div>
</div>

This answer illustrates the costs of using only one element
SVG is the tool for this. Any CSS alternative will probably be very hacky and quirky, so I say the best is to use SVG.
Using CSS
Properties used are:
box-shadows (for color around transparent region)
perspective transforms, rotation
overflow hidden
pseudoelement
body {
background:url('http://i.imgur.com/TYP4Xka.jpg');
}
#box {
height: 400px;
width: 400px;
position: relative;
box-shadow: inset 70px 0 0 #444, inset -70px 0 0 #444, inset 0 0 0 50px #444;
overflow: hidden;
}
#box:before {
content: "";
position: absolute;
height: 150px;
width: 259.8px; /* w = h * sqrt(3) bcoz w = 2*h*cos(30deg) */
top: 125px; /* (parentHeight - pseudoHeight)/2 */
left: 70.1px; /* (parentWidth - pseudoWidth)/2 */
-webkit-transform: rotate(60deg);
-moz-transform: rotate(60deg);
transform: rotate(60deg);
box-shadow: 70px 0 0 #444, -70px 0 0 #444;
}
#box:after {
content: "";
position: absolute;
height: 150px;
width: 259.8px;
top: 125px;
left: 70.1px;
-webkit-transform: rotate(120deg);
-moz-transform: rotate(120deg);
transform: rotate(120deg);
box-shadow: 70px 0 0 #444, -70px 0 0 #444;
}
<div id="box"></div>
NOTE
You can also kind off morph the shape around in an animation, but be warned. Do not use a lot of box-shadows for anything, especially for animation. Box- shadow has a very high CPU usage.

Related

gear icon using a single div in pure css

I'm trying to create this icon using pure css & a single div
so far I've only managed to add 2 points like this:
:root {
--gear_radius: 5rem;
--gear_color: black;
--gear_thickness: 1.5rem;
--gear_pin_length: 1.5rem;
--gear_pin_gap: 1.5rem;
}
.gear {
margin: 5rem;
height: var(--gear_radius);
width: var(--gear_radius);
border-radius: 50%;
border: var(--gear_color) var(--gear_thickness) solid;
box-sizing: border-box;
position: relative;
}
.gear:before {
position: absolute;
content: "";
display: block;
height: var(--gear_pin_length);
width: var(--gear_thickness);
left: 50%;
top: 50%;
transform: translate(-50%, -50%) rotate(45deg);
box-shadow: 0 calc(var(--gear_thickness) * 2) 0 0 black, 0 calc(var(--gear_thickness) * -2) 0 0 black;
}
.gear:after {
position: absolute;
content: "";
display: block;
height: var(--gear_pin_length);
width: var(--gear_thickness);
left: 50%;
top: 50%;
transform: translate(-50%, -50%) rotate(-45deg);
box-shadow: 0 calc(var(--gear_thickness) * 2) 0 0 black, 0 calc(var(--gear_thickness) * -2) 0 0 black;
}
<div class="gear"></div>
How do I add 2 more points at the top and bottom? I don't know what approach to take from here?
The original picture of a gear wheel has an angle to the sides of each tooth.
However, I notice that in your part-solution you aren't worried about that and have parallel edges.
Here's a snippet that puts in all 6 teeth with parallel edges.
It uses before and after pseudo elements which had stripes as background and are rotated. The main div also has a stripe for a background but additionally a radial gradient with white and black circles.
.cog {
width: 30vmin;
height: 30vmin;
position: relative;
background-image: radial-gradient(white 0 35%, black 35% 70%, transparent 70% 100%), linear-gradient(to right, black, black);
background-size: 70% 70%, 25% 100%;
}
.cog::before,
.cog::after {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-image: linear-gradient(to right, black, black);
background-size: 25% 100%;
z-index: -1;
}
.cog,
.cog::before,
.cog::after {
background-repeat: no-repeat;
background-position: center center;
transform-origin: center;
}
.cog::before {
transform: rotate(60deg);
}
.cog::after {
transform: rotate(120deg);
}
<div class="cog"></div>
Here's what it produces:
To get more sophisticated shape - such as the slope on the teeth, you could do more with gradients or just CSS clip-path (though by the time you've done this you probably might as well have created an SVG).
Well, of course SVG is better, but since your question is more of a challenge, here is my solution:
* {
margin: 0;
padding: 0;
}
.icon {
position: relative;
background: beige;
height: 160px;
width: 160px;
}
.wheel {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
margin: auto;
width: 32px;
height: 32px;
background: beige;
border-radius: 50%;
border: solid 24px brown;
}
.cog {
position: absolute;
width: 24px;
height: 120px;
border-radius: 6px;
background: brown;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: auto;
}
.cog:nth-child(2) {
transform: rotate(45deg);
}
.cog:nth-child(3) {
transform: rotate(90deg)
}
.cog:nth-child(4) {
transform: rotate(135deg)
}
<div class="icon">
<div class="cogs">
<div class="cog"></div>
<div class="cog"></div>
<div class="cog"></div>
<div class="cog"></div>
</div>
<div class="wheel"></div>
<div>

How can I paint a sector only with border-radius?

As we know, in CSS, we can use:
width : 100px; height : 100px; border-radius : 100% 0 0 0;
To paint a sector with 90deg; and I want to use this way to paint a sector with any deg. But the front sector doesn't cover perfectly. It leaks a slice of red sector and I don't know how to handle it.
body {
background-color: #fbb;
}
.box {
width: 200px;
height: 200px;
position: relative;
background-color: #f00;
border-radius: 100% 0 0;
}
.box::after {
content: '';
display: block;
position: absolute;
width: 100%;
height: 100%;
background-color: #fbb;
border-radius: 100% 0 0;
-webkit-transform-origin: 100% 100%;
transform-origin: 100% 100%;
-webkit-transform: rotate(45deg);
transform: rotate(45deg);
}
<div class="box"></div>
You can cheat a bit and shift the whole overlay with an additional transform.
body {
background-color: #fbb;
}
.box {
width: 200px;
height: 200px;
position: relative;
background-color: #f00;
border-radius: 100% 0 0;
}
.box::after {
content: '';
display: block;
position: absolute;
width: 100%;
height: 100%;
background-color: #fbb;
border-radius: 100% 0 0;
transform-origin: 100% 100%;
transform: rotate(45deg) translate(-1px, 0px); /* <---- here */
}
<div class="box"></div>
It also seems to work by shifting the transform origin slightly.
body {
background-color: #fbb;
}
.box {
width: 200px;
height: 200px;
position: relative;
background-color: #f00;
border-radius: 100% 0 0;
}
.box::after {
content: '';
display: block;
position: absolute;
width: 100%;
height: 100%;
background-color: #fbb;
border-radius: 100% 0 0;
transform-origin: 101% 100%; /* <---- here */
transform: rotate(45deg);
}
<div class="box"></div>
You could also use a sharp box shadow.
body {
background-color: #fbb;
}
.box {
width: 200px;
height: 200px;
position: relative;
background-color: #f00;
border-radius: 100% 0 0;
}
.box::after {
content: '';
display: block;
position: absolute;
width: 100%;
height: 100%;
background-color: #fbb;
border-radius: 100% 0 0;
transform-origin: 100% 100%;
transform: rotate(45deg);
box-shadow: 0 0 0 .5px #fbb; /* <---- here */
}
<div class="box"></div>
None of these are mathematically perfect, but they may suit your practical needs.

Skewing both top and bottom of div

I am trying to skew both the top and bottom of a div to create a shape that I can then insert a background pattern to however, after a few hours of research I can't really come up with a solid solution. I'm nearly there in the sense that all I need to do is to skew the bottom but am looking for some help or guidance on doing so.
I would like the bottom to mirror the skew of the top. Any suggestions?
#test {
position: relative;
width: 100%;
height: 400px;
}
.bg {
width: 50%;
height: 800px;
-webkit-transition: all 300ms ease-in;
background: black;
border-radius: 80px 0px 0px 80px;
position: absolute;
right: 0;
top: 0;
-ms-transform: skewY(-9deg);
-webkit-transform: skewY(-9deg);
transform: skewY(-9deg);
}
<section id="test">
<div class="bg"></div>
</section>
Example of what I currently have
https://jsfiddle.net/3atsj1e5/
With some rotation and perspective you can do it:
.box {
margin-left: auto;
width: 200px;
height: 450px;
transform-origin: right;
transform: perspective(100px) rotateY(-10deg);
border-radius: 40px 0 0 40px;
overflow: hidden;
}
.box::before {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: url(https://picsum.photos/id/1074/400/800) center/cover;
transform-origin:inherit;
transform: perspective(100px) rotateY(10deg);
}
body {
margin: 0;
background:#eee;
}
<div class="box"></div>

Squircle template rounding [duplicate]

I've been banging my head against the wall trying to figure out how to use The Code Player's CSS3 Squircles example to create an iOS-7-style app icon on my website (testing in the Safari browser). The example uses pseudo tags to clip the background color, whereas I need to crop around an <img>. In case you're not familiar, a squircle is like a rounded-rect, but with the sides rounding beyond the corner radius, like so:
.icons img {
width: 100px;
height: 100px;
border-radius: 24%;
}
.icons a {
text-decoration: none;
display: inline-block;
position: relative;
}
/*Now we will create fish-eye shapes using pseudo elements and clip them to add a curve to the sides of the icons*/
.icons a:before, .icons a:after {
content: '';
position: absolute; left: 0; top: 0;
width: 100%; height: 100%;
background: inherit;
border-radius: 100%; /*circle*/
/*time to transform the circle into fish-eye shape. iOS7 style now.*/
-webkit-transform: scaleX(2) scaleY(1.05);
transform: scaleX(2) scaleY(1.05);
/*clipping the left and right sides - 17px from the left and right*/
clip: rect(0, 66px, 100px, 34px);
/*pushing it behind the icon*/
z-index: -1;
}
/*duplicating the :before element and rotating it 90deg and swapping the X/Y transforms*/
.icons a:after {
-webkit-transform: scaleY(2) scaleX(1.05) rotate(90deg);
}
<div class="icons">
<img src="http://lorempixel.com/256/256/abstract/2/" />
</div>
The easiest solution might be to create the image with a transparent background until some of the following features are implemented.
If you can add the image via CSS then you could just add height, width, background-image and background-size to the link (.icons a).
Note: This might not be the desired effect as it is complemented by a background colour.
.icons a {
height: 100px;
width: 100px;
background-image: url(https://picsum.photos/256/);
background-size: cover;
text-decoration: none;
color: white;
display: inline-block;
margin: 20px;
border-radius: 24px;
position: relative;
}
.icons a:before,
.icons a:after {
content: '';
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
background: inherit;
border-radius: 100%;
-webkit-transform: scaleX(2) scaleY(1.05);
transform: scaleX(2) scaleY(1.05);
clip: rect(0, 66px, 100px, 34px);
z-index: -1;
}
.icons a:after {
-webkit-transform: scaleY(2) scaleX(1.05) rotate(90deg);
transform: scaleY(2) scaleX(1.05) rotate(90deg);
}
<div class="icons">
</div>
If this is not the case you could add size and border radius to the image. In this case the the pseudo rounded borders are filled by a background colour on the '.icon a' element.
Note: This might not be the desired effect as it is complemented by a background colour.
.icons a {
height: 100px;
width: 100px;
background: red;
text-decoration: none;
color: white;
display: inline-block;
margin: 20px;
border-radius: 24px;
position: relative;
}
.icons img{
height: 100px;
width: 100px;
border-radius: 24px;
}
.icons a:before, .icons a:after {
content: '';
overflow: hidden;
position: absolute; left: 0; top: 0;
width: 100%; height: 100%;
background: inherit;
border-radius: 100%;
-webkit-transform: scaleX(2) scaleY(1.05);
transform: scaleX(2) scaleY(1.05);
clip: rect(0, 66px, 100px, 34px);
z-index: -1;
}
.icons a:after {
-webkit-transform: scaleY(2) scaleX(1.05) rotate(90deg);
transform: scaleY(2) scaleX(1.05) rotate(90deg);
}
<div class="icons">
<a href="#">
<img src="https://picsum.photos/256/">
</a>
</div>
SVG Solution 1:
Use a cliping-path using an svg but this is not yet supported by webkit (sticks the clipped image at the top left of the screen). See this link for more info: https://css-tricks.com/clipping-masking-css/#comment-1587234
#squircle{
-webkit-clip-path: url(#svg-shape);
-moz-clip-path: url(#svg-shape);
-o-clip-path: url(#svg-shape);
-ms-clip-path: url(#svg-shape);
clip-path: url(#svg-shape);
}
<img src="https://picsum.photos/400/" id="squircle">
<svg height="0" width="0" version="1.1"
xmlns="http://www.w3.org/2000/svg">
<defs>
<clipPath id="svg-shape">
<path d="M100,200c43.8,0,68.2,0,84.1-15.9C200,168.2,200,143.8,200,100s0-68.2-15.9-84.1C168.2,0,143.8,0,100,0S31.8,0,15.9,15.9C0,31.8,0,56.2,0,100s0,68.2,15.9,84.1C31.8,200,56.2,200,100,200z" />
</clipPath>
</defs>
</svg>
SVG Solution 2:
Use a pattern to add the image as a background image.
svg.iOS-svg {
height: 100px;
width: 100px;
}
<svg class="iOS-svg" viewBox="0 0 200 200">
<defs>
<pattern id="squircle" patternUnits="userSpaceOnUse" width="200" height="200">
<image xlink:href="https://picsum.photos/256/" x="0" y="0" width="200" height="200" />
</pattern>
</defs>
<path d="M100,200c43.8,0,68.2,0,84.1-15.9C200,168.2,200,143.8,200,100s0-68.2-15.9-84.1C168.2,0,143.8,0,100,0S31.8,0,15.9,15.9C0,31.8,0,56.2,0,100s0,68.2,15.9,84.1C31.8,200,56.2,200,100,200z" fill="url(#squircle)" />
</svg>
Other Resources:
http://caniuse.com/#search=clip-path (Partial support at time of writing)
SVG support: http://caniuse.com/#search=svg
.squircle {
width: 52.1em;
height: 52.1em;
position: relative;
display: inline-block;
margin: 1em auto;
vertical-align: middle;
-webkit-transform: scale(0.5);
-webkit-transform-origin: 50% 0;
}
.squircle > * {
position: absolute;
width: 100%;
display: inline-block;
height: 100%;
background: 50% 50% no-repeat;
z-index: 5;
}
.squircle:before,
.squircle:after,
.squircle > *:before,
.squircle > *:after {
position: absolute;
background: #00aeef;
}
.squircle:before {
top: 0;
left: 4em;
border-top-left-radius: 20em 10em;
width: 50%;
bottom: 0;
border-bottom-left-radius: 20em 10em;
content: "";
}
.squircle:before {
top: 0;
left: 4em;
border-top-left-radius: 80% 10em;
width: 50%;
bottom: 0;
border-bottom-left-radius: 80% 10em;
content: "";
}
.squircle:after {
top: 0;
bottom: 0;
right: 4em;
border-top-right-radius: 80% 20%;
border-bottom-right-radius: 80% 20%;
width: 25em;
content: "";
}
.squircle > *:before {
top: 4em;
bottom: 4em;
border-top-left-radius: 100% 50%;
border-bottom-left-radius: 100% 50%;
width: 10em;
content: "";
}
.squircle > *:after {
top: 4em;
bottom: 4em;
right: 0;
border-top-right-radius: 100% 50%;
border-bottom-right-radius: 100% 50%;
width: 10em;
content: "";
z-index: 4;
}
body {
background: #1F1A1D;
}
body::before {
height: 100%;
content: '';
width: 0;
background: red;
vertical-align: middle;
display: inline-block;
}
<span class="squircle">
<span>I'm a squircle!</span>
</span>
A squircle is not border-radius or round corners, and you must draw the path by yourself.
The article from figma's blog and their implementation in Github.
https://www.figma.com/blog/desperately-seeking-squircles/
https://github.com/MartinRGB/Figma_Squircles_Approximation
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="470px" height="468px" viewBox="0 0 470 468" version="1.1">
<path fill="#987EFC" fill-rule="evenodd" d="M9.635 132.808C24.782 59.782 71.388 19.109 144.085 6.822c53.74-9.081 107.5-9.196 161.15.255 74.852 13.185 119.85 56.23 134.185 130.36 11.075 57.29 11.249 115.191-.174 172.427-15.324 72.52-63.132 117.285-135.561 129.527-53.74 9.08-107.5 9.195-161.15-.255-74.852-13.186-120.05-58.38-134.384-132.509-11.64-57.668-10.52-115.935 1.484-173.82z" id="path-1"/>
</svg>

How to squircle an app icon image with just CSS

I've been banging my head against the wall trying to figure out how to use The Code Player's CSS3 Squircles example to create an iOS-7-style app icon on my website (testing in the Safari browser). The example uses pseudo tags to clip the background color, whereas I need to crop around an <img>. In case you're not familiar, a squircle is like a rounded-rect, but with the sides rounding beyond the corner radius, like so:
.icons img {
width: 100px;
height: 100px;
border-radius: 24%;
}
.icons a {
text-decoration: none;
display: inline-block;
position: relative;
}
/*Now we will create fish-eye shapes using pseudo elements and clip them to add a curve to the sides of the icons*/
.icons a:before, .icons a:after {
content: '';
position: absolute; left: 0; top: 0;
width: 100%; height: 100%;
background: inherit;
border-radius: 100%; /*circle*/
/*time to transform the circle into fish-eye shape. iOS7 style now.*/
-webkit-transform: scaleX(2) scaleY(1.05);
transform: scaleX(2) scaleY(1.05);
/*clipping the left and right sides - 17px from the left and right*/
clip: rect(0, 66px, 100px, 34px);
/*pushing it behind the icon*/
z-index: -1;
}
/*duplicating the :before element and rotating it 90deg and swapping the X/Y transforms*/
.icons a:after {
-webkit-transform: scaleY(2) scaleX(1.05) rotate(90deg);
}
<div class="icons">
<img src="http://lorempixel.com/256/256/abstract/2/" />
</div>
The easiest solution might be to create the image with a transparent background until some of the following features are implemented.
If you can add the image via CSS then you could just add height, width, background-image and background-size to the link (.icons a).
Note: This might not be the desired effect as it is complemented by a background colour.
.icons a {
height: 100px;
width: 100px;
background-image: url(https://picsum.photos/256/);
background-size: cover;
text-decoration: none;
color: white;
display: inline-block;
margin: 20px;
border-radius: 24px;
position: relative;
}
.icons a:before,
.icons a:after {
content: '';
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
background: inherit;
border-radius: 100%;
-webkit-transform: scaleX(2) scaleY(1.05);
transform: scaleX(2) scaleY(1.05);
clip: rect(0, 66px, 100px, 34px);
z-index: -1;
}
.icons a:after {
-webkit-transform: scaleY(2) scaleX(1.05) rotate(90deg);
transform: scaleY(2) scaleX(1.05) rotate(90deg);
}
<div class="icons">
</div>
If this is not the case you could add size and border radius to the image. In this case the the pseudo rounded borders are filled by a background colour on the '.icon a' element.
Note: This might not be the desired effect as it is complemented by a background colour.
.icons a {
height: 100px;
width: 100px;
background: red;
text-decoration: none;
color: white;
display: inline-block;
margin: 20px;
border-radius: 24px;
position: relative;
}
.icons img{
height: 100px;
width: 100px;
border-radius: 24px;
}
.icons a:before, .icons a:after {
content: '';
overflow: hidden;
position: absolute; left: 0; top: 0;
width: 100%; height: 100%;
background: inherit;
border-radius: 100%;
-webkit-transform: scaleX(2) scaleY(1.05);
transform: scaleX(2) scaleY(1.05);
clip: rect(0, 66px, 100px, 34px);
z-index: -1;
}
.icons a:after {
-webkit-transform: scaleY(2) scaleX(1.05) rotate(90deg);
transform: scaleY(2) scaleX(1.05) rotate(90deg);
}
<div class="icons">
<a href="#">
<img src="https://picsum.photos/256/">
</a>
</div>
SVG Solution 1:
Use a cliping-path using an svg but this is not yet supported by webkit (sticks the clipped image at the top left of the screen). See this link for more info: https://css-tricks.com/clipping-masking-css/#comment-1587234
#squircle{
-webkit-clip-path: url(#svg-shape);
-moz-clip-path: url(#svg-shape);
-o-clip-path: url(#svg-shape);
-ms-clip-path: url(#svg-shape);
clip-path: url(#svg-shape);
}
<img src="https://picsum.photos/400/" id="squircle">
<svg height="0" width="0" version="1.1"
xmlns="http://www.w3.org/2000/svg">
<defs>
<clipPath id="svg-shape">
<path d="M100,200c43.8,0,68.2,0,84.1-15.9C200,168.2,200,143.8,200,100s0-68.2-15.9-84.1C168.2,0,143.8,0,100,0S31.8,0,15.9,15.9C0,31.8,0,56.2,0,100s0,68.2,15.9,84.1C31.8,200,56.2,200,100,200z" />
</clipPath>
</defs>
</svg>
SVG Solution 2:
Use a pattern to add the image as a background image.
svg.iOS-svg {
height: 100px;
width: 100px;
}
<svg class="iOS-svg" viewBox="0 0 200 200">
<defs>
<pattern id="squircle" patternUnits="userSpaceOnUse" width="200" height="200">
<image xlink:href="https://picsum.photos/256/" x="0" y="0" width="200" height="200" />
</pattern>
</defs>
<path d="M100,200c43.8,0,68.2,0,84.1-15.9C200,168.2,200,143.8,200,100s0-68.2-15.9-84.1C168.2,0,143.8,0,100,0S31.8,0,15.9,15.9C0,31.8,0,56.2,0,100s0,68.2,15.9,84.1C31.8,200,56.2,200,100,200z" fill="url(#squircle)" />
</svg>
Other Resources:
http://caniuse.com/#search=clip-path (Partial support at time of writing)
SVG support: http://caniuse.com/#search=svg
.squircle {
width: 52.1em;
height: 52.1em;
position: relative;
display: inline-block;
margin: 1em auto;
vertical-align: middle;
-webkit-transform: scale(0.5);
-webkit-transform-origin: 50% 0;
}
.squircle > * {
position: absolute;
width: 100%;
display: inline-block;
height: 100%;
background: 50% 50% no-repeat;
z-index: 5;
}
.squircle:before,
.squircle:after,
.squircle > *:before,
.squircle > *:after {
position: absolute;
background: #00aeef;
}
.squircle:before {
top: 0;
left: 4em;
border-top-left-radius: 20em 10em;
width: 50%;
bottom: 0;
border-bottom-left-radius: 20em 10em;
content: "";
}
.squircle:before {
top: 0;
left: 4em;
border-top-left-radius: 80% 10em;
width: 50%;
bottom: 0;
border-bottom-left-radius: 80% 10em;
content: "";
}
.squircle:after {
top: 0;
bottom: 0;
right: 4em;
border-top-right-radius: 80% 20%;
border-bottom-right-radius: 80% 20%;
width: 25em;
content: "";
}
.squircle > *:before {
top: 4em;
bottom: 4em;
border-top-left-radius: 100% 50%;
border-bottom-left-radius: 100% 50%;
width: 10em;
content: "";
}
.squircle > *:after {
top: 4em;
bottom: 4em;
right: 0;
border-top-right-radius: 100% 50%;
border-bottom-right-radius: 100% 50%;
width: 10em;
content: "";
z-index: 4;
}
body {
background: #1F1A1D;
}
body::before {
height: 100%;
content: '';
width: 0;
background: red;
vertical-align: middle;
display: inline-block;
}
<span class="squircle">
<span>I'm a squircle!</span>
</span>
A squircle is not border-radius or round corners, and you must draw the path by yourself.
The article from figma's blog and their implementation in Github.
https://www.figma.com/blog/desperately-seeking-squircles/
https://github.com/MartinRGB/Figma_Squircles_Approximation
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="470px" height="468px" viewBox="0 0 470 468" version="1.1">
<path fill="#987EFC" fill-rule="evenodd" d="M9.635 132.808C24.782 59.782 71.388 19.109 144.085 6.822c53.74-9.081 107.5-9.196 161.15.255 74.852 13.185 119.85 56.23 134.185 130.36 11.075 57.29 11.249 115.191-.174 172.427-15.324 72.52-63.132 117.285-135.561 129.527-53.74 9.08-107.5 9.195-161.15-.255-74.852-13.186-120.05-58.38-134.384-132.509-11.64-57.668-10.52-115.935 1.484-173.82z" id="path-1"/>
</svg>