Is it possible to create this irregular quadrilate

2019-02-23 18:07发布

问题:

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?

回答1:

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>



回答2:

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.


回答3:

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>



回答4:

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



回答5:

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)