Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CSS - How to create diagonal emboss?

I want to a 3d diagonal emboss button like seen in the picture below:

enter image description here

My first thought is to use shadow, then add two small triangle using ::before and ::after to close the gap.

But it's always very-slightly misaligned by less than 1 pixel (see snippet below). I used different color for easier coding.

.button {
  border: 1px solid red;
  box-shadow: -10px 10px red;
  
  display: inline-block; margin: 30px; position: relative; outline: none; font-size: 40px;
  padding: 10px 30px; background-color: #333; font-weight: 700;
  color: white; letter-spacing: 1px;
  line-height: 1; text-transform: uppercase; text-align: center;
}

/* create triangle */

.button::before { content: ""; position: absolute;
  top: -1px;
  left: -11px;
  width: 0; height: 0; font-size: 0; line-height: 0%; border-style: solid; border-color: transparent; border-width: 0 0 11px 11px; border-bottom-color: red; }

.button::after { content: ""; position: absolute;
  right: -1px;
  bottom: -11px;
  width: 0; height: 0; font-size: 0; line-height: 0%; border-style: solid; border-color: transparent; border-width: 11px 11px 0 0; border-top-color: red; }
<a class="button">Gallery</a>

Is there better implementation than using triangle and absolute-positioning it?

like image 983
hrsetyono Avatar asked Jun 01 '16 08:06

hrsetyono


Video Answer


2 Answers

One solution would be to use two angled linear-gradient strips - one on the left and other at bottom of the button element.

Imagine placing at 10px x 10px square on the top left and the bottom right of the pseudo-element such that its fill is transparent on one side of the diagonal and colored on the other side. It'd result a triangle shape. That is exactly the approach that we are using here.

A pseudo-element (which is a square or rectangle) is placed behind the parent and the triangular cuts are produced by using the angled linear-gradients. The gradients have 135 degrees and 315 degrees as angle (which is a 45 degree line or in other words the diagonal line of a square/rectangle). Since the imaginary square's size is 10px x 10px, the diagonal line will be 14px in length and so by setting color as transparent for 7px (half distance) and hotpink from 7px (other half), a triangular cut is produced.

The below are the steps that were performed:

  • Create a pseudo-element which is 10px taller and 10px wider than the parent .button element because the projection has to extend outside the element on the left and the bottom.
  • Place 2 small linear-gradient background strips on the top left and the bottom left of the pseudo-element. The size of the horizontal strip (the one on the left) is set as 10px 100%. This is because the thickness of the emboss (which is nothing but width of the strip) on the left is 10px.
  • Similarly the size of the vertical strip (the one on the bottom) is set as 100% 10px. Again because the thickness (in this case, thickness is the height of the emboss) on the bottom is 10px.
  • Then we have produced two angled linear-gradients with angles as 135deg and 315deg so that the triangular cut is seen on the bottom right and top left sides. The pixel color stop points within the gradient is calculated based on Pythagoras theorem. The value would be 10px/sqrt(2).
  • The 1px border for the element is achieved using box-shadow: inset 0px 0px 0px 1px hotpink because an inset shadow will not affect the positioning attributes of the pseudo-element unlike an extra border would.

.button {
  display: inline-block;
  margin: 30px;
  position: relative;
  outline: none;
  font-size: 40px;
  padding: 10px 30px;
  background-color: #333;
  font-weight: 700;
  color: white;
  letter-spacing: 1px;
  line-height: 1;
  text-transform: uppercase;
  text-align: center;
  box-shadow: inset 0px 0px 0px 1px hotpink; /* mimics the border */
}
.button:after {
  position: absolute;
  content: '';
  top: 0px;
  right: 0px; 
  height: calc(100% + 10px); /* since projection should extend outside bottom edge */
  width: calc(100% + 10px); /* since the projection should extend outside the left edge */
  background: linear-gradient(135deg, transparent 7px, hotpink 7px), linear-gradient(315deg, transparent 7px, hotpink 7px);
  background-size: 10px 100%, 100% 10px;
  background-position: top left, bottom left;
  background-repeat: no-repeat;
}
<a class="button">Gallery</a>

<a class="button">Gallery Button Big</a>

Note: The same approach can be employed without a pseudo-element also but it would become a lot more complex to understand and hence I've left it out. Here is a demo but as can be seen it is highly complex and I'd recommend going with the pseudo-element approach itself.

like image 152
Harry Avatar answered Sep 30 '22 14:09

Harry


You can use only box-shadow, maybe less code than triangle.

Example :

.button {
  border: 1px solid pink;
  box-shadow: -10px 10px pink,-9px 9px pink,-8px 8px pink,-7px 7px pink,-6px 6px pink,-5px 5px pink,-4px 4px pink,-3px 3px pink,-2px 2px pink;
  
  display: inline-block; margin: 30px; position: relative; outline: none; font-size: 40px;
  padding: 10px 30px; background-color: #333; font-weight: 700;
  color: white; letter-spacing: 1px;
  line-height: 1; text-transform: uppercase; text-align: center;
}
<a class="button">Gallery</a>

To avoid pixel you can add 1px at each declaration.

.button{
 border: 1px solid pink;
 box-shadow: -10px 10px 1px pink,-9px 9px 1px pink,-8px 8px 1px pink,-7px 7px 1px pink,-6px 6px 1px pink,-5px 5px 1px pink,-4px 4px 1px pink,-3px 3px 1px pink,-2px 2px 1px pink,-1px 1px 1px pink,0px 0px 1px pink;
  
  display: inline-block; margin: 30px; position: relative; outline: none; font-size: 40px;
  padding: 10px 30px; background-color: #333; font-weight: 700;
  color: white; letter-spacing: 1px;
  line-height: 1; text-transform: uppercase; text-align: center;
  }
<a class="button">Gallery</a>
like image 44
Alexis Avatar answered Sep 30 '22 12:09

Alexis