0

I have an admin header from Django which is divided in 2 columns with css grid. I included a JavaScript dropdown effect on the user icon to show other elements like "Change Password" and "Log Out" but the problem is that dropdown stays hidden inside the column, doesn't show outside.

I need to mention that drop-down stays in a container with clip-path: polygon applied.

How can I fix this?

Thanks in advance,

A newbie in web development

Images attached will show exactly the situation described above: enter image description here

Forced height of header to show the dropdown: enter image description here

Below you can find partial Django code:

{% load i18n static %}<!DOCTYPE html>
{% get_current_language as LANGUAGE_CODE %}{% get_current_language_bidi as LANGUAGE_BIDI %}
<html lang="{{ LANGUAGE_CODE|default:"en-us" }}" {% if LANGUAGE_BIDI %}dir="rtl"{% endif %}>
<head>
<title>{% block title %}{% endblock %}</title>
<link rel="stylesheet" type="text/css" href="{% block stylesheet %}{% static "admin/css/base.css" %}{% endblock %}">
{% block extrastyle %}{% endblock %}
{% if LANGUAGE_BIDI %}<link rel="stylesheet" type="text/css" href="{% block stylesheet_rtl %}{% static "admin/css/rtl.css" %}{% endblock %}">{% endif %}
{% block extrahead %}
    {{ block.super }}
    <script>
        /* When the user clicks on the button,
        toggle between hiding and showing the dropdown content */
        function openDropdown() {
          document.getElementById("myDropdown").classList.toggle("show");
        }
        // Close the dropdown if the user clicks outside of it
        window.onclick = function(event) {
          if (!event.target.closest('.dropbtn')) {
            let dropdowns = document.getElementsByClassName("dropdown-content");
            let i;
            for (i = 0; i < dropdowns.length; i++) {
              let openDropdown = dropdowns[i];
              if (openDropdown.classList.contains('show')) {
                openDropdown.classList.remove('show');
              }
            }
          }
        }
    </script>
{% endblock %}

Header code in Django

