htmlcsscss-shapeslinear-gradients

How can I correctly add a shadow and a gradient to my triangular shape?


I want to make the following design:

Sample image

I tried with :after and :before but it does not work. Here’s my current code:

.design {
  background: #ea053a;
  display: inline-block;
  height: 155px;
  margin-left: 33px;
  margin-right: 40px;
  position: relative;
  width: 228px;
}

.design:before {
  border-top: 43px solid #ea053a;
  border-left: 50px solid transparent;
  border-right: 50px solid transparent;
  margin-right: 40px;
  content: "";
  height: 0;
  left: 0;
  position: absolute;
  top: 55px;
  margin-top: 100px;
  width: 128px;
}
<div class="design"></div>

How could I leave it the same as the original design and with the following two properties?:

box-shadow: 0 1px 10px 0 rgba(0, 0, 0, 0.2);
background-image: linear-gradient(to bottom, #ea053a, #d0021b);

Solution

  • Here is an idea with skew transformation and drop-shadow filter. You simply need some extra element to correctly have the gradient. The trick is to invert the skew to keep the gradient direction correct (not needed if we deal with solid color)

    .box {
      width: 150px;
      height: 150px;
      position: relative;
      z-index:0;
      overflow: hidden;
      filter: drop-shadow(0 1px 10px rgba(0, 0, 0, 0.8));
    }
    
    .box span {
      position: absolute;
      z-index:-1;
      top: 0;
      width: 50%;
      height: 100%;
      overflow: hidden;
    }
    
    .box span:first-of-type {
      left: 0;
      transform: skewY(35deg);
      transform-origin: top right;
    }
    
    .box span:last-of-type {
      right: 0;
      transform: skewY(-35deg);
      transform-origin: top left;
    }
    
    .box span::before {
      content: "";
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      background: linear-gradient(to bottom, blue , red );
      transform-origin: inherit;
    }
    
    .box span:first-of-type::before {
      transform: skewY(-35deg);
    }
    
    .box span:last-of-type::before {
      transform: skewY(35deg);
    }
    
    p {
     margin:0;
     color:#fff;
     font-size:45px;
     line-height:100px;
     text-align:center;
    }
    <div class="box">
      <span></span><span></span>
      <p>29</p>
    </div>

    CSS triangle linear gradient and shadow

    Here is how we can do with a left or right gradient. In this case we don't need extra elements because the skew will not affect the direction:

    .box {
      width: 150px;
      height: 150px;
      position: relative;
      z-index:0;
      overflow: hidden;
      filter: drop-shadow(0 1px 10px rgba(0, 0, 0, 0.8));
    }
    
    .box:before,
    .box:after{
      content:"";
      position: absolute;
      z-index:-1;
      top: 0;
      width: 50%;
      height: 100%;
      overflow: hidden;
      background:linear-gradient(to right,blue,red);
      background-size:200% 100%;
    }
    
    .box:before{
      left: 0;
      transform: skewY(35deg);
      transform-origin: top right;
    }
    
    .box:after{
      right: 0;
      transform: skewY(-35deg);
      transform-origin: top left;
      background-position:right;
    }
    
    p {
     margin:0;
     color:#fff;
     font-size:45px;
     line-height:100px;
     text-align:center;
    }
    <div class="box">
      <p>29</p>
    </div>

    And here is with an arbitrary gradient:

    .box {
       --g:linear-gradient(45deg,blue,red 60%,yellow); /* gradient coloration*/
    
      width: 150px;
      height: 150px;
      margin:15px;
      display:inline-block;
      position: relative;
      z-index:0;
      overflow: hidden;
      filter: drop-shadow(0 1px 10px rgba(0, 0, 0, 0.8));
    }
    
    .box span {
      position: absolute;
      z-index:-1;
      top: 0;
      width: 50%;
      height: 100%;
      overflow: hidden;
    }
    
    .box span:first-of-type {
      left: 0;
      transform: skewY(35deg);
      transform-origin: top right;
    }
    
    .box span:last-of-type {
      right: 0;
      transform: skewY(-35deg);
      transform-origin: top left;
    }
    
    .box span::before {
      content: "";
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      background: var(--g);
      background-size:200% 100%;
      transform-origin: inherit;
    }
    
    .box span:first-of-type::before {
      transform: skewY(-35deg);
    }
    
    .box span:last-of-type::before {
      transform: skewY(35deg);
      background-position:right;
    }
    
    p {
     margin:0;
     color:#fff;
     font-size:45px;
     line-height:100px;
     text-align:center;
    }
    <div class="box">
      <span></span><span></span>
      <p>29</p>
    </div>
    
    <div class="box" style="--g:linear-gradient(-62deg,blue,red 60%,yellow)">
      <span></span><span></span>
      <p>29</p>
    </div>

    CSS gradient and drop shadow

    Since each element is taking 50% of the width we make the background to be 200% to have its size as the main container then we adjust the position to create the illusion of one background. It's like each element will show half of the main background.


    An optimized version using mask

    .box {
      width: 150px;
      height: 150px;
      filter: drop-shadow(0 1px 10px rgba(0, 0, 0, 0.8));
    }
    .box > div {
      height: 100%;
      background: linear-gradient(35deg, blue, red);
      -webkit-mask: conic-gradient(from -50deg at bottom,#000 100deg,#0000 0);
      
    p {
      margin: 0;
      color: #fff;
      font-size: 45px;
      line-height: 100px;
      text-align: center;
    }
    <div class="box">
      <div>
        <p>29</p>
      </div>
    </div>

    Or clip-path

    .box {
      width: 150px;
      height: 150px;
      filter: drop-shadow(0 1px 10px rgba(0, 0, 0, 0.8));
    }
    .box > div {
      height: 100%;
      background: linear-gradient(35deg, blue, red);
      clip-path:polygon(0 0,100% 0,100% 70%,50% 100%,0 70%);
    }
    p {
      margin: 0;
      color: #fff;
      font-size: 45px;
      line-height: 100px;
      text-align: center;
    }
    <div class="box">
      <div>
        <p>29</p>
      </div>
    </div>