CSS: Skew a buttons border, not the text

17.9k views Asked by At

I'm looking for an easy way with a single tag (just <a>)to create a skew effect on the borders, but keep the text the way it is.

I would know how do with a span in- or outside, but I don't want to have additional, pretty much zero meaning HTML on the page.

Example below.

enter image description here

4

There are 4 answers

5
Saumil On BEST ANSWER

You can unskew the child element i.e. provide the opposite skew co-ordinates as you specified for the parent.

Here is a working example

Suppose you have below as you html,

<div class="btn">
    <button><div class="btn-text">Click</div></button>
</div>

If we skew the parent element by 20deg then we should skew the child element by -20deg as,

.btn {
    -ms-transform: skewX(20deg); /* IE 9 */
    -webkit-transform: skewX(20deg); /* Safari */
    transform: skewX(20deg);
}
.btn-text {
    -ms-transform: skewX(-20deg); /* IE 9 */
    -webkit-transform: skewX(-20deg); /* Safari */
    transform: skewX(-20deg);
    padding: 20px;
}
0
Toni Leigh On

One solution is to use css triangles on :before and :after. This solution leaves the cleanest HTML.

This jsfiddle demonstrates

.is-skewed {
    width: 80px;
    height: 40px;
    background-color: #f07;
    display: block;
    color: #fff;
    margin-left: 40px;
}

.is-skewed:before,
.is-skewed:after {
    content: '';
    width: 0;
    height: 0;
}

.is-skewed:before {
    border-bottom: 40px solid #f07;
    border-left: 20px solid transparent;
    float:left;
    margin-left: -20px;
}

.is-skewed:after {
    border-top: 40px solid #f07;
    border-right: 20px solid transparent;
    float:right;
    margin-right: -20px;
}

CSS triangles use thick borders on elements with 0 dimensions with the points at which the borders meet providing the diagonal line required for a triangle (a good visualisation is to look at the corner of a picture frame, where the two borders meet and create triangles). It's important that one border is transparent and one coloured and that they are adjacent (i.e. left and top, not left and right). You can adjust the size, orientation and the lengths of the sides by playing with the border sizes.

For your button, we also use floats and negative margins to pull them outside of the element and line them up right. Position absolute and negative left and right values would also be a good solution to positioning

You can also do :hover states

.is-skewed:hover {
    background-color: #40f;
}
.is-skewed:hover:after {
    border-top-color: #40f;    
}
.is-skewed:hover:before {
    border-bottom-color: #40f;
}

It's important to note the use of background-color and border-color and also that the :hover comes first in all the relevant selectors. If the hover came second this would happen

5
Vadym Pechenoha On

You can simply accompish desired effect using CSS triangle tricks. Just add some styles for the ::before and :: after pseudo-classes.

.skewed_button {
    background: #32CD32;
    color: #000;
    text-decoration: none;
    font-size: 20px;
    display: inline-block;
    height: 30px;
    margin-left: 15px;
    padding: 6px 10px 0;
}
.skewed_button::before {
    content: "";
    float: left;
    margin: -6px 0 0 -25px;
    border-left: 15px solid transparent;
    border-bottom: 36px solid #32CD32;  
    height: 0px;
}
.skewed_button::after {
    content: "";
    float: right;
    margin: -6px -25px 0 0 ;
    border-left: 15px solid #32CD32;
    border-bottom: 36px solid transparent;  
    height: 0px;
}
<a href="#some_url" class="skewed_button">Some Text</a>

0
uNmAnNeR On

You can also use clip-path for this, eg:

clip-path: polygon(14px 0%, 100% 0%, calc(100% - 14px) 100%, 0% 100%);

.skewed_button {
    background: yellow;
    text-decoration: none;
    display: inline-block;
    padding: 10px 20px;
    clip-path: polygon(14px 0%, 100% 0%, calc(100% - 14px) 100%, 0% 100%);
}
<a href="" class="skewed_button">Some Text</a>