Search code examples
htmlcssnavigationwidthnavbar

Navbar dropdown width resize


I have a navigation bar that is fluid on both desktop and mobile devices. However, the drop-down items widths don't resize based on the parent's width. I would like to hover over a drop-down item and it has the same width as the list item I hovered over. At the moment it has a fixed width but I can't seem to get it working by trying other options. I also cannot get the entire navigation bar to center, as at the moment it is stuck to the left. Thanks for the help!

Here's a codepen of the code: https://codepen.io/Macast/pen/rYQPNe

HTML:

<nav>
        <div id="logo">
            <img src="images/J.-Freeman-&-Son-Landscape-Logo-White.png">
        </div>

        <label for="drop" class="toggle">Menu</label>
        <input type="checkbox" id="drop" />
        <ul class="menu">
            <li><a href="#">Home</a></li>
            <li>
                <!-- First Tier Drop Down -->
                <label for="drop-1" class="toggle">Short +</label>
                <a href="#">Short</a>
                <input type="checkbox" id="drop-1" />
                <ul>
                    <li><a href="#">History</a></li>
                    <li><a href="#">Our Services</a></li>
                    <li><a href="#">Our Aim</a></li>
                </ul>

            </li>
            <li>
                <!-- First Tier Drop Down -->
                <label for="drop-2" class="toggle">Dropdown Even Longer +</label>
                <a href="#">Dropdown Even Longer</a>
                <input type="checkbox" id="drop-2" />
                <ul>
                    <li><a href="#">Option</a></li>
                    <li><a href="#">Option</a></li>
                    <li><a href="#">Option</a></li>
                    <li>
                        <!-- Second Tier Drop Down -->
                        <label for="drop-3" class="toggle">More Options +</label>
                        <a href="#">More Options</a>
                        <input type="checkbox" id="drop-3" />

                        <ul>
                            <li><a href="#">Option</a></li>
                            <li><a href="#">Option</a></li>
                            <li><a href="#">Option</a></li>
                        </ul>
                    </li>
                </ul>
            </li>
            <li><a href="#">Option</a></li>
            <li><a href="#">Option</a></li>
            <li><a href="#">Option</a></li>
            <li><a href="#">Option</a></li>
        </ul>
    </nav>

CSS:

.toggle,
[id^=drop] {
    display: none;
}
/* Giving a background-color to the nav container. */

nav {
    margin: 0;
    padding: 0;
    background-color: #254441;
}
#logo {
    display: block;
    text-align: center;
    /*padding: 0 30px;*/
    /*float: left;*/
    /*font-size: 20px;*/
    /*line-height: 60px; */
}
#logo img {
    width: 30%;
}
/* Since we'll have the "ul li" "float:left"
 * we need to add a clear after the container. */

nav:after {
    content: "";
    display: table;
    clear: both;
}
/* Removing padding, margin and "list-style" from the "ul",
 * and adding "position:reltive" */

nav ul {
    /*float: right;*/
    padding: 0;
    margin: 0;
    list-style: none;
    position: relative;
}
/* Positioning the navigation items inline */

nav ul li {
    margin: 0px;
    display: inline-block;
    float: left;
    background-color: #254441;
    text-align: center;
}
/* Styling the links */

nav a {
    display: block;
    padding: 14px 20px;
    color: #FFF;
    font-size: 17px;
    text-decoration: none;
    text-align: center;
}
nav ul li ul li:hover {
    background: #000000;
}
/* Background color change on Hover */

nav a:hover {
    background-color: #000000;
}
/* Hide Dropdowns by Default
 * and giving it a position of absolute */

nav ul ul {
    display: none;
    position: absolute;
    /* has to be the same number as the "line-height" of "nav a" */
    top: 60px;
}
/* Display Dropdowns on Hover */

nav ul li:hover > ul {
    display: inherit;
}
/* Fisrt Tier Dropdown */

nav ul ul li {
    width: 170px;
    float: none;
    display: list-item;
    position: relative;
    text-align: center;
}
/* Second, Third and more Tiers 
 * We move the 2nd and 3rd etc tier dropdowns to the left
 * by the amount of the width of the first tier.
*/

nav ul ul ul li {
    position: relative;
    top: -60px;
    /* has to be the same number as the "width" of "nav ul ul li" */

    left: 170px;
}
/* Change ' +' in order to change the Dropdown symbol */

li > a:after {
    content: ' +';
}
li > a:only-child:after {
    content: '';
}
/* Media Queries
--------------------------------------------- */

