csscss-shapesskew

How to use skew only in the parent element?


Is there any way to use skew only in a parent element? I need to create something like a 'diamond' as a mask and the child elements can't be affected. There is no way, in this case, to use png as a mask. Thanks in advance!


Solution

  • It's really easy, you just need to unskew the thing for the children. Unskew means applying another skew transform, but of opposite angle this time.

    .parent { transform: skewX(45deg); }
    .parent > * { transform: skew(-45deg); }
    

    In general, if you apply a number of transforms on a parent element and you want the child elements to go back to normal, then you have to apply the same transforms, only in reverse order (the order does matter in most cases!) and with a minus for angle/ length values used for skew, rotate or translate. In the case of scale, you need a scale factor of 1/scale_factor_for_parent. That is, for scale, you would do something like this:

    .parent { transform: scale(4); }
    .parent > * { transform: scale(.25); /* 1/4 = .25 */ }
    

    A diamond shape with children is pretty easy.

    DEMO

    Result:

    result

    HTML:

    <div class='wrapper'>
      <div class='diamond'>
        <div class='child'>Yogi Bear</div>
        <div class='child'>Boo Boo</div>
      </div>
    </div>
    

    CSS:

    .wrapper {
      overflow: hidden;
      margin: 0 auto;
      width: 10em; height: 10em;
    }
    .diamond {
      box-sizing: border-box;
      margin: 0 auto;
      padding: 4em 1em 0;
      width: 86.6%; height: 100%;
      transform: translateY(-37.5%) rotate(30deg) skewY(30deg);
      background: lightblue;
    }
    .child {
      transform: skewY(-30deg) rotate(-30deg);
    }
    

    2024 EDIT

    In order to create a diamond shape nowadays, it's better to use clip-path, for example:

    $x: 10%;
    $y: 15%;
    
    .diamond {
        padding: 2em 3em;
        width: max-content;
        aspect-ratio: 2/ 3;
        background: skyblue;
        text-align: center;
        clip-path: 
            polygon(0 $y, $x 0, calc(100% - #{$x}) 0, 100% $y, 50% 100%)
    }
    

    Live demo

    .diamond {
      padding: 2em 3em;
      width: max-content;
      aspect-ratio: 2/ 3;
      background: skyblue;
      text-align: center;
      clip-path: 
        polygon(0 15% /* left */, 10% 0 /* top left */, 
          calc(100% - 10%) 0 /* top right */, 100% 15% /* right */, 
          50% 100% /* bottom */);
    }
    <div class='diamond'>Yogi Bear<br>Boo Boo</div>