Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CSS apply gradient to right triangle shape with solid fill

I want to apply the same gradient to the triangle (class="triangle-right") as the rectangle (class="fillblue"). I have seen some other examples but they are not working for me. Combining both shapes and using a single class would be awesome too!

JS FIDDLE HERE!

CSS:

.fillblue {
background: rgb(208,228,247); /* Old browsers */
background: -moz-linear-gradient(top,  rgba(208,228,247,1) 0%, rgba(115,177,231,1) 24%, rgba(10,119,213,1) 50%, rgba(83,159,225,1) 79%, rgba(135,188,234,1) 100%); /* FF3.6+ */
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(208,228,247,1)), color-stop(24%,rgba(115,177,231,1)), color-stop(50%,rgba(10,119,213,1)), color-stop(79%,rgba(83,159,225,1)), color-stop(100%,rgba(135,188,234,1))); /* Chrome,Safari4+ */
background: -webkit-linear-gradient(top,  rgba(208,228,247,1) 0%,rgba(115,177,231,1) 24%,rgba(10,119,213,1) 50%,rgba(83,159,225,1) 79%,rgba(135,188,234,1) 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top,  rgba(208,228,247,1) 0%,rgba(115,177,231,1) 24%,rgba(10,119,213,1) 50%,rgba(83,159,225,1) 79%,rgba(135,188,234,1) 100%); /* Opera 11.10+ */
background: -ms-linear-gradient(top,  rgba(208,228,247,1) 0%,rgba(115,177,231,1) 24%,rgba(10,119,213,1) 50%,rgba(83,159,225,1) 79%,rgba(135,188,234,1) 100%); /* IE10+ */
background: linear-gradient(to bottom,  rgba(208,228,247,1) 0%,rgba(115,177,231,1) 24%,rgba(10,119,213,1) 50%,rgba(83,159,225,1) 79%,rgba(135,188,234,1) 100%); /* W3C */
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#d0e4f7',   
    endColorstr='#87bcea',GradientType=0 ); /* IE6-9 */

height: 40px;
width: 100px;
display: inline-block;
float: left;
color: white;
text-align: center;
line-height: 40px;
font-weight: bold;
}

   .triangle-right {
width: 0;
height: 0;
border-top: 20px solid transparent;
border-left: 40px solid lightblue;
border-bottom: 20px solid transparent;
float: left;
}

HTML:

<div class="fillblue">Step 1</div><div class="triangle-right"></div>
like image 791
DivineChef Avatar asked Oct 17 '25 19:10

DivineChef


2 Answers

Final Result

Part 1: Giving the triangle a gradient

The easiest way to achieve this would be to invert your triangle. and extend the length of the element with the gradient.

JSFiddle demo.

Inverting the triangle

Rather than giving the border-left on the triangle a solid colour, you want to give the top and bototm borders the colour (in this case we want to match the background colour, so lets make these white as that's the JSFiddle background colour):

.triangle-right {
    ...
    border-top: 20px solid white;
    border-left: 40px solid transparent;
    border-bottom: 20px solid white;
}

If you're unsure what this achieves, here is an example of the triangle when the top and bottom borders are set to red instead of white:

Red Example

Increasing the width of your gradient element

As your triangle is 40px wide, we need to increase the width of our gradient element by 40px. For this I've used padding to ensure the text remains in the same place:

.fillblue {
    ...
    padding-right: 40px;
}

With the same red triangle we used above, this is what it now looks like:

Stage 2 Example

Positioning the inverted triangle on top of our gradient element

Now we simply need to set a negative margin on our inverted triangle to make it appear on top of our gradient element:

.triangle-right {
    ...
    margin-left: -40px;
}

Finally, using the red triangle again, our finished result looks like this:

Final Example


Part 2: Combining both shapes into one element

To do this we can make use of the :after pseudo-element.

JSFiddle demo.

First off, lets modify our HTML:

<div class="fillblue">Step 1</div>

Now lets give our .fillblue element relative positioning. We do this so that we can absolutely position our triangle in the next step:

.fillblue {
    ...
    position: relative;
}

Now we modify our previous .triangle-right styling to use this :after pseudo-element instead:

.fillblue:after {
    width: 0;
    height: 0;
    border-top: 20px solid white;
    border-left: 40px solid transparent;
    border-bottom: 20px solid white;
}

Finally we give it the new properties to position it correctly and actually make it display:

.fillblue:after {
    ...
    content: '';
    position: absolute;
    top: 0;
    right: 0;
}
like image 78
James Donnelly Avatar answered Oct 20 '25 10:10

James Donnelly


I wanted to suggest using border-image: linear-gradient(...); but then I looked up https://developer.mozilla.org/en-US/docs/Web/CSS/border-top and saw that it's not possible to apply a border-image to just 1 of the borders, and then make the other borders transparent. There's also no border-left-image, so that won't work either. Since border-image is a relatively new addition to CSS (it's part of CSS3), it's not integrated in CSS as well as the other border styles. That's why doing this with borders is not possible. (It looks like this (simple webkit-only demo) if you do try to add a border-image, and then try to override it with transparent borders - it doesn't work)

Assuming you want to keep using borders to create your triangle, I would say this is not possible.


The only way you could make it work then is by changing the div to a square that's got a diagonal gradient, and is rotated 45 degrees via CSS transforms. That would end up being something like this:

.triangle-right {
    display:inline-block;
    background: -webkit-gradient(linear, left top, right bottom, color-stop(0%,rgba(208,228,247,1)), color-stop(24%,rgba(115,177,231,1)), color-stop(50%,rgba(10,119,213,1)), color-stop(79%,rgba(83,159,225,1)), color-stop(100%,rgba(135,188,234,1))); /* Chrome,Safari4+ */
    /* etc. */
    width:28px; /* ~ sqrt(2*40^2)/2 */
    height:28px;
    -webkit-transform: rotate(45deg);
    /* etc. */
    margin-top:6px;
    margin-left:-14px;
}

Demo

Keep in mind that that is probably not the best solution, since it'd rely purely on transforms, which are not supported in every browser, and there are no good fallbacks for it. It does have one advantage over James Donnely's solution, which is that it keeps its soft borders instead of becoming jagged.

It does have other significant downsides though, namely that you're relying on fixing its position with transform and margin. It is possible other browsers don't handle this exactly the same as Chrome does, and therefore show your triangle differently. They should all show it the same way, but there's always a chance some browser decides to do things slightly differently.

Explanation of the code: The /* etc. */ stands for the other browser prefixes, the width and height are 28px because that's the height of the rotated square, its diagonal length (sqrt(width^2 + height^2)). This is also the reason the margin-left needs to be -14px (half of this diagonal length): it needs to move 14 pixels to the left, so that its corner is moved over the .fillblue element.


As was asked below in the comments, it is also possible to scale the triangle to be wider (or slimmer). This can be done by simply changing the transformation to scale(2, 1) rotate(45deg) so that it applies the stretching and rotating in the right order. A demo of this can be found at http://jsfiddle.net/x61Lyar0/2/.

PS: If you want your arrow to be less pointy, you can apply border-radius: 0 2px 0 0; (or border-top-right-radius: 2px) to smooth it out just a little bit.

like image 29
Joeytje50 Avatar answered Oct 20 '25 09:10

Joeytje50