$background-color: #999; $ribbon-color: hsla(292,87%,38%,1); $contrast-color: if(lightness($ribbon-color) > 50%, darken($ribbon-color, 50%), lighten($ribbon-color, 50%)); $nav-height: 100px; $tab-width: 100px; $transition-speed: 200ms; $ribbon-hover-distance: 15px; * { margin: 0; padding: 0; } body { font-family: sans-serif; } a { text-decoration: none; color: $contrast-color; } span.title-label { //Center label within tab position: relative; display: inline-block; top: 50%; transform: translateY(-50%); } nav { background-color: $background-color; //Unrelated to the size of the nav -- I just wanted to give it some breathing room margin-top: 100px; height: $nav-height; //aligns the ul to the middle of the nav //Also cascades down to the anchors text-align: center; ul { // centers the UL vertically position: relative; display: inline-block; top: 50%; transform: translateY(-50%); height: $nav-height/2; /* Ribbon sides */ &:before, &:after { content: ""; position: absolute; display: block; //Each triangle should be half the height of the UL (which is half the height of the nav) //Triangles are rendered using borders border: $nav-height/4 solid $ribbon-color; } &:before { //The pseudo-element is actually outside of the UL by its own size //so the right edge lines up with the left edge of the UL transform: translateX(-100%); //The length of the ribbon sides (changing it doesn't look weird) border-right-width: 100%; //Cuts away the outside triangle border-left-color: transparent; } &:after { //Moves the right side to the right right: 0; //And brings the pseudo-element outside of the UL transform: translateX(100%); //Length of right ribbon side border-left-width: 100%; border-right-color: transparent; } li { /* - Removes list decoration - Helps position pseudo-elements */ display: block; //Makes it so that the tabs don't stack float: left; width: $tab-width; height: 100%; background-color: $ribbon-color; //Adds the little creases between the tabs border-right: 1px dotted mix($contrast-color, $ribbon-color); &:first-child { border-left: 1px dotted mix($contrast-color, $ribbon-color); } a { //Makes the a fill up the tab (so clicking anywhere in the tab works) display: inline-block; width: 100%; height: $nav-height/2; } &:hover { a { background-color: lighten($ribbon-color, 10); //Adds a hitbox to prevent odd hover behavior //It's actually a pretty large hitbox //Good usability in general &::before { content: ''; display: block; height: 300%; width: 100%; position: absolute; transform: translateY(-50%); } transition: background-color $transition-speed; } border-color: transparent; transition: transform $transition-speed; //Makes the hovered LI get bigger and moves it down //.5 * .125 * $nav-height is half the amount the height of the LI grows //(It grows 25%, so 12.5% is the amount that will bring it flush to the top after it grows) //However, because we're scaling by 1.25, the translation also scales, so we need to scale it // down by 80% transform: scale(1.25) translateY((.8 * .125 * .5 * $nav-height) + $ribbon-hover-distance); position: relative; z-index: 1; } /* "ligaments" -- the parts that connect the expanded tab to the rest of the ribbon */ &::before, &::after { transform: translateY(-100%); content: ''; position: absolute; display: block; border-style: solid; border-width: 0; opacity: 0; transition: border-width $transition-speed ease; } &::before { left: 0; } &::after { right: 0; } $ligament-color: darken($ribbon-color, 20); &:hover::before { border-color: transparent $ligament-color transparent transparent; //The triangle fits perfectly to make the shape we want //The height is the ribbon hover distance //The width is the amount the LI grows divided by two, adjusted by the amount we're scaling by border-width: $ribbon-hover-distance $tab-width*.125*.8 0 0; opacity: 1; } &:hover::after { border-color: transparent transparent transparent $ligament-color; border-width: $ribbon-hover-distance 0 0 $tab-width*.125*.8; opacity: 1; position: absolute; top: 0; } } } }

!