<div id="header">
        <div id="branding">
        {% block branding %}{% endblock %}
        </div>
        {% block usertools %}
        {% if has_permission %}
        <div id="user-tools">
            {% block welcome-msg %}
                {% trans 'Welcome,' %}
                <strong>{% firstof user.get_short_name user.get_username %}</strong>.
            {% endblock %}
            {% block userlinks %}
{#                {% if site_url %}#}
{#                    <a href="{{ site_url }}">{% trans 'View site' %}</a> /#}
{#                {% endif %}#}
                {% if user.is_active and user.is_staff %}
                    {% url 'django-admindocs-docroot' as docsroot %}
                    {% if docsroot %}
                        <a href="{{ docsroot }}">{% trans 'Documentation' %}</a> /
                    {% endif %}
                {% endif %}
            <div class="dropdown">
                <button onclick="openDropdown()" class="dropbtn"><img src="{% static "admin/img/user.svg"%}" alt="User Menu" style="height: 30px;"></button>
                <div id="myDropdown" class="dropdown-content">
                    {% if user.has_usable_password %}
                    <a href="{% url 'admin:password_change' %}">{% trans 'Change password' %}</a> /
                    {% endif %}
                    <a href="{% url 'admin:logout' %}">{% trans 'Log out' %}</a>
                </div>
            </div>
            {% endblock %}
        </div>

I'm showing the CSS for the dropdown menu:

/* Dropdown in navbar */

.dropbtn {
  background-color: #0071ce;
  color: white;
  /*padding: 16px;*/
  font-size: 16px;
  border: none;
  cursor: pointer;
}

.dropbtn:hover, .dropbtn:focus {
  background-color: #005ba6;
}

.dropdown {
  position: relative;
  display: block;
}

.dropdown-content {
  display: none;
  position: absolute;
  background-color: #f1f1f1;
  min-width: 160px;
  /*overflow: auto;*/
  box-shadow: 0 8px 16px 0 rgba(0,0,0,0.2);
  z-index: 1;
  right: 0.5rem;
}

.dropdown-content a {
  color: black !important;
  padding: 1rem 1rem !important;
  text-decoration: none;
  display: block;
}

.dropdown a:hover {background-color: #ddd;}

.show {display: block;}
JustMe
  • 327
  • 1
  • 9
  • `overflow` of the header isn't it set to `hidden` ? This could cause such problem – Cedric Cholley Apr 24 '20 at 20:26
  • Header overflow indeed is hidden `#header { width: auto; height: auto; display: flex; justify-content: space-between; align-items: center; padding: 10px 40px; background: #417690; color: #ffc; overflow: hidden; } ` My code on top of this one to override some declarations: `#header { background: #FFF; -moz-box-shadow: 0 3px 3px 0 rgba(148,148,148,0.5); box-shadow: 0 3px 3px 0 rgba(148,148,148,0.5); padding: 0; display: grid; grid-template-columns: repeat(2, 1fr); grid-template-areas: "logo navbar"; }` – JustMe Apr 24 '20 at 20:28
  • By definition everything which overflown your header is hidden hence what you see. You need to make your design works with `overflow` set to `visible` – Cedric Cholley Apr 24 '20 at 20:32
  • @CedricCholley I've forced `overflow: visible` to #header but dropdown menu still stays hidden. What can I do in this case? Thanks! – JustMe Apr 24 '20 at 20:34
  • I made a snippet below, it seems to work – Cedric Cholley Apr 24 '20 at 20:50

3 Answers3

0

Dropdown content needs to be positioned absolutely, and have higher z-index that the content you want to display it over.

A codepen or the like would help make this easier to help with.

0

I've copy/pasted your code in the snippet below, commented overflow: hidden; from #header and it seems to work doesn't it ?

/* When the user clicks on the button,
        toggle between hiding and showing the dropdown content */
        function openDropdown() {
         const myDropdown = document.getElementById("myDropdown");
          const show = document.getElementById("myDropdown").classList.toggle("show");
          
          if(show){
           const {top, left, width} = myDropdown.getBoundingClientRect();
            myDropdownClone = myDropdown.cloneNode(true);
            myDropdownClone.style.width = `${width}px`;
            myDropdownClone.style.top = `${top}px`;
            myDropdownClone.style.left = `${left}px`;
            myDropdownClone.style.position = 'fixed';
            myDropdownClone.id = 'myDropdownClone';
            document.body.append(myDropdownClone);
          } else {
           document.getElementById("myDropdownClone").remove();
          }
          
        }
        // Close the dropdown if the user clicks outside of it
        window.onclick = function(event) {
          if (!event.target.closest('.dropbtn')) {
            let dropdowns = document.getElementsByClassName("dropdown-content");
            let i;
            for (i = 0; i < dropdowns.length; i++) {
              let openDropdown = dropdowns[i];
              if (openDropdown.classList.contains('show')) {
                openDropdown.classList.remove('show');
              }
            }
          }
        }
#header {
  width: auto;
  height: auto;
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px 40px;
  background: #417690;
  color: #ffc;
   /* overflow: hidden; */
   clip-path: polygon(5% 0%, 100% 0%, 100% 100%, 0% 100%);
}

#header {
  background: #FFF;
  -moz-box-shadow: 0 3px 3px 0 rgba(148, 148, 148, 0.5);
  box-shadow: 0 3px 3px 0 rgba(148, 148, 148, 0.5);
  padding: 0;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  grid-template-areas: "logo navbar";
}

.dropbtn {
  background-color: #0071ce;
  color: white;
  /*padding: 16px;*/
  font-size: 16px;
  border: none;
  cursor: pointer;
}

.dropbtn:hover, .dropbtn:focus {
  background-color: #005ba6;
}

.dropdown {
  position: relative;
  display: block;
}

.dropdown-content {
  display: none;
  position: absolute;
  background-color: #f1f1f1;
  min-width: 160px;
  /*overflow: auto;*/
  box-shadow: 0 8px 16px 0 rgba(0,0,0,0.2);
  z-index: 1;
  right: 0.5rem;
}

.dropdown-content a {
  color: black !important;
  padding: 1rem 1rem !important;
  text-decoration: none;
  display: block;
}

.dropdown a:hover {background-color: #ddd;}

.show {display: block;}
<div id="header">
  <div id="branding">

  </div>

  <div id="user-tools">

    <strong>My name</strong>.

    <a href="#">View site</a>
    <a href="#">trans Documentation</a> /

    <div class="dropdown">
      <button onclick="openDropdown()" class="dropbtn"><img src="" alt="User Menu" style="height: 30px;"></button>
      <div id="myDropdown" class="dropdown-content">

        <a href="#">Change password</a> /
        <a href="#">Log out</a>
      </div>
    </div>
  </div>
</div>

[EDIT] I've edited the code snippet to take under account the clip-path: polygon(5% 0%, 100% 0%, 100% 100%, 0% 100%); mentioned in the comments

Cedric Cholley
  • 1,956
  • 2
  • 9
  • 15
  • I'm just trying this in a codepen and indeed it works with `overflow: visible` I've applied solution to the page and I still have the problem described. Why? https://codepen.io/alexandru-h/pen/RwWpyME – JustMe Apr 24 '20 at 21:05
  • Is the header is itself in a "wrapper" with `overflow: hidden`? – Cedric Cholley Apr 24 '20 at 21:07
  • No, there isn't a wrapper but I found out what's the problem. I have a `clip-path: polygon(5% 0%, 100% 0%, 100% 100%, 0% 100%);` which hides the dropdown. How can I keep it and show the dropdown? – JustMe Apr 24 '20 at 21:15
  • First thing which pops into my mind (there may be other solutions), once the dropdown is opened (click event) you... 1. find its position in the viewport (.getBoundingClientRect())[https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect] 2. move the the element outside the header, you can append it to the body (or use a clone of the element) 3. set `position: fixed` to this element with `top` and `left` from point 1. of course once the button is click again, you need to append the element back to its original place – Cedric Cholley Apr 24 '20 at 21:28
  • I've edited the answer to take under account the `clip-path: polygon(5% 0%, 100% 0%, 100% 100%, 0% 100%);` you've mentioned – Cedric Cholley Apr 24 '20 at 21:53
  • @JustMe you may have to adapt you code to "close the dropdown if the user clicks outside of it" – Cedric Cholley Apr 24 '20 at 21:55
0

The best solution found for a drodown inside a container with a clip-path is to add an additional div just like in the solution found here: How to place dropdown div over clip-path?

JustMe
  • 327
  • 1
  • 9