@media all and (max-width: 768px) {
    #logo {
        display: block;
        padding: 0;
        width: 100%;
        text-align: center;
        float: none;
    }
    #logo img {
        width: 100%;
        box-sizing: border-box;
        padding: 20px;
    }
    nav {
        margin: 0;
    }
    /* Hide the navigation menu by default */
    /* Also hide the  */

    .toggle + a,
    .menu {
        display: none;
    }
    /* Stylinf the toggle lable */

    .toggle {
        display: block;
        background-color: #254441;
        padding: 14px 20px;
        color: #FFF;
        font-size: 17px;
        text-decoration: none;
        border: none;
        text-align: center;
    }
    .toggle:hover {
        background-color: #000000;
    }
    /* Display Dropdown when clicked on Parent Lable */

    [id^=drop]:checked + ul {
        display: block;
    }
    /* Change menu item's width to 100% */

    nav ul li {
        display: block;
        width: 100%;
    }
    nav ul ul .toggle,
    nav ul ul a {
        padding: 0 40px;
    }
    nav ul ul ul a {
        padding: 0 80px;
    }
    nav a:hover,
    nav ul ul ul a {
        background-color: #000000;
    }
    nav ul li ul li .toggle,
    nav ul ul a,
    nav ul ul ul a {
        padding: 14px 20px;
        color: #FFF;
        font-size: 17px;
    }
    nav ul li ul li .toggle,
    nav ul ul a {
        background-color: #212121;
    }
    /* Hide Dropdowns by Default */

    nav ul ul {
        float: none;
        position: static;
        color: #ffffff;
        /* has to be the same number as the "line-height" of "nav a" */
    }
    /* Hide menus on hover */

    nav ul ul li:hover > ul,
    nav ul li:hover > ul {
        display: none;
    }
    /* Fisrt Tier Dropdown */

    nav ul ul li {
        display: block;
        width: 100%;
    }
    nav ul ul ul li {
        position: static;
        /* has to be the same number as the "width" of "nav ul ul li" */
    }
}
@media all and (max-width: 330px) {
    nav ul li {
        display: block;
        width: 94%;
    }
}

