Creating a angled shape with CSS3 - css

I have been asked to create a responsive application, the layout / theme of the application has a angled shapes (see image below). I've tried using CSS3 skew and rotate however these property values manipulated the content as well as the shape which is not what i want. I would just like the shape to have what appears to be a 90 degree angle and the text to lay on top of the shape.
Can this be accomplished using CSS3?

Rather than using skew and rotate on the container itself, you can use an ::after rule to create an empty div to rotate.
jsfiddle here: http://jsfiddle.net/carasin/ndb1koca/1/
html:
<div id="banner-wrap">
<div id="banner"><h1>Text here</h1></div>
</div>
css:
#banner-wrap {
position:relative;
}
#banner::after {
content: "";
display:block;
background: orange;
width:200%;
height:500px;
position:absolute;
left:-30%;
top:-60%;
z-index:0;
transform: rotate(13deg);
}
h1 {
font-family:sans-serif;
color:#fff;
text-transform:uppercase;
font-size:3em;
z-index:1;
position:relative;
padding:40px 30px ;
}

I've tried using CSS3 skew and rotate however these property values
manipulated the content as well as the shape which is not what i want.
In order to prevent the content from being affected you could simply skew() the content In the opposite direction as well - Example.
Used properties
transform
transform-origin
overflow
* {
margin: 0;
padding: 0;
}
body {
background-color: #fff;
}
h1, h2 {
text-transform: uppercase;
font-size: 6vw;
}
h2 {
font-size: 4vw;
}
.wrapper {
overflow: hidden;
}
header {
background-color: gold;
height: 40vw;
line-height: 40vw;
-webkit-transform: skewY(10deg);
-ms-transform: skewY(10deg);
-o-transform: skewY(10deg);
transform: skewY(10deg);
-webkit-transform-origin: 100% 0;
-moz-transform-origin: 100% 0;
-ms-transform-origin: 100% 0;
-o-transform-origin: 100% 0;
transform-origin: 100% 0;
-webkit-box-shadow: inset 0 -.7em 1em -0.7em rgba(0,0,0,0.5);
box-shadow: inset 0 -.7em 1em -0.7em rgba(0,0,0,0.5);
}
header h1 {
-webkit-transform: skewY(-10deg);
-ms-transform: skewY(-10deg);
-o-transform: skewY(-10deg);
transform: skewY(-10deg);
padding-left: 1em;
color: white;
}
.search {
background-color: lightgray;
padding: 1em;
margin: 0 1em;
}
<div class="wrapper">
<header>
<h1>Hello World</h1>
</header>
</div>
<div class="search">
<h2>Search</h2>
</div>

There's an upcoming CSS property that allows you to create this effect without hacks. It's called clip-path, though presently (Oct 2014) you need to use -webkit-clip-path to avoid collisions with an existing SVG CSS property. The two properties will be merged soon into a single clip-path.
This works today in Chrome, Safari, iOS 8 and Opera (Firefox will follow soon, without -webkit- prefix, obviously):
#banner {
background: yellow;
width: 600px;
height: 300px;
-webkit-clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 0% 50%);
}
Since the polygon uses percentages, the clipping shape will scale with the container whatever dimensions it has -- good for responsive design.
Your use case means that this solution can degrade gracefully to a simple rectangle.
Learn mode about clipping as part of CSS Masking.

Related

Is it possible to create this irregular quadrilateral with CSS?

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)

How can I cut off the corner of a container without allowing content within to overflow?

