Question: Why when you make css shapes using the border tricks seen here does it move the visual of your element out of its dom-box?
So I found these two questions while searching:
Can I use CSS hover on this complex irregular shaped link
Hovering on overlapping CSS3 shapes
But I don't think that either addresses my question (though if I want to change my html structure I could probably use the answer from that first link.
Example pics to illustrate:
Which means that when I hover over the bottom half of that element it highlights the one below it.
I understand that even though I have a diamond visually the box-model says that it's still a rectangle, but why is the diamond not contained inside that rectangle?
Is there a way around this - with css/markup -, or do I have to go with the maping solution from the first link?
My source code incase anyone wants that:
<header class="navigation">
<div class="nav">
<ul class='master_nav'>
<li>Home</li>
<li>About</li>
<li>Resources</li>
<li>FAQs</li>
</ul>
</div>
</header>
.navigation li{
height: 0;
width: 0;
margin: 10px 0;
list-style: none;
position: relative;
border: 70px solid transparent;
border-bottom: 90px solid #2B2B2B;
display: block;
}
.navigation li:after{
content: '';
position: absolute;
left: -70px; top: 90px;
width: 0;
height: 0;
border: 70px solid transparent;
border-top: 90px solid #2B2B2B;
}
.navigation li a{
height: 25px;
width: 100%;
display: inline-block;
text-decoration: none;
color: #b7b7b7;
position: absolute;
top: 75px;
left: -19px;
}
.navigation li:hover a{
color: #010101;
}
I'm not 100% sure why but you can get around it by making the <a> the hover target and filling the space:
.navigation li a{
height:70px;
width: 80px;
display: block;
text-decoration: none;
color: #b7b7b7;
position: absolute;
top: 38px;
left: -40px;
padding-top: 40px;
text-align: center;
border: 1px solid yellow; //just to see it.
}
.navigation a:hover{
color: #010101;
}
Here's a working pen http://codepen.io/willthemoor/pen/KpcLD/ (updated)
Edit
Getting it lined up perfectly might take a little trial and error but you can use the transform property to rotate and skew the <a> to match the shape. I updated the pen.
I had to add some skew to match the shape of the diamonds, and then use a a <span> inside of the <a> to sort revert the changes. Skew messes with text so you might try to find a happy medium between the shape of your border diamonds and the shape you can make without using skew.
.navigation li{
height: 0;
width: 0;
margin: 10px 0;
list-style: none;
position: relative;
border: 70px solid transparent;
border-bottom: 90px solid #2B2B2B;
display: block;
/* position fix */
top: -90px;
left: -19px;
}
.navigation li:before{
content: '';
position: absolute;
left: -70px;
top: 90px;
width: 0;
height: 0;
border: 70px solid transparent;
border-top: 90px solid #2B2B2B;
}
.navigation li a{
background-color: rgba(255, 0, 0, 0.3);
color: #B7B7B7;
display: block;
height: 68px;
left: -55px;
padding-top: 40px;
position: absolute;
text-align: center;
text-decoration: none;
top: 34px;
-webkit-transform:rotate(314deg);
transform: rotate(314deg);
width: 110px;
}
.skew li a {
/* following lines it up better but hard to 'rewind it' on the span witout the text looking a little strange */
-webkit-transform: rotate(310deg) skewX(-11deg) skewY(-2deg);
transform: rotate(310deg) skewX(-11deg) skewY(-2deg);
height: 73px;
left: -55px;
width: 112px;
}
.navigation a:hover{
background-color: rgba(0,0,255,.3);
color: #010101;
}
.navigation a > span {
display: block;
/* and reset the text*/
-webkit-transform: rotate(46deg);
transform: rotate(46deg);
}
.skew a > span {
-webkit-transform: rotate(45deg);
transform: rotate(45deg);
letter-spacing: .04em;
}
/*
lis are actually covering each other on the bottoms.
Adding this hacky bit makes the bottom of the diamond link work. Could use classes instead.
*/
.navigation li { z-index: 100; }
.navigation li + li { z-index: 90; }
.navigation li + li + li { z-index: 80; }
.navigation li + li + li + li { z-index: 70; }
Related
I am planning to use Bootstrap's Scrollspy component to work on a <ul> element.
The issue for me is that when I use the border-left property on a <li> element, the text in the anchor tag gets shifted a little to the right.
What could I do to fix this?
Please see Pen:
https://codepen.io/AshNaz87/pen/QmVJVY
.wrapper {
position: fixed;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
li {
list-style: none;
margin-bottom: 0.5rem;
padding-left: 1rem;
}
li:last-child {
margin: 0;
}
.with-border {
border-left: 3px solid grey;
}
a {
text-decoration: none;
color: #000;
}
<div class="wrapper">
<ul class="nav">
<li class="with-border">Fortune</li>
<li>Favours</li>
<li>The</li>
<li class="with-border">Brave</li>
</ul>
</div>
The reason why you're seeing this inconsistent offset of the text is because the border of an element actually take up physical space in the layout. To circumvent this, you will need to account for the space the border will take (see solution 1), or use alternative strategies that do not alter the flow of the document (see solution 2 and 3).
You can either use a:
transparent left-border on all your elements <li>,
background-image to visually mimic a border, or
abolustely positioned pseudo-element
Solution 1: Transparent left border
This solution means introducing a transparent border on all <li> elements, and simply changing the border-color property when needed:
li {
border-left: 3px solid transparent;
}
li.with-border {
border-color: grey;
}
.wrapper {
position: fixed;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
li {
border-left: 3px solid transparent;
list-style: none;
margin-bottom: 0.5rem;
padding-left: 1rem;
}
li:last-child {
margin: 0;
}
li.with-border {
border-color: grey;
}
a {
text-decoration: none;
color: #000;
}
<div class="wrapper">
<ul class="nav">
<li class="with-border">Fortune</li>
<li>Favours</li>
<li>The</li>
<li class="with-border">Brave</li>
</ul>
</div>
Solution 2: background-image to mimic border
Alternatively, you can use a linear gradient as a background image with a clearly demarcated border/breakpoint, to visually mimic a border:
li.with-border {
background-image: linear-gradient(90deg, grey 3%, transparent 3%);
}
.wrapper {
position: fixed;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
li {
list-style: none;
margin-bottom: 0.5rem;
padding-left: 1rem;
}
li:last-child {
margin: 0;
}
li.with-border {
background-image: linear-gradient(90deg, grey 3%, transparent 3%);
}
a {
text-decoration: none;
color: #000;
}
<div class="wrapper">
<ul class="nav">
<li class="with-border">Fortune</li>
<li>Favours</li>
<li>The</li>
<li class="with-border">Brave</li>
</ul>
</div>
Solution 3: Absolutely-positioned pseudo-element
This solution is the most verbose one: it uses a generated pseudo-element that is absolutely positioned within the <li> element to visually mimic a border:
li {
position: relative;
}
li::before {
position: absolute;
top: 0;
left: 0;
bottom: 0;
width: 3px;
display: none;
content: '';
background-color: grey;
}
li.with-border::before {
display: block;
}
.wrapper {
position: fixed;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
li {
position: relative;
list-style: none;
margin-bottom: 0.5rem;
padding-left: 1rem;
}
li:last-child {
margin: 0;
}
li::before {
position: absolute;
top: 0;
left: 0;
bottom: 0;
width: 3px;
display: none;
content: '';
background-color: grey;
}
li.with-border::before {
display: block;
}
a {
text-decoration: none;
color: #000;
}
<div class="wrapper">
<ul class="nav">
<li class="with-border">Fortune</li>
<li>Favours</li>
<li>The</li>
<li class="with-border">Brave</li>
</ul>
</div>
So I've created part of a ribbon menu I plan on using myself. So here is what it looks like so far:
Before hover:
On hover:
Basically, I want it to show my social icon as well as being able to use my other banners when i add them in.
Here is the code that I am using so far:
<body>
<ul class="social">
<li class="ribbon" media="facebook"><i class="fa fa-facebook" aria-hidden="true"></i></li>
</ul>
<script src="https://use.fontawesome.com/c2f336433a.js"></script>
</body>
Here is the CSS:
#import 'reset';
#import 'mixins';
ul.social {
position: absolute;
z-index: 4;
margin: -225px auto;
list-style: none;
right: 0;
li.ribbon {
float: right;
cursor: pointer;
position: relative;
width: 75px;
height: 250px;
border: none;
color: white;
padding: 5px;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
#include transition(all .2s ease-in-out);
#include filter(drop-shadow(0 1px 10px rgba(0, 0, 0, 0.5)));
span {
line-height: 20px;
font-size: 5em;
}
}
li.ribbon:hover {
margin-top: 70px;
color: white;
}
li.ribbon:before {
content: '';
position: absolute;
top: 100%; left: 0;
width: 0; height: 0;
border-top: 25px solid blue;
border-right: 50px solid transparent;
}
li.ribbon:after {
content: '';
position: absolute;
top: 100%; right: 0;
width: 0; height: 0;
border-top: 25px solid blue;
border-left: 50px solid transparent;
}
li.ribbon[media="facebook"] {
background: #3b5998;
color: #1e2e4f;
margin-right: 5px;
}
li.ribbon[media="facebook"]:before,
li.ribbon[media="facebook"]:after {
border-top-color: #3b5998;
}
}
Note that the reset is just an eric meyer reset and the mixins are just for transitions etc...
The reason why you weren't able to see the icon was because there was a negative margin of 225px on the ul. On hover, only the margin-top of the li was being set to 70px but the ul still has the negative margin, so the li is still around 155px above the viewport. This means that the a which is not positioned (that is, has static positioning) and is near the top of the li is still not visible.
You can correct this by avoiding the margin on the ul and just moving the li around. I've used the transform: translateY() to move the li around because that is better for performance than using margins (which need repainting).
I have also added some extra properties like text-align, line-height etc for a better look.
ul.social {
position: absolute;
z-index: 4;
margin: 0px auto; /* modified */
list-style: none;
right: 0;
}
ul.social li.ribbon {
float: right;
cursor: pointer;
position: relative;
width: 75px;
height: 100px; /* modified */
border: none;
color: white;
padding: 5px;
text-align: center; /* added */
line-height: 100px; /* added, equal to height */
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
transform: translateY(-100%); /* added */
transition: all .2s ease-in-out;
-webkit-filter: drop-shadow(0 1px 10px rgba(0, 0, 0, 0.5));
}
ul.social li.ribbon span {
line-height: 20px;
font-size: 5em;
}
ul.social li.ribbon:hover {
transform: translateY(0%); /* added */
/* margin-top: 70px; removed for better performance */
}
ul.social li.ribbon:before {
content: '';
position: absolute;
top: 100%;
left: 0;
width: 0;
height: 0;
border-top: 25px solid blue;
border-right: 50px solid transparent;
}
ul.social li.ribbon:after {
content: '';
position: absolute;
top: 100%;
right: 0;
width: 0;
height: 0;
border-top: 25px solid blue;
border-left: 50px solid transparent;
}
ul.social li.ribbon[media="facebook"] {
background: #3b5998;
color: #1e2e4f;
margin-right: 5px;
}
ul.social li.ribbon[media="facebook"]:before,
ul.social li.ribbon[media="facebook"]:after {
border-top-color: #3b5998;
}
/* added */
ul.social li.ribbon a {
color: white;
}
<body>
<ul class="social">
<li class="ribbon" media="facebook"><i class="fa fa-facebook" aria-hidden="true"></i>
</li>
</ul>
<script src="https://use.fontawesome.com/c2f336433a.js"></script>
</body>
Is there any way to create the border on the left with css ?
Here is a way to do it using CSS; you are just layering a Parallelogram and a Rectangle:
.espanolIcon
{
width: 300px;
height: 100px;
padding-left: 30px;
}
.rectangle {
position: absolute;
top: 0px;
left: 200px;
width: 200px;
height: 100px;
background-color: green;
border-radius: 0px 0px 30px 40px;
}
.arrow-left {
position: absolute;
top: 0px;
width: 300px;
height: 100px;
background-color: green;
-webkit-transform: skew(22deg);
transform: skew(22deg);
border-radius: 0px 0px 30px 40px;
}
h1 {
color: white;
}
<div class="espanolIcon">
<div class="rectangle"><h1>Espanol</h1></div>
<div class="arrow-left"></div>
</div>
Use a zero-dimension :before with thick, partial borders
By adjusting the top/bottom and left/right values of border-width on the :before pseudo-element, you can effectively change the skew of the triangle. The left position can then be changed to properly align the pseudo-element.
a {
display: inline-block;
position: relative;
margin-left: 14px; /* Should counter `left` value of `a:before` */
padding: .5em 1em;
color: #fff;
font: bold 1em/1 sans-serif;
text-decoration: none;
text-transform: uppercase;
border-radius: 0 0 10px 10px;
background: #75bf41;
}
a:before {
content: '\200B'; /* zero-width non-breaking space */
display: block;
position: absolute;
top: 0;
left: -14px; /* Adjust to align */
width: 0;
height: 0;
border-width: 14px 8px; /* Adjust top/bottom and left/right to skew */
border-style: solid;
border-color: #75bf41 #75bf41 transparent transparent; /* Triangle orientation. */
}
Español
Full css could work, but you should use .png as background-image or perhaps you could use .svg as you can animate and/or change every point or pixel. You might be able to use just CSSbut it would take a lot of leveling and positioning and alot of layers of absolute and relative positioning. As Css would only change the full width of the element, and it can only be used to change the width of elements. What you can do is use .svg, you could map every pixel which could be animated.
I accomplished it using borders and pseudo elements.
<ul>
<li class="lang-item lang-item-6 lang-item-es">
::before
<a>Español</a>
</li>
</ul>
ul {
position:relative;
}
.lang-item {
text-align: right;
position: relative;
}
.lang-item a {
background: #76c53f;
padding: 15px;
color: #fff;
text-transform: uppercase;
border-bottom-right-radius: 10px;
border-bottom-left-radius: 14px;
}
.lang-item::before {
position: absolute;
right: 101px;
top: -15px;
content: "";
display: inline-block;
border-top: 40px solid #76C541;
border-left: 40px solid transparent;
}
jsfiddle
I want to produce something like the following (note the inverted arrow below "Product":
I want to show an inverted arrow below the active menu item. The mega menu is inside Bootstrap .container.
However with my skills this is what I've been able to accomplish so far. There are two overflowing lines from both sides. I have created these using :before and :after of the arrow element inside the active <li>. Challenge is to make them visible only within the range of .container below
Demo
I didn't see the demo link, but already set up this pure CSS code for you:
<ul>
<li>Menu item</li>
<li>Menu item</li>
<li>Menu item</li>
</ul>
<div class="content"> </div>
ul {
margin: 0 auto;
width: 90%;
height: 60px;
overflow: hidden;
position: relative;
}
ul li {
float: right;
padding: 5px;
height: 40px;
background: lightblue;
position: relative;
}
ul li:hover:before {
content: ' ';
position: absolute;
right: 50%;
margin-right: 5px;
top: 40px;
width: 10000px;
height: 20px;
background: white;
-webkit-transform: skew(20deg);
-moz-transform: skew(20deg);
-o-transform: skew(20deg);
}
ul li:hover:after {
content: ' ';
position: absolute;
left: 50%;
margin-left: 5px;
top: 40px;
width: 10000px;
height: 20px;
background: white;
-webkit-transform: skew(-20deg);
-moz-transform: skew(-20deg);
-o-transform: skew(-20deg);
}
ul:after {
content: ' ';
position: absolute;
top: 40px;
width: 100%;
height: 20px;
background: white;
}
ul:hover:after {
display: none;
}
It creates a 20px space under the menu items. This space is filled by a ul:after element. When hovering the ul, the :after class gets removed. When hovering the menu items, a li:before and li:after are shown, which provide a white background and is skewed, making it look like an arrow.
The only downside with this script is that the default white space (presented by ul:after) is also removed when hovering the ul and not the li. Maybe someone can come up with a fix for that.
JSFiddle
The way you did it is way too complicated. The spaces are due to the height of your pseudo-elements. In this example I deleted your arrows and replace them with CSS triangles, you just need a pseudo element on your open class like this (I let you tweak dimension and position):
.open::after {
content: '';
position: absolute;
left: 50%;
top: 126px;
transform: translate(-50%, 0);
display: block;
width: 0;
height: 0;
border-style: solid;
border-width: 8px 5px 0 5px;
border-color: #808080 transparent transparent transparent;
}
Example : http://codepen.io/mbrillaud/pen/ZGOqoa?editors=110
Done the following modifications: RESULT PEN
Added z-index, adjusted margin-top and removed width from :after and :before . The reason you were getting extra white background was because you have given the width as 100vw full viewport which was not needed
.header .menu > li.open.horizontal > span.arrow {
background-image:
url(https://s3.amazonaws.com/imgrvx/white.svg);
background-repeat: no-repeat;
width: 14px;
height: 7px;
left: calc(50% - 14px);
margin-top: 19px;
position: absolute;
z-index:2;
}
.header .menu > li.open.horizontal > span.arrow:before {
content: '';
position: absolute;
height: 7px;
width: 100vw;
background-color: #ffffff;
display: block;
left: -100vw;
border-top: 1px solid #e6e6e6;
}
.header .menu > li.open.horizontal > span.arrow:after {
content: '';
position: absolute;
height: 7px;
left: 14px;
background-color: #ffffff;
border-top: 1px solid #e6e6e6;
}
I'm trying to get a trapezoidal perspective shape to have the whole area be clickable. I've gotten it to work in Firefox and even IE, but Chrome isn't cooperating too well.
Here's a fiddle with the shape and a link: http://jsfiddle.net/9n9uh6f6/1/
As you can tell, the link doesn't become active until you hover over the 'area' part of the text. In other browsers, the whole height of the shape is clickable.
I read that Chrome renders a perspective image differently and perhaps that's why it's not doing what it's supposed to.
Here's my CSS:
.prodcaptions {
width:136px;
height: 85px;
position:relative;
left:10%;
text-transform:uppercase;
text-align:center;
letter-spacing: 1.6px;
color: #000;
}
.prodcaptions:before {
content:"";
position:absolute;
border-radius:1px;
box-shadow:0 0 0 3px #27628e;
top:-5%;
bottom:-11%;
left:-1%;
right:-5%;
-webkit-transform:perspective(40em) rotateX(-45deg);
transform:perspective(40em) rotateX(-45deg);
}
.prodcaptions a {
z-index:999;
position:relative;
height: 85px;
display: block;
padding-top: 25px;
}
Please have look at this code:
.prodcaptions {
position: relative;
height: 150px;
width: 150px;
margin: 50px;
padding: 10px;
perspective: 150px;
perspective-origin: 50% 0;
}
a{
padding: 50px;
position: absolute;
border: 1px solid black;
transform: rotateX(-15deg);
}
Seems to work the way you want it. fiddle
Try this shape for link trapazoid shape - jsFiddle
Advantage - you can change skew property to change angle of shape! Easy and effective! Reverse value for reverse shape!
html
Click Here!
css
a {
display: block;
z-index: 1;
position: relative;
/* custom sizes */
width: 136px;
height: 85px;
/* demo-only decoration */
margin: 100px auto;
font: 16px/50px Arial, sans-serif;
text-transform: uppercase;
text-align: center;
background-color: orange;
}
a:before, a:after {
content:'';
position: absolute;
top: 0;
left: 0;
width: 100%;
bottom: 0;
z-index: -1;
/* demo-only decoration */
border-radius: 4px;
background-color: orange;
}
a:before {
transform: skew(-20deg);
left: 25px;
}
a:after {
transform: skew(20deg);
right: 25px;
left: auto;
}