Home > Software design >  how to make dropdown width (background) follow parent li without using media queries Css only
how to make dropdown width (background) follow parent li without using media queries Css only

Time:03-19

There is a question very similar to this one which already been solved, yet that solution is not helping me.

The issue I'm facing is the dropdown is not following its parent width ( position: absolute is in play here) and I think position: absolute is the only way to stop the whole nav bar to expand when the dropdown is accessed.

so is there any way I can make dropdown follow its parent width other than using media queries and defining a width for every device?

And forgive me if I'm not able to explain myself clearly. Beginner here.

Thanks

CSS

* {
    box-sizing: border-box;
}
body {
    margin: 0;
    background: #333;
}
ul {
    display: flex;
    background: #9999ff;
    list-style: none;
    padding: 6px;
    overflow: hidden;
    justify-content: space-around;
    line-height: 2;

}

li {
    color: white;
    text-decoration: none;
    text-align: center !important;
    flex-grow: 1;  

}

.drop{
    position: absolute;
    visibility: hidden;
    flex-direction: column;
    color: white;
    background-color: #9999ff;
    line-height: 3;
    /*width: 17em;*/
}
.drop li {
    border: 1px solid transparent;
    text-align: center;
}

li:hover {
    background: black;
    color: plum;
}

li:hover .drop {
    visibility: visible;
    
}

.drop li:hover {
    border: 1px solid rgba(255, 51, 153,1);
}

HTML

<ul>
    <li>Home</li>
    <li>JS
        <ul >
            <li>Node</li>
            <li>React</li>
        </ul>
    </li>

    <li>CSS</li>
    <li>About</li>
</ul>
 

* {
    box-sizing: border-box;
}
body {
    margin: 0;
    background: #333;
}
ul {
    display: flex;
    background: #9999ff;
    list-style: none;
    padding: 6px;
    overflow: hidden;
    justify-content: space-around;
    line-height: 2;

}

li {
    color: white;
    text-decoration: none;
    text-align: center !important;
    flex-grow: 1;  

}

.drop{
    position: absolute;
    visibility: hidden;
    flex-direction: column;
    color: white;
    background-color: #9999ff;
    line-height: 3;
    /*width: 17em;*/
   
    
    
}
.drop li {
    border: 1px solid transparent;
    text-align: center;
}

li:hover {
    background: black;
    color: plum;
}

li:hover .drop {
    visibility: visible;
    
}

.drop li:hover {
    border: 1px solid rgba(255, 51, 153,1);
}
    <ul>
        <li>Home</li>
        <li>JS
            <ul >
                <li>Node</li>
                <li>React</li>
            </ul>
        </li>

        <li>CSS</li>
        <li>About</li>
    </ul>
    

CodePudding user response:

Solution for fixed number of items, all with the same width:

* {
    box-sizing: border-box;
}
body {
    margin: 0;
    background: #333;
}
ul {
    display: flex;
    background: #9999ff;
    list-style: none;
    padding: 6px;
    overflow: hidden;
    justify-content: space-around;
    line-height: 2;

}

li {
    color: white;
    text-decoration: none;
    text-align: center !important;
    flex-grow: 1;  
    width: calc(100vw / 4 - 15px);
}

.drop{
    position: absolute;
    visibility: hidden;
    flex-direction: column;
    color: white;
    background-color: #9999ff;
    line-height: 3;
    /*width: 17em;*/
   
    
    
}
.drop li {
    border: 1px solid transparent;
    text-align: center;
}

li:hover {
    background: black;
    color: plum;
}

li:hover .drop {
    visibility: visible;
    
}

.drop li:hover {
    border: 1px solid rgba(255, 51, 153,1);
}
    <ul>
        <li>Home</li>
        <li>JS
            <ul >
                <li>Node</li>
                <li>React</li>
            </ul>
        </li>

        <li>CSS</li>
        <li>About</li>
    </ul>
    

Relevant snippet:

       li {
          color: white;
          text-decoration: none;
          text-align: center !important;
          flex-grow: 1;  
          width: calc(100vw / 4 - 15px); // full viewport width divided by number of elements, minus paddings
        }

Explanation: Viewport width takes into account the entire viewport width. Divide this by the number of items in our header, and we get our item width. Now this does not take into account paddings, margins and similar, so you have to supply that yourself - but calc() is pretty flexible for this, as long as you know about the actual value of these factors.

CodePudding user response:

I came up with a workaround to fix your problem. It might not be the prettiest but it works!

* {
    box-sizing: border-box;
}
body {
    margin: 0;
    background: #333;
}
ul {
    display: flex;
    background: linear-gradient(180deg, #9999ff 44px, transparent 0px);
    list-style: none;
    padding: 6px;
    overflow: hidden;
    justify-content: space-around;
    line-height: 2;

}

li {
    color: white;
    text-decoration: none;
    text-align: center !important;
    flex-grow: 1;  

}

.drop{
    display: none;
    flex-direction: column;
    color: white;
    background-color: #9999ff;
    line-height: 3;
    /*width: 17em;*/
   
    
    
}
.drop li {
    border: 1px solid transparent;
    text-align: center;
}

li:hover {
    background: black;
    color: plum;
}

li:hover .drop {
    display: block;
    background: #9999ff;
}

.drop li:hover {
    border: 1px solid rgba(255, 51, 153,1);
}
    <ul>
        <li>Home</li>
        <li>JS
            <ul >
                <li>Node</li>
                <li>React</li>
            </ul>
        </li>

        <li>CSS</li>
        <li>About</li>
    </ul>
    

Problem:

We need our .drop element to NOT have position:absolute (because we need to access its parent's width), and we also cannot specify a maximum height for the header itself, as the overflowing dropdown would be hidden from view.

Solution: We set the background of the header to a linear-gradient which has a specified height of 44px for purple color, and 0px for transparent. This means that even if the header changes height, the background gradient color will always have the same height. As a result, the header itself WILL change size, but it is not visually detectable.

Is it a pretty solution? No. Is it good practice? Probably not. Does it work? Well, it does!

I suggest using javascript for similar problems in the future though :)

  • Related