A client has requested that I create an image slider which is quadrilateral but not rectangular. The slider ends half way across a page and mustn't overlap the right side content. An example of this would be:
First Attempt
I've currently created this JSFiddle demo which uses borders to sheer off the bottom right corner. This is in two parts: #intro-bottom-left which is the foreground and #intro-bottom-left-back which is the background (and what creates the border effect along the right side.
HTML
<section id="intro">
<div id="intro-bottom">
<div id="intro-bottom-left-back"></div>
<div id="intro-bottom-left"></div>
</div>
</section>
CSS
#intro-bottom-left {
height: 0;
width: 0;
position: absolute;
top: 0;
left: 0;
border-top: 410px solid white;
border-right: 153px solid transparent;
border-left: 211px solid white;
}
#intro-bottom-left-back {
height: 0;
width: 0;
position: absolute;
top: 0;
left: 0;
border-top: 410px solid black;
border-right: 154px solid transparent;
border-left: 212px solid black;
}
I've made this on a slightly smaller scale to fit easily within the JSFiddle result UI area. This creates:
Note how I've given the body a grey background to show how this isn't affected.
The Problem
The client has specified that this must work on IE8, which rules out using the CSS3 border-image property or using CSS3 2D Transformations to add in or modify the images and their containers.
I need to somehow add in an <img /> element on top of this which is unable to overflow outside of the boundaries of the shape, without covering any of the area to the right. As the #intro-bottom-left container has no width or height other than what is created by the borders, simply adding an image in and giving the container overflow: hidden will not achieve anything.
Given the below markup (JSFiddle), what can I do to get this image to display the same as the first example at the top without overlapping any of the right content?
<div id="intro-bottom-left">
<div class="slide">
<img src="http://placehold.it/500x500" />
</div>
</div>
You could use IE filters to achieve the CSS3 2D Transformation effect in IE8. Try this tool:
http://www.useragentman.com/IETransformsTranslator/
Update:
The fiddle below looks the same in IE8, Chrome and Firefox:
http://jsfiddle.net/myajouri/jjbrn/
You have to adjust the positioning manually through negative margins to compensate for the difference in transform-origin.
body {
background: #444;
}
#intro-bottom {
overflow: hidden;
}
#intro-bottom-left {
width: 500px;
height: 500px;
padding-left: 90px;
margin-left: -90px;
overflow: hidden;
box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-transform: skew(-20deg);
-moz-transform: skew(-20deg);
-o-transform: skew(-20deg);
transform: skew(-20deg);
/* IE8 */
-ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=1, M12=-0.3639702342662026, M21=0, M22=1, SizingMethod='auto expand')";
margin-left: -182px\0/;
}
.slide {
width: 500px;
height: 500px;
-webkit-transform: skew(20deg);
-moz-transform: skew(20deg);
-o-transform: skew(20deg);
transform: skew(20deg);
/* IE8 */
-ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=1, M12=0.3639702342662022, M21=0, M22=1, SizingMethod='auto expand')";
margin-left: -90px\0/;
}

draw angular side / parallelogram using CSS

Need to draw angular sides of menubar as
inner content may be the some labels or links.
How about using CSS3 transform skew?
Demo
.shape {
width: 200px;
height: 50px;
-webkit-transform: skew(30deg);
-moz-transform: skew(30deg);
transform: skew(30deg);
background: #000;
margin: 20px;
}
Nothing much to explain here, it's a simple div element, which I've skewed by 30deg which will result in the shape you expected.
Note: It's a CSS3 property, so older browsers, as well as IE will spoil your things, make sure you use CSS3 Pie.
Other way to achieve this is by using :after and :before pseudo and CSS Triangles along with content property.
Demo 2 (Kept red triangles for demo purpose)
Demo 3 (Color Changed)
Demo 4 (As you commented, you need to use top: 0; for :before and :after pseudo as well, because when you add text, it will shift both the triangles from the top. So inorder to prevent that, use top: 0;)
Here, am using a simple div element and placing 2 CSS triangles which are positioned absolute to the container. This is more compatible than above, if you are going for a NON CSS3 solution, you can choose this. Make sure you use display: block; for :before as well as :after. And ofcourse you can merge the common styles but I've kept both separate, so that you can get easability to customize them separately.
.shape {
width: 200px;
height: 50px;
background: #000;
margin: 50px;
position: relative;
}
.shape:before {
display: block;
content: "";
height: 0;
width: 0;
border: 25px solid #f00;
border-bottom: 25px solid transparent;
border-left: 25px solid transparent;
position: absolute;
left: -50px;
}
.shape:after {
display: block;
content: "";
height: 0;
width: 0;
border: 25px solid #f00;
border-top: 25px solid transparent;
border-right: 25px solid transparent;
position: absolute;
right: -50px;
}
HTML
<div class="shape">
<div class="text">
text goes here
</div>
</div>
CSS
.shape {
width: 200px;
height: 30px;
-webkit-transform: skew(30deg);
-moz-transform: skew(30deg);
transform: skew(30deg);
background: #000;
margin: 20px;
color:#fff;
}
.text{
width: 150px;
height: 30px;
margin:0px auto;
-webkit-transform: skew(-30deg);
-moz-transform: skew(-30deg);
transform: skew(-30deg);
color:#fff;
}
One major gripe I have with using triangular borders is that there is no easy way to have multiple triangles with different colours, even using javascript [because JS can't access the pseudo-elements :before and :after], the alternative being that I use 3 divs, align them properly, and give all of them the same colour, etc... Too much hassle.
The best way would be using transform: skew() for newer browsers.
But you need to keep in mind that this will transform every element inside that div as well. So the text inside your menu-bar would also come up skewed. To counter that, add a reverse-skew on the inner div like this:
.menu-container {
...
transform: skewX(30deg);
...
}
.menu-inner {
...
transform: skewX(-30deg);
...
}
Have fun experimenting... :)