Solution

  • To adjust the dropdown menu size to the same size as the containing list-item, declare a left and right property value of 0 on the dropdown element in question (nav ul ul), then remove the explicitly declared width on the nested list items of the dropdown menu (nav ul ul li).

    Example:

    nav ul ul {
        display: none;
        position: absolute;
        top: 60px;
        /* additional property values declared */
        left: 0;
        right: 0;
    }
    

    This works because the dropdown menus are already positioned absolute and the containing parent element list item (nav ul li) is already positioned relative.

    You can position absolute elements relative to their parents if their parents are relative.

    So all we are doing here is defining the extent of the dropdown menu width to "stretch" from "left to right" of the parent's width.

    Code Snippet Demonstration:

    .toggle,
    [id^=drop] {
        display: none;
    }
    /* Giving a background-color to the nav container. */
    
    nav {
        margin: 0;
        padding: 0;
        background-color: #254441;
    }
    #logo {
        display: block;
        text-align: center;
        /*padding: 0 30px;*/
        /*float: left;*/
        /*font-size: 20px;*/
        /*line-height: 60px; */
    }
    #logo img {
        width: 30%;
    }
    /* Since we'll have the "ul li" "float:left"
     * we need to add a clear after the container. */
    
    nav:after {
        content: "";
        display: table;
        clear: both;
    }
    /* Removing padding, margin and "list-style" from the "ul",
     * and adding "position:reltive" */
    
    nav ul {
        text-align: center;
        padding: 0;
        margin: 0;
        list-style: none;
        position: relative;
    }
    /* Positioning the navigation items inline */
    
    nav ul li {
        margin: 0px;
        display: inline-block;
        background-color: #254441;
        text-align: center;
        position: relative;
    }
    /* Styling the links */
    
    nav a {
        display: block;
        padding: 14px 20px;
        color: #FFF;
        font-size: 17px;
        text-decoration: none;
        text-align: center;
    }
    nav ul li ul li:hover {
        background: #000000;
    }
    /* Background color change on Hover */
    
    nav a:hover {
        background-color: #000000;
    }
    /* Hide Dropdowns by Default
     * and giving it a position of absolute */
    
    nav ul ul {
        display: none;
        position: absolute;
        /* has to be the same number as the "line-height" of "nav a" */
        top: 60px;
        left: 0;
        right: 0;
    }
    /* Display Dropdowns on Hover */
    
    nav ul li:hover > ul {
        display: inherit;
    }
    /* Fisrt Tier Dropdown */
    
    nav ul ul li {
        /*width: 170px;*/
        float: none;
        display: list-item;
        position: relative;
        text-align: center;
    }
    /* Second, Third and more Tiers	
     * We move the 2nd and 3rd etc tier dropdowns to the left
     * by the amount of the width of the first tier.
    */
    
    nav ul ul ul li {
        position: relative;
        top: -60px;
        /* has to be the same number as the "width" of "nav ul ul li" */
        
        left: 170px;
    }
    /* Change ' +' in order to change the Dropdown symbol */
    
    li > a:after {
        content: ' +';
    }
    li > a:only-child:after {
        content: '';
    }
    /* Media Queries
    --------------------------------------------- */
    
    @media all and (max-width: 768px) {
        #logo {
            display: block;
            padding: 0;
            width: 100%;
            text-align: center;
            float: none;
        }
        #logo img {
            width: 100%;
            box-sizing: border-box;
            padding: 20px;
        }
        nav {
            margin: 0;
        }
        /* Hide the navigation menu by default */
        /* Also hide the  */
        
        .toggle + a,
        .menu {
            display: none;
        }
        /* Stylinf the toggle lable */
        
        .toggle {
            display: block;
            background-color: #254441;
            padding: 14px 20px;
            color: #FFF;
            font-size: 17px;
            text-decoration: none;
            border: none;
            text-align: center;
        }
        .toggle:hover {
            background-color: #000000;
        }
        /* Display Dropdown when clicked on Parent Lable */
        
        [id^=drop]:checked + ul {
            display: block;
        }
        /* Change menu item's width to 100% */
        
        nav ul li {
            display: block;
            width: 100%;
        }
        nav ul ul .toggle,
        nav ul ul a {
            padding: 0 40px;
        }
        nav ul ul ul a {
            padding: 0 80px;
        }
        nav a:hover,
        nav ul ul ul a {
            background-color: #000000;
        }
        nav ul li ul li .toggle,
        nav ul ul a,
        nav ul ul ul a {
            padding: 14px 20px;
            color: #FFF;
            font-size: 17px;
        }
        nav ul li ul li .toggle,
        nav ul ul a {
            background-color: #212121;
        }
        /* Hide Dropdowns by Default */
        
        nav ul ul {
            float: none;
            position: static;
            color: #ffffff;
            /* has to be the same number as the "line-height" of "nav a" */
        }
        /* Hide menus on hover */
        
        nav ul ul li:hover > ul,
        nav ul li:hover > ul {
            display: none;
        }
        /* Fisrt Tier Dropdown */
        
        nav ul ul li {
            display: block;
            width: 100%;
        }
        nav ul ul ul li {
            position: static;
            /* has to be the same number as the "width" of "nav ul ul li" */
        }
    }
    @media all and (max-width: 330px) {
        nav ul li {
            display: block;
            width: 94%;
        }
    }
    <nav>
                <div id="logo">
                    <img src="images/J.-Freeman-&-Son-Landscape-Logo-White.png">
                </div>
    
                <label for="drop" class="toggle">Menu</label>
                <input type="checkbox" id="drop" />
                <ul class="menu">
                    <li><a href="#">Home</a></li>
                    <li>
                        <!-- First Tier Drop Down -->
                        <label for="drop-1" class="toggle">Short +</label>
                        <a href="#">Short</a>
                        <input type="checkbox" id="drop-1" />
                        <ul>
                            <li><a href="#">History</a></li>
                            <li><a href="#">Our Services</a></li>
                            <li><a href="#">Our Aim</a></li>
                        </ul>
    
                    </li>
                    <li>
                        <!-- First Tier Drop Down -->
                        <label for="drop-2" class="toggle">Dropdown Even Longer +</label>
                        <a href="#">Dropdown Even Longer</a>
                        <input type="checkbox" id="drop-2" />
                        <ul>
                            <li><a href="#">Option</a></li>
                            <li><a href="#">Option</a></li>
                            <li><a href="#">Option</a></li>
                            <li>
                                <!-- Second Tier Drop Down -->
                                <label for="drop-3" class="toggle">More Options +</label>
                                <a href="#">More Options</a>
                                <input type="checkbox" id="drop-3" />
    
                                <ul>
                                    <li><a href="#">Option</a></li>
                                    <li><a href="#">Option</a></li>
                                    <li><a href="#">Option</a></li>
                                </ul>
                            </li>
                        </ul>
                    </li>
                    <li><a href="#">Option</a></li>
                    <li><a href="#">Option</a></li>
                    <li><a href="#">Option</a></li>
                    <li><a href="#">Option</a></li>
                </ul>
            </nav>

    In Addition:
    You can horizontally center the navigation menu by removing the float rule declared on nested list-items (nav ul li), as this will negate any attempt to align content (unless you use flex-box), then declare text-align: center on the containing unordered list (.menu), as demonstrated below:

    nav ul {
        text-align: center;
        padding: 0;
        margin: 0;
        list-style: none;
        position: relative;
    }