Search code examples
cssmenuz-indexcss-position

How to create a transparent current state notch onto a fixed menu?


I know we can use triangles that are the same color as the background-color in order to put a notch in the current state on a nav. However, I've created a nav menu within a fixed-position div that has a high z-index and background-color set to an opacity of .7, so that the whole nav sits on top of the page content, but you can see through it as you scroll down the page. Is it possible to create a current state notch that "cuts" through the opaque div to show the content beneath it as you scroll down the page?

For reference, I'm trying to replicate the experience you get on iOS app store. Unfortunately, the image has been deleted, following the link to the image gives a 404 page. You can check the revision history to see the original URL of the image.


Solution

  • There are many ways you could do this, here's my take on it:

    This is the layout I would use. The <nav> is fixed at the top with a <div> for the notch right below. The content is underneath both of those with a padding-top equal to the heights of the nav and notch.

    +--------------------------------+--+
    |                                |  |
    |               nav (fixed)      |  |   <-- the content is below these fixeds,
    |                                |  |       which have a higher z-index
    +--------------------------------+  |
    |              notch (fixed)     |  |
    +--------------------------------+  |
    |                                   |
    |                                   |
    |                                   |
    |              content              |
    |              section              |
    | (padding-top = nav+notch heights) |
    |                                   |
    |                                   |
    +-----------------------------------+
    

    I am going to assume you want a fluid layout, so I am opting to use FlexBox (http://www.w3.org/TR/css3-flexbox/) to keep the notch positioned where it should be as the browser resizes. If you have a fixed layout, there are several more straight-forward solutions which don't require FlexBox or calculating where the notch should be placed in the flexible container.

    As the other parts should be fairly straightforward, here is the breakdown of the notch <div>

    +---------------------------------------------------+
    |                 |       |       |                 |
    |     spacing     | notch | notch |     spacing     |
    |   (flexible)    | left  | right |    (flexible)   |
    |                 |       |       |                 |
    +---------------------------------------------------+
    

    The two outer <div>s are flexed and have the same background-color as <nav>. Then, the two inner notches are using gradients to create the triangles.

    background: -webkit-linear-gradient(
        top left,
        rgba(145, 145, 145, 1) 0%,
        rgba(145, 145, 145, 1) 50%,
        transparent 50%,
        transparent 100%
    );
    

    By starting the gradients at top left and top right, the <div>s are filled in half-way on a diagonal.

    The rest is just determining where the notch should be placed as you click on the nav links. I do this by adding and removing width from the flexible <div>s after determining where the user clicked. It will take some time to understand how FlexBox works when adding and subtracting widths from elements that are flexing but you can inspect the code to see that.

    I did all of this in Chrome using -webkit- prefixes so please run this JSFiddle in Chrome or Safari: http://jsfiddle.net/dwJbq/

    As I stated previously, there are several other ways this could be done and it would also be much easier if not using a fluid layout. Another idea you could try is to have a notch for every nav link, and then showing/hiding the notch underneath the link that was clicked. This doesn't require you to calculate anything, rather just change the backgrounds of the notches.

    Here is an example of how that could be done: http://jsfiddle.net/V4K6K/1/