Rounded arrows with CSS [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How to create a triangle in CSS3 using border-radius
Are they possible to make with CSS?
Normal arrow:
.some_element:after{
content: '';
height: 0;
width: 0;
position: absolute;
top: 0;
left: 0;
border: 100px solid transparent;
border-top-color: #000;
}
( http://jsfiddle.net/W3xwE/ )
Rounded arrow (I want only the bottom side rounded):
:(
Yes, it is possible! You rotate the box, give it a border-radius and use a 45deg linear-gradient as a background.
DEMO
HTML:
<div class='arrow'></div>
CSS:
.arrow {
width: 7em;
height: 7em;
border-radius: 0 0 2em 0;
margin: 5em;
transform: rotate(45deg);
background: linear-gradient(-45deg, black 50%, transparent 50%);
}
If you want the angle of the arrow to be different, then you can also skew it.
Take into account the fact that CSS gradients are not supported by IE9 (I am not saying "or older" this time because you mention CSS3 among your tags). The solution in that case would be to use a solid background and to somehow make sure the upper part won't show, either by covering it with a preceding element, or by clipping it (see the answer Tim Medora provided).
Also, at this point there is still no support for the unprefixed syntax (although this will soon change :D ), so you will need to either manually add the prefixes -webkit-, -moz-, and -o-. (I did not add them in the demo because Dabblet uses -prefix-free which takes care of doing this.)
Here's a way to do it by placing a rotated square inside a box to control clipping. Personally, I think #Ana's solution is much cleaner.
http://jsfiddle.net/K44mE/14/
<div id="outer"><div id="inner"> </div></div>
#inner{
-ms-transform: rotate(45deg);
-webkit-transform: rotate(45deg);
-o-transform: rotate(45deg);
-moz-transform: rotate(45deg);
transform: rotate(45deg);
background-color:silver;
width:100px;
height:100px;
top: -70px;
left: 20px;
position:relative;
-moz-border-radius: 20px;
border-radius: 20px;
}
#outer {
position: absolute;
width: 140px;
height: 70px;
top:10px;
left:10px;
overflow: hidden;
border: 1px solid red;
}
CSS
.arrow {
width: 7em;
height: 7em;
border-radius: 0 0 2em 0;
margin: -2em 2.5em;
transform: rotate(45deg);
background: linear-gradient(-45deg, black 50%, transparent 50%);
}
HTML
<div class='arrow'></div>

absolute position rotated element to right corner

Im trying to figure out how to make shopping cart tab that would be positioned on the right corner and also rotated 90 degrees. The rotation naturally mixes the position but maybe there's a workaround of wrapping to different wrappers etc....
Extra points if there wouldn't need to define width. I don't care about older browsers
How about using transform-origin? See DEMO.
Relevant CSS:
#box {
position: relative;
}
.bg {
right: 40px; /* same as height */
height: 40px;
transform: rotate(-90deg);
transform-origin: 100% 0;
position: absolute;
line-height: 40px; /* same as height, for vertical centering */
}
Ana's answer is excellent and pointed me in the right direction, but I realised you could achieve the same effect without having to explicitly set the height, line-height and position for the element you want to move - instead, just set translate(0, -100%):
body {
margin: 0;
}
#box {
position: relative;
}
.bg {
right: 0;
padding: 1em;
transform: rotate(-90deg) translate(0, -100%);
transform-origin: 100% 0;
position: absolute;
background: #FF1493;
}
<div id="box">
<div class="bg">
<div class="txt">He's not the Messiah. He's a very naughty boy.</div>
</div>
</div>
...and a jsFiddle for good measure.
To rotate text at 90° using CSS, consider using writing-mode.
Set position: relative; on the parent div, then use something like this on the rotated element:
#rot {
position: absolute; /* only handy here because its parent is set to `position: relative;` */
left: 0;
top: 0px;
/* writing-mode: sideways-lr; /* Webkit browsers don't support `sideways-lr` yet */
writing-mode: vertical-rl; /* `vertical-rl` and a rotation will achieve the same effect */
transform: scaleX(-1) scaleY(-1);
height: 100%;
background: rgba(0, 0, 0, 0.1);
text-align: center;
line-height: 2.85;
color: white;
font-weight: bold;
}
You'll end up with a div stacked on the side of your parent div, with the text at a 90° angle.
This way you don't have to think about the rotation origin.
If you need to position wrapper div.and rotate child div so that its always centered vertically and horizontally, try something like this!
.togglewrap{
position:relative;
float:left;left:20%;top:0;
width:30px;
height:120px;
background-color: #ffde21;
}
.sbartoggle {
background:#f5f5f5;
position:absolute;
left:0;
top:0;
right:0;
bottom:0;
margin:auto;
width:100%;
height:30px;/*equal to parent width*/
line-height:30px;/*center text*/
transform: rotate(-90deg);
background-size:10px 10px;
}

Resources