CSS button - transparent arrow on both sides - css

I am trying to create the button below by using the pseudo-elements before and after. I do not want to manipulate the HTML DOM. I'm searching for a solution with pure CSS.
How is it possible to make the currently white border-color of these triangles transparent?
//EDIT: The marked topic does not answer my question because I need a different angle than just rotating a square. It is also not transparent. I don't want to manipulate the DOM.
//SOLVED: This is the result after using Kate Millers solution:
//EDIT2: There is another problem with the solution I use now:
Is there a way to fix the border-width of the triangles (left and right)?
Here you can see how the size changes to 14.4 and 26.4px, 26.4px:

The best solution is to reverse the triangles (so you're adding top and bottom triangles that match the button, but not on the sides). You can technically make "transparent" triangles, but you can't have that transparency apply to a different object.
One of the most important things I changed was that the background color and padding of the button has to apply to the span element (which means each button will need an interior span), not .btn.
If you replace all of your CSS about the buttons with the below, you'll have a solution that gets you at least 90% of the way there. The angle isn't perfect because it's stopping at the text. If you want to make the angle truly perfect, you'll probably need to do some absolute positioning, which would make it messy as your button sizes change.
The non-code way you can also achieve this is to create a .png or .svg with triangles that match the color of your button and insert them into the :before and :after with content: ' ';
body { margin: 20px; background:#c2c2c2; }
.btn {
display: inline-block;
text-shadow: 0 1px 0 #000;
font-weight: bold;
text-transform: uppercase;
}
.btn {
padding: 11px 40px;
color: #fff;
position: relative;
background: #a00;
}
.btn:before, .btn:after {
content: '';
border-top: 20px solid #a00;
border-bottom: 20px solid #a00;
position: absolute;
top: 0;
}
.btn:before {
border-left:20px solid transparent;
left: -20px;
}
.btn:after {
border-right:20px solid transparent;
right:-20px;
}
.btn.inset:before, .btn.inset:after {
content: '';
border-top: 20px solid transparent;
border-bottom: 20px solid transparent;
position: absolute;
top: 0;
}
.btn.inset:before {
border-right:20px solid #a00;
left: -40px;
}
.btn.inset:after {
border-left:20px solid #a00;
right:-40px;
}
<div class="btn">Text in my little banner button</div>
<div class="btn inset">Text in my little banner button</div>

I don't use, and am not really familiar with, LESS... but you can create a similar element using a span and a wrapper with pseudo elements. It does take 2 triangles for each side (hence the span).
body { margin: 20px; background: #ddd; }
.btn {
display: inline-block;
padding: 11px 40px;
color: #fff;
position: relative;
background: #a00;
text-shadow: 0 1px 0 #000;
font-weight: bold;
text-transform: uppercase;
}
.btn:after,
.btn span:after,
.btn:before,
.btn span:before {
content: "";
width: 0;
height: 0;
display: block;
position: absolute;
right: 0;
border: 10px solid transparent;
}
.btn:after {
top: 0;
border-right-color: #ddd;
border-bottom-color: #ddd;
}
.btn span:after {
bottom: 0;
border-right-color: #ddd;
border-top-color: #ddd;
}
.btn:before {
top: 0;
left:0;
border-left-color: #ddd;
border-bottom-color: #ddd;
}
.btn span:before {
bottom: 0;
left:0;
border-left-color: #ddd;
border-top-color: #ddd;
}
<div class="btn"><span>Text in my little banner button</span></div>
I realize the ends aren't really transparent, they just match the background color to appear transparent.

Related

How can I create an even spaced separated outline with border radius?

I've been trying some solutions found around the web, but they all are just a bit . . . off.
We have a design for a button's :focus style, like so:
That's 2px of empty space and a 2px outline.
Here's what we are doing now:
&::after {
border-radius: 18px;
content: "";
display: block;
margin: -2px;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
&:focus::after {
box-shadow: 0 0 0 2px blue;
}
which is almost good. See how it is just off-keel?
Is there a more reliable approach to this sort of design problem? Nudging the position properties by .5 pixels can hack it into shape but it just breaks elsewhere and makes my CSS bone ache.
you can try with border and background-clip:
button {
height: 50px;
border-radius: 25px;
width: 120px;
text-align: center;
color: #fff;
transition: .2s;
margin: 30px;
border: 3px solid transparent; /* we start transparent */
padding: 3px; /* control the space */
background: green content-box; /* color only the content */
}
button:hover {
border-color: blue; /* change color on hover */
}
body {
background:#f2f2f2;
}
<button>Accept</button>

Hide outline on pseudo-element only

I'm trying to absolute position an arrow relative to a button that toggles a filter box using :before pseudo-element.
I think I can't position relative to the filter box because its width is related to other div and I need the triangle to be aligned with the outside button.
Problem: when button is focused, the outline is present both in button and its :before, aka my triangle. I'm searching for a solution that outlines the button, but not its :before.
What I've already tried: set the rule outline: none; in the :before selector. Didn't worked.
What I've achieved:
My code, simplified for question purpose:
/* Toggle control isn't necessary for the purpose of the question */
.button-filter {
background-color: #333;
color: $click-white;
position: relative;
border: none;
color: #fff;
padding: 1em;
}
.button-filter:before {
content: "";
position: absolute;
display: block;
width: 0;
height: 0;
left: calc(50% - 15px);
bottom: -20px;
border-bottom: 15px solid #333;
border-left: 15px solid transparent;
border-right: 15px solid transparent;
}
<button class="button-filter" autofocus>Filter</button>
You can change the outline with a box-shadowto avoid this effect:
.button-filter {
background-color: #333;
position: relative;
border: none;
color: #fff;
padding: 1em;
}
.button-filter:before {
content: "";
position: absolute;
display: block;
width: 0;
height: 0;
left: calc(50% - 15px);
bottom: -20px;
border-bottom: 15px solid #333;
border-left: 15px solid transparent;
border-right: 15px solid transparent;
}
.button-filter:focus {
outline:none;
box-shadow:0 0 5px blue;
}
<button class="button-filter" autofocus>Filter</button>
Asuming that the pseudo will used to create an arrow next to another element, you don't really need it to be a triangle, it can be a rotated square. The lower part of it will be hidden by the other div.
If this is the case, the you can set the pseudo as a small square located inside the button. I set it red to show where it is, but in production you can set background transparent, or set z-index : -1;
And then set a shadow, located where you want the triangle to be. Since this is a shadow, not a real element, the outline won't be applied to it. (Note: the element is rotated, so the shadow coordinates are tricky)
/* Toggle control isn't necessary for the purpose of the question */
.button-filter {
background-color: #333;
color: $click-white;
position: relative;
border: none;
color: #fff;
padding: 1em;
}
.button-filter:after {
content: "";
position: absolute;
display: block;
width: 5px;
height: 5px;
left: 50%;
bottom: 10px;
transform: rotate(45deg);
background-color: red;
box-shadow: 40px 40px 0px 10px black;
}
<button class="button-filter" autofocus>Filter</button>

how can i add to rectangle with arrows border [duplicate]

I would like to make a button like these one just with CSS without using another element.
Button Image
Since the button has a border attached, I think I normally need both, the :before and :after elements to create just one arrow at one side. So to make one arrow at each side I would need another span element inside the link.
The second method I tried is the one you see below. But with this solution they are not properly centered and each side of the arrow is different in length.
Has someone a solution?
/* General Button Style */
.button {
display: block;
position: relative;
background: #fff;
width: 300px;
height: 80px;
line-height: 80px;
text-align: center;
font-size: 20px;
text-decoration: none;
text-transform: uppercase;
color: #e04e5e;
margin: 40px auto;
font-family: Helvetica, Arial, sans-serif;
box-sizing: border-box;
}
/* Button Border Style */
.button.border {
border: 4px solid #e04e5e;
}
.button.border:hover {
background: #e04e5e;
color: #fff;
}
/* Button Ribbon-Outset Border Style */
.button.ribbon-outset.border:after,
.button.ribbon-outset.border:before {
top: 50%;
content: " ";
height: 43px;
width: 43px;
position: absolute;
pointer-events: none;
background: #fff;
}
.button.ribbon-outset.border:after {
left: -3px;
margin-top: -40px;
transform-origin: 0 0;
box-sizing: border-box;
border-bottom: 4px solid #e04e5e;
border-left: 4px solid #e04e5e;
transform: rotate(57.5deg) skew(30deg);
}
.button.ribbon-outset.border:before {
right: -46px;
margin-top: -40px;
transform-origin: 0 0;
box-sizing: border-box;
border-top: 4px solid #e04e5e;
border-right: 4px solid #e04e5e;
transform: rotate(57.5deg) skew(30deg);
}
.button.ribbon-outset.border:hover:after {
background: #e04e5e
}
.button.ribbon-outset.border:hover:before {
background: #e04e5e
}
Click me!
CodePen Demo
Here is another alternate way to get this done with only one element.
This approach works like below:
Two pseudo-elements :before and :after which are about half the size (including borders) of the main .button element. The height of each pseudo-element is 34px + 4px border on one side (top/bottom) and 2px on the other side.
The top half of the shape is achieved using the :before element whereas the bottom half is achieved using the :after element.
Using a rotateX with perspective to achieve the tilted effect and positioning to place the two elements such that they form the expected shape.
/* General Button Style */
.button {
position: relative;
display: block;
background: transparent;
width: 300px;
height: 80px;
line-height: 80px;
text-align: center;
font-size: 20px;
text-decoration: none;
text-transform: uppercase;
color: #e04e5e;
margin: 40px auto;
font-family: Helvetica, Arial, sans-serif;
box-sizing: border-box;
}
.button:before,
.button:after {
position: absolute;
content: '';
width: 300px;
left: 0px;
height: 34px;
z-index: -1;
}
.button:before {
transform: perspective(15px) rotateX(3deg);
}
.button:after {
top: 40px;
transform: perspective(15px) rotateX(-3deg);
}
/* Button Border Style */
.button.border:before,
.button.border:after {
border: 4px solid #e04e5e;
}
.button.border:before {
border-bottom: none; /* to prevent the border-line showing up in the middle of the shape */
}
.button.border:after {
border-top: none; /* to prevent the border-line showing up in the middle of the shape */
}
/* Button hover styles */
.button.border:hover:before,
.button.border:hover:after {
background: #e04e5e;
}
.button.border:hover {
color: #fff;
}
<!-- Library included to avoid browser prefixes -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
Click me!
Fixed Width Demo | Dynamic Width Demo
Output Screenshot:
This is tested in Chrome v24+, Firefox v19+, Opera v23+, Safari v5.1.7, IE v10.
As-is, this would degrade quite well in IE 8 and IE 9 into a square button with borders. However, due to the nullification of one border (border-bottom for :before and border-top for :after) it would leave a white area (resembling a strike-through line) in the middle. This can be overcome by adding a couple of IE < 10 specific styles using conditional comments like in this demo.
<!--[if IE]>
<style>
.button.border:after{
top: 38px;
}
.button.border:hover:before, .button.border:hover:after {
border-bottom: 4px solid #e04e5e;
}
</style>
<![endif]-->
Output Screenshot from IE 9 and IE 8:
This is just a simpler alternative to Harry's answer.
This approach uses scale() and rotate(45deg) transforms. Using this approach, you can very easily change the angle of right and left chevrons.
Fiddle
div {
height: 70px;
width: 200px;
margin-left: 40px;
border-top: 4px solid #E04E5E;
border-bottom: 4px solid #E04E5E;
position: relative;
text-align: center;
color: #E04E5E;
line-height: 70px;
font-size: 21px;
font-family: sans-serif;
}
div:before, div:after {
content:'';
position: absolute;
top: 13px;
height: 40px;
width: 40px;
border: 4px solid #E04E5E;
-webkit-transform: scale(0.8,1.25) rotate(45deg);
-moz-transform: scale(0.8,1.25) rotate(45deg);
-ms-transform: scale(0.8,1.25) rotate(45deg);
transform: scale(0.8,1.25) rotate(45deg);
}
div:before {
left: -22px;
border-top: 0px solid transparent;
border-right: 0px solid transparent;
}
div:after {
right: -22px;
border-bottom: 0px solid transparent;
border-left: 0px solid transparent;
}
div:hover, div:hover:before, div:hover:after {
background-color: #E04E5E;
color: #EEE;
}
<div>HELLO!</div>
Want a wider arrow? Simply decrease scale() transform's x value : Fiddle (wide)
Narrower one? Increase scale() transform's x value : Fiddle (narrow)
Note: IE 8 and below don't support CSS Transforms (9 supports with -ms- prefix), so you can check out this site for supporting them: IE Transform Translator
I forked your Pen
Codepen Demo
The essential changes are that I removed the side borders from the main button (as they were superflous
/* Button Border Style */
.button.border {
border-top: 4px solid #e04e5e;
border-bottom: 4px solid #e04e5e;
}
and changed a couple of values to tweak it all into place
/* Button Ribbon-Outset Border Style */
.button.ribbon-outset.border:after,
.button.ribbon-outset.border:before {
top: 50%;
content: " ";
height: 43px;
width: 43px;
position: absolute;
pointer-events: none;
}
.button.ribbon-outset.border:after {
left:0;
margin-top:-40px;
transform-origin:0 0;
box-sizing:border-box;
border-bottom:4px solid #e04e5e;
border-left:4px solid #e04e5e;
transform:rotate(57.5deg) skew(30deg);
}
.button.ribbon-outset.border:before {
right:-43px;
margin-top:-40px;
transform-origin:0 0;
box-sizing:border-box;
border-top:4px solid #e04e5e;
border-right:4px solid #e04e5e;
transform:rotate(57.5deg) skew(30deg);
}
I got the answer myself. It was a problem of the transform property of the :before and :after elements.
CSS changed:
/* Button Border Style */
.button.border {
border-top:4px solid #e04e5e;
border-bottom:4px solid #e04e5e;
}
/* Button Ribbon-Outset Border Style */
.button.ribbon-outset.border:after, .button.ribbon-outset.border:before {
height: 42px;
width: 42px;
}
.button.ribbon-outset.border:after {
left:0;
border-bottom:5px solid #e04e5e;
border-left:5px solid #e04e5e;
transform:rotate(45deg) skew(19deg,19deg);
}
.button.ribbon-outset.border:before {
right:-42px;
border-top:5px solid #e04e5e;
border-right:5px solid #e04e5e;
transform:rotate(45deg) skew(19deg,19deg);
}
Updated Codepen

CSS Triangle For Testimonial Box

I have a testimonials box that I would like to add a triangle to.
.arrow {
float: left;
margin-left: 25px;
margin-top: 20px;
width: 0;
height: 0;
border-top: 20px solid #eee;
border-left: 0px solid transparent;
border-right: 25px solid transparent;
}
The problem is the triangle ends up being solid, as opposed to white with a gray border. Below is a screenshot of how the CSS currently displays. Thanks in advance for the time and help.
You can create two triangles, one that overlaps the other, to create this bordered effect. You can do this with the ::before and ::after pseudo-elements so that you don't even have any superfluous HTML.
http://jsfiddle.net/7K2c4/
.mybox {
position: relative;
border: 1px solid #ccc;
}
.mybox:before,
.mybox:after { position: absolute;
left: 20px;
bottom: -19px;
display: block;
width: 0;
height: 0;
border-width: 0 25px 20px;
border-style: solid;
border-color: transparent;
border-left-color: #fff;
content: ' ';
}
.mybox:before { left: 19px;
bottom: -21px;
border-left-color: #ccc; }
You can place another triangle over it, smaller with the same color of the box background. You don't even need to create another HTML element, just use a pseudo-element selector.

CSS/Web design: how to create an oblique/sided button

How can one create a button on a website with each side being oblique (diagonals)?
I didn't find an example to show you but this is the closest I could find in 10 minutes:
http://cfl.ca/ (see the menu with tabs: News, Video, Schedule, Standings)
However, in my case, I need that sort of design for an independant button and not for a menu tab.
Here's one (imperfect) way of doing it, though it's a little mark-up heavy:
<div class="button">
<span></span>
Some button text
<span></span>
</div>
With the CSS:
.button {
width: auto;
display: inline-block;
background-color: #f00;
height: 2em;
overflow: hidden;
}
.button span:first-child {
display: inline-block;
border-top: 1em solid #fff;
border-left: 1em solid #fff;
border-bottom: 1em solid #f00;
border-right: 1em solid #f00;
float: left;
margin-right: 1em;
}
.button span:last-child {
display: inline-block;
border-bottom: 1em solid #fff;
border-right: 1em solid #fff;
border-top: 1em solid #f00;
border-left: 1em solid #f00;
margin-left: 1em;
}
.button:hover {
background-color: #0f0;
}
.button:hover span:first-child {
border-right-color: #0f0;
border-bottom-color: #0f0;
}
.button:hover span:last-child {
border-left-color: #0f0;
border-top-color: #0f0;
}
JS Fiddle demo.
I'm not yet sure why the text-is aligned to the bottom of the .button element, but it seems to be a starting point, at least. (And any edits, or comments, left that explain/improve the answer will be welcome as soon as I get back to my desk...).
Edited to revise the demo CSS:
.button {
width: auto;
display: inline-block;
background-color: #f00;
height: 2em;
line-height: 2em; /* centering the text vertically */
}
/* other stuff */
.button span:last-child {
display: inline-block;
border-bottom: 1em solid #fff;
border-right: 1em solid #fff;
border-top: 1em solid #f00;
border-left: 1em solid #f00;
margin-left: 1em;
float: right; /* removes from the 'normal flow' */
margin-top: -2em; /* aligns vertically with the top of the parent .button div */
}
Revised JS Fiddle demo.
Edited in response to Adam's (OP's) question (in comments):
...I'm trying to understand how you did it.
The idea is based around the simple premise that the join between borders is 45°, as illustrated with the following HTML/CSS:
<span id="box"></span>
#box {
display: inline-block;
border-width: 30px;
border-style: solid;
border-top-color: red;
border-right-color: green;
border-bottom-color: yellow;
border-left-color: blue;
}
With the result:
JS Fiddle demo.
That being the case if two adjoining borders are coloured the same two right-angled triangles are created (using the same HTML as above):
#box {
display: inline-block;
border-width: 30px;
border-style: solid;
border-top-color: red;
border-right-color: red;
border-bottom-color: yellow;
border-left-color: yellow;
}
Giving:
JS Fiddle demo.
In the example above I defined the height of the containing element (.box) as 2em, and the borders of the contained span elements as 1em (making the overall height 2em, had I given the spans their own height (or width) the shape would have become more intricate:
#box {
display: inline-block;
border-width: 30px;
border-style: solid;
border-top-color: red;
border-right-color: red;
border-bottom-color: yellow;
border-left-color: yellow;
height: 30px;
}
Giving (with height):
Or, using width:
#box {
display: inline-block;
border-width: 30px;
border-style: solid;
border-top-color: red;
border-right-color: red;
border-bottom-color: yellow;
border-left-color: yellow;
width: 30px;
}
Giving:
Using both width and height allows for a partially-dissected box:
#box {
display: inline-block;
border-width: 30px;
border-style: solid;
border-top-color: red;
border-right-color: red;
border-bottom-color: yellow;
border-left-color: yellow;
width: 30px;
height: 30px;
}
Giving:
This could be useful for pseudo-3D frame effects, perhaps; particularly with :hover effects/changes.
I'm not sure if that's helped, much, but if you have any specific curiosities let me know in the comments, and I'll do my best to answer them. =)
Edited to add a pseudo-element, ::before/::after, solution.
The HTML is simplified somewhat to:
<div class="button">
Some button text
</div>
<div class="button">
Some more button text
</div>
<div class="button">
And yet more button text
</div>​
But the CSS is rather more verbose, not complex, but certainly there seems to be more of it:
.button {
width: auto;
display: inline-block;
background-color: #f00;
height: 2em;
line-height: 2em;
position: relative;
margin-left: 3em;
}
.button::before,
.button::after {
content: '';
border-color: #f00;
border-width: 1em;
border-style: solid;
position: absolute;
top: 0;
bottom: 0;
}
.button::before {
border-top-color: transparent;
border-left-color: transparent;
right: 100%;
}
.button::after {
border-right-color: transparent;
border-bottom-color: transparent;
left: 100%;
}
.button:hover {
background-color: #0f0;
}
.button:hover::before {
border-color: #0f0;
border-top-color: transparent;
border-left-color: transparent;
}
.button:hover::after {
border-color: #0f0;
border-right-color: transparent;
border-bottom-color: transparent;
}
​JS Fiddle demo.
Funnily enough thirtydot posted a link to a tutorial for this earlier today: http://www.joecritchley.com/demos/slanted-nav/
It's for a nav, but the principle should be the same.
You use oblique background images for each element, then overlap the elements to get the images to butt-up to each other visually. The only way to get around not having rectangle hit areas is to use an image map (which you probably don't want to use).
I know it's not the most "techie" answer ever but this site can generate that kind of css for you (and browser compatible if possible)

Resources