I've tried the perspective solution here How to transform each side of a shape separately? but can't get it to work probably due to the irregularness of the shape. Only the top and right side columns are slanted, vertical and bottom are straight. How can I do this with CSS?
Using CSS borders you can create triangles and trapezoids.
You can achieve your shape joining a triangle and a trapezoid.
.triangle {
border: 0 solid red;
border-left-width: 500px;
border-top-width: 30px;
border-top-color: transparent;
}
.trapezoid {
border: 0 solid red;
width: 500px;
border-bottom-width: 150px;
border-right-width: 30px;
border-right-color: transparent;
}
<div class="triangle"></div>
<div class="trapezoid"></div>
Method 1: Clip path
You could make use of CSS clip-path feature to clip a rectangle into the required polygon shape.
div {
box-sizing: border-box;
height: 150px;
width: 250px;
background: red;
padding: 10px;
-webkit-clip-path: polygon(0% 0%, 90% 10%, 100% 100%, 0% 100%);
clip-path: polygon(0% 0%, 90% 10%, 100% 100%, 0% 100%);
}
div#image {
background: url(http://lorempixel.com/400/200);
}
/* Just for demo */
div{
float: left;
margin: 10px;
transition: all 1s;
}
div:hover{
height: 200px;
width: 300px;
}
<div>Some text</div>
<div id="image"></div>
Pros:
Supports non-solid color fills inside the shape and also allow text to be present inside.
The shape is responsive and can adapt even if the container's dimensions change.
Cons:
Poor browser support for the CSS clip-path feature. This can be overcome by using inline SVG for the clip-path like in the below snippet as this has much better browser support.
div {
box-sizing: border-box;
height: 150px;
width: 250px;
padding: 10px;
background: red;
-webkit-clip-path: url(#clip);
clip-path: url(#clip);
}
div#image {
background: url(http://lorempixel.com/400/200);
}
/* Just for demo */
div{
float: left;
margin: 10px;
transition: all 1s;
}
div:hover{
height: 200px;
width: 300px;
}
<svg width="0" height="0">
<defs>
<clipPath id="clip" clipPathUnits="objectBoundingBox">
<path d="M0 0, 0.9 0.1, 1 1, 0 1z" />
</clipPath>
</defs>
</svg>
<div>
Some text
</div>
<div id="image"></div>
Method 2: CSS Transforms
Generally it is better not to use transforms when there is going to be content like image or text inside the shape (or) when the shape's background is not going to be a solid color because then we would either have to (a) reverse transform the child elements separately to make them look normal or (b) use absolute positioning.
For this particular shape, having text inside the shape is not a problem even while using transforms but having non solid background colors would be.
Option 1: Using two pseudo-elements
You could use a couple of pseudo-elements with skew transforms, position one on the top and the other on the right to produce the required shape. Hover the shape in snippet to see how it is created.
div {
position: relative;
height: 150px;
width: 250px;
background: red;
margin: 40px 40px 0px 0px;
}
div:after,
div:before {
position: absolute;
content: '';
background: red;
z-index: -1;
backface-visibility: hidden;
}
div:before {
height: 12.5%;
width: 100%;
top: 0px;
left: 0px;
transform-origin: right top;
transform: skewY(3deg);
}
div:after {
height: 100%;
width: 12.5%;
right: -1px;
top: -1px;
transform-origin: right top;
transform: skewX(10deg);
}
/* Just for demo */
div{
transition: all 1s;
}
div:hover{
height: 250px;
width: 300px;
}
div:hover:after{
background: blue;
}
div:hover:before{
background: green;
}
<div>Some text</div>
Pros:
Shape can be created with a single element and can have text inside it without any trouble.
Cons:
Having gradients (or) images as background for the shape is complex because they would need reverse rotation as mentioned earlier.
Shape is not 100% scalable as dimensions of the container should change proportionately for the shape to be maintained (hover on the shape in the snippet to see what I mean). Reason is same as mentioned here.
Option 2: Using one pseudo-element
This is pretty similar to the previous option except that this uses a single pseudo-element along with a overflow: hidden on the parent.
div {
position: relative;
box-sizing: border-box;
height: 200px;
width: 300px;
padding: 10px;
overflow: hidden;
}
div:after {
position: absolute;
content: '';
top: 0px;
left: -20px;
height: 100%;
width: 100%;
background: red;
transform-origin: left bottom;
transform: skewY(5deg) skewX(7.5deg);
z-index: -1;
}
div:hover {
height: 300px;
width: 500px;
transition: all 1s;
}
<div>Some text</div>
Pros:
Shape can be created with a single element and can have text inside it without any trouble.
Shape is responsive and can adapt even if the container's dimensions change .
Cons:
Same constraint as the previous option for gradient and image backgrounds.
Not suitable if the overflow: hidden on the parent is a constraint.
A solution is:
div {
width: 300px;
height: 100px;
margin:50px;
background-color: yellow;
border: 1px solid black;
}
.thisdiv {
-ms-transform: skewX(-20deg); /* IE 9 */
-webkit-transform: skewX(-20deg); /* Safari */
transform: skewX(-20deg); /* Standard syntax */
}
<div class="thisdiv">
This is the div I will skew
</div>
This is how to skew an element, if you want to make the shape you added, try using two overlaping div's, position, scale, rotate and skew, like this:
.outer-div{
position:relative;
margin:50px;
width:200px;
height:200px;
border:2px black dashed;
}
.inner-one{
position:absolute;
left:0;
bottom:0;
width:180px;
height:180px;
background:red;
}
.inner-two{
position:absolute;
bottom:2px;
right:0px;
width:200px;
height:195px;
background:red;
transform: rotate(7deg) skew(14deg) scale(0.905); /* Standard syntax */
}
<div class="outer-div">
<div class="inner-one">
</div>
<div class="inner-two">
</div>
</div>
2 Triangle Solution for Irregular Quadrilateral in CSS
In looking at your image, I notice that the skew at the top and right are really just long, narrow triangles overlaying the rectangle.
So what I did was create triangles using CSS border properties and absolutely position them over the rectangle.
#rectangle {
width: 400px;
height: 200px;
background-color: red;
margin-top: 25px;
position: relative;
}
#triangle-down {
border-left: 30px solid red;
border-right: 0;
border-top: 200px solid transparent;
position: absolute;
right: -30px;
top: 0;
}
#triangle-left {
border-top: 0;
border-bottom: 15px solid red;
border-right: 400px solid transparent;
position: absolute;
right: 0;
top: -15px;
}
<div id="rectangle">
<div id="triangle-down"></div>
<div id="triangle-left"></div>
</div>
jsFiddle demo
You could check out the clip-path property (see below from MDN), but support is very patchy. Chrome 24+ supports with prefix and FF, but only URL values, which reference a path in an SVG. You can read more about clip-path here.
Here's a basic pen - this will only work in Chrome.
From MDN
The clip-path CSS property prevents a portion of an element from getting displayed by defining a clipping region to be displayed i.e, only a specific region of the element is displayed. The clipping region is a path specified as a URL referencing an inline or external SVG, or shape method such as circle(). The clip-path property replaces the now deprecated clip property.
developer.mozilla.org/en-US/docs/Web/CSS/clip-path (sorry, not enough rep to link)
Related
I want to create a top-right border of a div like the following picture
I am pretty new to css. Could anyone give me a pointer to this?
You can use an absolutely positioned ::after pseudo element ( or an element in your markup ) to create the green area. Setting the upper right border radius and overflow: hidden; will finish the job.
body {
background: #ddd;
}
div {
background: white;
width: 100px;
height: 50px;
}
.funky-border {
border-top-right-radius: 30px;
position: relative;
overflow: hidden;
}
.funky-border:after {
content:'';
background: green;
width: 20px;
height: 60px;
transform: rotate( 135deg );
position: absolute;
top: -20px;
right: 0;
}
<div class="funky-border"></div>
Here is an easy way with one element:
.box {
width:200px;
height:100px;
border-top-right-radius:30px;
background:
linear-gradient(to top right,transparent 49%,green 50%) top right/50px 50px no-repeat,
gray;
}
<div class="box">
</div>
This is what i am trying to achive
i have :
#image1 {
position: absolute;
bottom: 0px;
align-self: auto;
background-color: #dc022e;
width: 340px;
height: 100px;
border-radius: 50% / 100%;
border-bottom-left-radius: 0;
/*transform: rotate(10deg);*/
border-bottom-right-radius: 0;
opacity: 0.8;
}
#image2 img {
width: 80%;
}
<div>
<div id="image2">
<img src="http://t1.gstatic.com/images?q=tbn:ANd9GcThtVuIQ7CBYssbdwtzZjVLI_uw09SeLmyrxaRQEngnQAked5ZB">
</div>
<div id="image1"></div>
</div>
Finally I don't know how to make it rotated and with the margins cut like in the picture
A Quick example of this would use a pseudo element and have the image set in the background.
div {
position: relative;
height: 300px;
width: 500px;
background: url(http://lorempixel.com/500/300);/*image path*/
overflow: hidden;/*hides the rest of the circle*/
}
div:before {
content: "";
position: absolute; /*positions with reference to div*/
top: 100%;
left: 50%;
width: 0;/*define value if you didn't want hover*/
height: 0;
border-radius: 50%;
background: tomato;/*could be rgba value (you can remove opacity then)*/
opacity: 0.5;
transform: translate(-50%, -50%);/*ensures it is in center of image*/
transition: all 0.4s;
}
/*Demo Only*/
div:hover:before {/*place this in your pseudo declaration to remove the hover*/
height: 100%;
width: 150%;/*this makes the shape wider than square*/
transform: translate(-50%, -50%) rotate(5deg);/*ensures it is in center of image + rotates*/
}
div {/*This stuff is for the text*/
font-size: 40px;
line-height: 300px;
text-align: center;
}
<div>HOVER ME</div>
Instead of nested elements, you can just use a pseudo element. This is placed at the bottom of the container div. For this to work, you need position:relative and overflow:hidden on the container div. Also, pseudo elements always need the content declaration.
To modify the border radius, you just play around with left | width | height of the pseudo element. You don't need any rotation.
Instead of hex color and opacity you can as well use the "new" color space rgba(r,g,b,a) where a is the opacity value.
For the passepartout you simply use the border declaration.
#image2{
position:relative;
border:10px solid #888;
overflow:hidden;
box-shadow:0 0 4px #aaa;
}
#image2::after {
content:"";
display:block;
position: absolute;
bottom: 0;left:-10%;
background-color: #dc022e;
width: 120%;
height: 60%;
border-radius: 100% 100% 0 0;
opacity: 0.8;
}
#image2 img {
width: 100%;
display:block;
position:relative;
}
<div id="image2">
<img src="http://t1.gstatic.com/images?q=tbn:ANd9GcThtVuIQ7CBYssbdwtzZjVLI_uw09SeLmyrxaRQEngnQAked5ZB">
</div>
You can just use position: absolute for your image and position: relative for your overlay, adjusting the top position and width according to your needs. Here's a Fiddle. Hope this helps!
Edit: Here's an updated version of the Fiddle demonstrating border and overflow properties on the img container. As CBroe mentioned, rotating a circle is probably not a good use of your time in this case. Also, I definitely agree that using a pseudo element is a much cleaner approach than nesting images.
I was wondering if it is possible to make a square with round corners and a indented border in pure CSS.
Currently I have this:
#custom-square {
position: relative;
display: block;
width: 75px;
height: 75px;
border: 2px solid #8A6EF1;
border-radius: 10px;
background-color: white;
}
Considering the hassle and amount of code needed to align double curves with CSS, SVG seems way more appropriate. A few other reasons to go for svg here are :
control of the path (color, width, curve...)
control the fill with a plain color, gradient or image
less code
you can display it over a non plain background (gradient or image)
maintain the boundaries of the shape for user interactions (hover, click...)
Here is a basic example using an inline svg with a path element.
The curves are drawn with Cubic Bezier curves :
svg{width:30%;}
<svg viewbox="0 0 10 10">
<path d="M1.5 0.5 Q5 1 8.5 0.5 Q9.5 0.5 9.5 1.5 Q9 5 9.5 8.5 Q9.5 9.5 8.5 9.5 Q5 9 1.5 9.5 Q0.5 9.5 0.5 8.5 Q1 5 0.5 1.5 Q0.5 0.5 1.5 0.5z"
fill="none" stroke-width="0.2" stroke="#8A6FF2" />
</svg>
Another pure CSS approach for creating this border would be to make use of border-image property. All that is required is create an image with the required border shape and set it to an element using the border-image-source property.
.shape.large {
height: 300px;
width: 300px;
border-image-source: url(http://i.stack.imgur.com/Qkh6A.png);
border-image-width: 34px; /* the width of the border portions in the image - refer to image at the end of the answer for the exact portion details*/
border-image-slice: 34; /* equal to border-image-width */
border-width: 34px; /* equal to border-image-width */
}
.shape.small {
height: 100px;
width: 100px;
border-image-source: url(http://i.stack.imgur.com/Mra4B.png);
border-image-width: 14px;
border-image-slice: 14;
border-width: 14px;
}
.shape.small.fill {
background: aliceblue content-box;
border-image-source: url(http://i.stack.imgur.com/Ovj03.png);
border-width: 14px;
}
/* Just for demo */
body {
background: url(http://lorempixel.com/800/800/abstract/2);
}
.shape.small {
float: left;
}
.shape.large {
clear: both;
}
<div class='shape small'>Some content</div>
<div class='shape small fill'>Some content</div>
<div class='shape large'>Some content</div>
At present this method is definitely not much advantageous compared to SVG but it is an option and in my opinion is better than the other CSS only approaches that are possible.
The advantages of this approach are:
Very minimal and low complexity code.
Better control over the curves and their radii (like with SVG) because the image with the required border curvature can be created separately.
Can be placed on top of an image or a gradient background.
Can be made to degrade gracefully (into a solid square border) in browser's that don't support it.
The drawbacks are:
The container is still a square and so hover effects will not be restricted to the boundaries of the shape unlike with SVG.
Adding solid color fill to the shape is possible (by using a filled version of the image) but adding a gradient or image fill is tricky because borders are still blocks (that is, there are transparent areas on either side of the curves).
The output is responsive but as dimensions increase or decrease beyond a threshold, the shape starts to look a bit compressed or stretched. So, this is more suited for break-point based design.
The browser support is not bad but is not great either. It works in Chrome, Firefox, Safari, Opera and IE11+.
Calculation of Border Image Width:
The width or height of border area (which becomes the border-image-width) is nothing but the width of the portion highlighted in the below image.
This draft mock up is as close as i could get it to pure CSS, but still requires a nested div. You would need to tweak the sizing / radius for the before / after circles.
Pen
div {
position: absolute;
top: 100px;
left: 100px;
width: 100px;
height: 100px;
border: 4px solid purple;
border-radius: 30px;
//overflow: hidden;
box-sizing: border-box;
&:before {
position: absolute;
top: -4px;
left: -94px;
content: ' ';
width: 100px;
height: 100px;
border: 4px solid purple;
border-radius: 50px;
box-sizing: border-box;
background-color: white;
clip: rect(0px, 100px, 100px, 90px);
}
&:after {
position: absolute;
top: -4px;
right: -94px;
content: ' ';
width: 100px;
height: 100px;
border: 4px solid purple;
border-radius: 50px;
box-sizing: border-box;
background-color: white;
clip: rect(0px, 10px, 100px, 0px);
}
}
div > div {
position: absolute;
top: -4px;
left: -4px;
transform: rotate(90deg);
border-color: transparent;
}
SVG is probably the way to go here, but here's a pretty close approximation in pure CSS. It could be made even better by increasing the size of the outer circles.
#middle {
width: 96px;
height: 96px;
border-radius: 10px;
background-color: green;
border: 2px solid #8A6EF1;
}
.outside {
width: 100px;
height: 100px;
position: relative;
overflow: hidden;
margin: 0;
padding: 0;
}
.cutout {
width: 96px;
height: 96px;
border-radius: 50%;
background-color: white;
border: 2px solid #8A6EF1;
}
#top {
top: -100px;
height: 10px;
}
#right {
top: -110px;
left: 90px;
width: 10px;
}
#bottom {
top: -120px;
height: 10px;
}
#left {
top: -220px;
width: 10px;
}
#top > .cutout {
margin-top: -90px;
}
#left > .cutout {
margin-left: -90px;
}
<div id="wrapper">
<div id="middle">
</div>
<div id="top" class="outside">
<div class="cutout">
</div>
</div>
<div id="right" class="outside">
<div class="cutout">
</div>
</div>
<div id="bottom" class="outside">
<div class="cutout">
</div>
</div>
<div id="left" class="outside">
<div class="cutout">
</div>
</div>
</div>
Any idea how to make the div shape like this ?
Just create a rectangle and skew the Y axis using the CSS3 transform property.
In this case, transform: skewY(-20deg) will work.
.shape {
border: 2px solid;
height: 200px;
width: 100px;
transform: skewY(-20deg);
margin: 2em 0;
}
<div class="shape"></div>
This will work in all modern browsers and will fall back to a rectangle in older browsers.
.skewed {
border: solid 5px black;
height: 200px;
margin-top: 50px;
width: 100px;
transform: skewY(-30deg);
}
<div class="skewed"></div>
Can I ask a little help about creating that shape with CSS?
The button needs a circle for the icon, and the simple box for the text.
Here is a possible version using the :before pseudo element. The pseudo element is converted into a circle by using border-radius: 50% and is then positioned before the rectangular div#menu as required.
You can add a image (like the one in question) to the pseudo element by using the content property like shown below:
content: url(http://yoursite.com/yourimage.png);
or using the background-image property also:
background-image: url(http://yoursite.com/yourimage.png);
#menu {
position: relative;
width: 100px;
height: 24px;
line-height: 24px;
color: white;
background-color: peru;
border: 1px solid peru;
border-radius: 2px;
padding-left: 24px;
}
#menu:before {
position: absolute;
content: '';
height: 40px;
width: 40px;
top: -9px; /* (height of parent - height of pseudo) / 2 - border-top of parent for vertical mid */
/* top: -17px; (height of parent - height of pseudo) - border-top of parent for bottom align */
left: -24px; /* some value less than width - depends on amount of overlap needed */
border: 1px solid transparent;
background-image: url(http://lorempixel.com/40/40/people/1);
background-color: peru;
border-radius: 50%;
}
/* Just for demo */
* {
font-family: Calibri;
letter-spacing: 2px;
}
#menu {
margin: 25px;
}
<div id='menu'>Menu Text</div>
Note: This is in essence a different version of the answer posted by Jason Gennaro. If you need support for IE lower versions, use his answer because they don't support :before.
Here's a quick and dirty version:
HTML
<div id="circle"></div>
<div id="rectangle">Header Text</div>
CSS
#circle{
border-radius: 50%;
width: 85px;
height: 85px;
background: brown;
float:left;
}
#rectangle{
width:300px;
height:40px;
background:brown;
color:white;
float:left;
margin-top:20px;
margin-left:-40px;
position:relative;
z-index:-1;
padding-left:60px;
padding-top:6px;
font-family:arial;
font-size:2em;
}
DEMO
http://jsfiddle.net/H6Lkk/
Explanation
use border-radius:50% and any width to create a circle.
float the two divs to allow for the overlap
use position and z-index to place the rectangle under the circle
add the logo image as necessary in the #circle