How do you find the dimensions of a “display: none” element?

后端 未结 6 827
轻奢々
轻奢々 2021-02-13 18:58

I have some child elements inside a div that gets the CSS display: none applied to it and I want to find out what the child element dimensions are. How can I do thi

相关标签:
6条回答
  • 2021-02-13 19:17

    I use a method that for some reasons work but, funny thing, I can't properly explain why. Basically, in my use case, I need to know the height of tabs in order to toggle them smoothly in vanilla js.

    To calculate the height, I do the following steps in javascript:

    1. Element is displayed but with "height:0px" and "overflow:hidden" (alternative to "display: none")
    2. Set the element to "height:auto"
    3. Calculate the height of the element with offsetHeight property
    4. Set back the element to "height:0px"
    5. Set the calculated height to the element inside a setTimeout, in combination with a css transition for smoother transition

    I expected the animation to flicker but it does not. It blows my mind to be able to do this since it's probably the most simple solution here, but feel free to share your ideas if you understand why it works and if you see any drawbacks doing this.

      function toggleTabs() {
        let tabs = document.querySelectorAll('.accordionX a span')
        tabs.forEach(tab => {
          tab.addEventListener('click', function(e) {
            tab.classList.toggle('active')
            if (tab.classList.contains('active')) {
              //hide other tabs
              tabs.forEach(tab => {
                if (tab != e.target) {
                  tab.classList.remove('active');
                  tab.parentElement.nextElementSibling.style.height = '0px';
                }
              })
              var tabContent = tab.parentElement.nextElementSibling;
              tabContent.style.height = 'auto';
              var tabHeight = tabContent.offsetHeight + 'px'
              tabContent.style.height = '0px';
              setTimeout(function() {tabContent.style.height = tabHeight}, 15)
            } else {
              tab.classList.remove('active');
              tab.parentElement.nextElementSibling.style.height = '0px';
            }
          })
        })
      } toggleTabs();
    .accordionX{margin:0px 20px}
    .accordionX > li{border-bottom:1px solid #e7e7e7;position:relative;list-style-type:none}
    .accordionX > li:first-child{border-top:1px solid #e7e7e7}
    .accordionX > li a::after{display:none}
    .accordionX > li p{color:#3c3c3b;line-height:1.8;text-align:left}
    .accordionX > li > a span{position:relative;color:#3c3c3b;padding-right:5%;display:block;cursor:pointer;font-weight:600;line-height:3;text-indent:15px;user-select:none;-webkit-tap-highlight-color:transparent;border:none!important}
    .accordionX > li > a span:after{width:8px;height:8px;border-right:1px solid #3c3c3b;border-bottom:1px solid #3c3c3b;position:absolute;right:18px;top:25px;content:" ";top:50%;transform:translate(0,-50%) rotate(-45deg);-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;transition:all .2s ease-in-out}
    .accordionX > li > a span > img {vertical-align: middle;margin-right: 10px;}
    .accordionX p{font-size:1em;padding:10px 15px 0}
    .accordionX > li > a span.active:after{transform:translate(0,-75%) rotate(45deg);-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;transition:all .2s ease-in-out}
    .accordionX .in-accordion{box-sizing:content-box;overflow:hidden;height:0px;transition:height .4s ease 0.1s}
    .accordionX .in-accordion li {list-style: disc;list-style-position: inside;}
    .accordionX .in-accordion p:last-child{padding-bottom:20px}
    <ul class="accordionX">
        <li>
            <a id="tab1">
                <span>TAB 1</span>
            </a>
            <div class="in-accordion" style="height: 0px;">
                <p>
                    Lorem ipsum dolor sit amet consectetur adipiscing elit placerat vestibulum at, leo torquent arcu tortor lectus gravida commodo neque elementum, semper posuere libero tincidunt velit vulputate morbi iaculis lacinia.
                </p>
            </div>
        </li>
    
        <li>
            <a id="tab2">
                <span>TAB 2</span>
            </a>
            <div class="in-accordion" style="height: 0px;">
                <p>
                    Lorem ipsum dolor sit amet consectetur adipiscing elit placerat vestibulum at, leo torquent arcu tortor lectus gravida commodo neque elementum, semper posuere libero tincidunt velit vulputate morbi iaculis lacinia. Lorem ipsum dolor sit
                    amet consectetur adipiscing elit placerat vestibulum at, leo torquent arcu tortor lectus gravida commodo neque elementum, semper posuere libero tincidunt velit vulputate morbi iaculis lacinia. Lorem ipsum dolor sit amet
                    consectetur adipiscing elit placerat vestibulum at, leo torquent arcu tortor lectus gravida commodo neque elementum, semper posuere libero tincidunt velit vulputate morbi iaculis lacinia.
                </p>
            </div>
        </li>
    </ul>

    0 讨论(0)
  • 2021-02-13 19:24

    Use window.getComputedStyle()

    var o = document.getElementById('output');
    var wmd1 = document.getElementById('whats-my-dims1');
    var wmd2 = document.getElementById('whats-my-dims2');
    o.innerHTML = 'wmd1: "' + window.getComputedStyle(wmd1).getPropertyValue("width") 
    + '", "' 
    + window.getComputedStyle(wmd1).getPropertyValue("height") 
    + '", wmd2: "' 
    + window.getComputedStyle(wmd2).getPropertyValue("width") + '", "' 
    + window.getComputedStyle(wmd2).getPropertyValue("height") + '"';
    #some-hidden-div{
      display: none;
    }
    .whats-my-dims{
      display:block;
      width: 69px;
      height: 42px;
      background-color: #f00;
    }
    <div id='output'>
      Processing... :p
    </div>
    <div>
      Sooo... How do I get the width and height of whats-my-dims1?
    </div>
    <div id='some-hidden-div'>
      <div class='whats-my-dims' id='whats-my-dims1'></div>
    </div>
    <div class='whats-my-dims' id='whats-my-dims2'></div>

    jsfiddle https://jsfiddle.net/h9b17vyk/3/

    0 讨论(0)
  • 2021-02-13 19:31

    You cannot find the dimensions of an element with display: none but you can turn on the display, get the dimensions and then set it back to hidden. This wouldn't cause any visual differences.

    var o = document.getElementById('output');
    var wmd1 = document.getElementById('whats-my-dims1');
    var someHiddenDiv = document.querySelector('#some-hidden-div');
    someHiddenDiv.style.display = 'block';
    var wmd2 = document.getElementById('whats-my-dims2');
    o.innerHTML = 'wmd1: "' + wmd1.clientWidth + '", "' + wmd1.clientHeight + '", wmd2: "' + wmd2.clientWidth + '", "' + wmd2.clientHeight + '"';
    someHiddenDiv.style.display = 'none';
    #some-hidden-div {
      display: none;
    }
    .whats-my-dims {
      width: 75px;
      height: 42px;
      background-color: #f00;
    }
    <div id='output'>
      Processing... :p
    </div>
    <div>
      Sooo... How do I get the width and height of whats-my-dims1?
    </div>
    <div id='some-hidden-div'>
      <div class='whats-my-dims' id='whats-my-dims1'></div>
    </div>
    <div class='whats-my-dims' id='whats-my-dims2'></div>


    Note that in some cases setting the display: none back with inline styles might cause unnecessary trouble (because inline styles take precedence over CSS selectors unless they have !important). In such cases you might want to remove the style attribute itself totally.

    In the below snippet, you would see that the addition of .show class has no effect because the inline display: none is taking precedence.

    var o = document.getElementById('output');
    var wmd1 = document.getElementById('whats-my-dims1');
    var someHiddenDiv = document.querySelector('#some-hidden-div');
    someHiddenDiv.style.display = 'block';
    var wmd2 = document.getElementById('whats-my-dims2');
    o.innerHTML = 'wmd1: "' + wmd1.clientWidth + '", "' + wmd1.clientHeight + '", wmd2: "' + wmd2.clientWidth + '", "' + wmd2.clientHeight + '"';
    someHiddenDiv.style.display = 'none';
    
    
    var btn = document.querySelector('#show');
    
    btn.addEventListener('click', function() {
      someHiddenDiv.classList.add('show');
    });
    #some-hidden-div {
      display: none;
    }
    .whats-my-dims {
      width: 75px;
      height: 42px;
      background-color: #f00;
    }
    #some-hidden-div.show {
      display: block;
    }
    <div id='output'>
      Processing... :p
    </div>
    <div>
      Sooo... How do I get the width and height of whats-my-dims1?
    </div>
    <div id='some-hidden-div'>
      <div class='whats-my-dims' id='whats-my-dims1'>Some text</div>
    </div>
    <div class='whats-my-dims' id='whats-my-dims2'></div>
    
    <button id='show'>Show the hidden div</button>

    whereas in the below snippet, it doesn't cause any problem because the inline style is totally removed.

    var o = document.getElementById('output');
    var wmd1 = document.getElementById('whats-my-dims1');
    var someHiddenDiv = document.querySelector('#some-hidden-div');
    someHiddenDiv.style.display = 'block';
    var wmd2 = document.getElementById('whats-my-dims2');
    o.innerHTML = 'wmd1: "' + wmd1.clientWidth + '", "' + wmd1.clientHeight + '", wmd2: "' + wmd2.clientWidth + '", "' + wmd2.clientHeight + '"';
    someHiddenDiv.style = null;
    
    
    var btn = document.querySelector('#show');
    
    btn.addEventListener('click', function() {
      someHiddenDiv.classList.add('show');
    });
    #some-hidden-div {
      display: none;
    }
    .whats-my-dims {
      width: 75px;
      height: 42px;
      background-color: #f00;
    }
    #some-hidden-div.show {
      display: block;
    }
    <div id='output'>
      Processing... :p
    </div>
    <div>
      Sooo... How do I get the width and height of whats-my-dims1?
    </div>
    <div id='some-hidden-div'>
      <div class='whats-my-dims' id='whats-my-dims1'>Some text</div>
    </div>
    <div class='whats-my-dims' id='whats-my-dims2'></div>
    
    <button id='show'>Show the hidden div</button>

    0 讨论(0)
  • 2021-02-13 19:36

    You can't get dimensions of an element with display: none, because since it's hidden, it doesn't take any space, so it has no dimensions. The same apply to its children.

    You can instead make the element visible for a while, check the child dimensions and make the element invisible back. As pointed by @JanDvorak:

    Browsers don't repaint while synchronous Javascript is running, so the element should never appear on-screen.

    Example code:

    var o = document.getElementById('output');
    var wmd1 = document.getElementById('whats-my-dims1');
    var wmd2 = document.getElementById('whats-my-dims2');
    var hiddenDiv = document.getElementById("some-hidden-div");
    hiddenDiv.style.display = "block";
    o.innerHTML = 'wmd1: "' + wmd1.clientWidth + '", "' + wmd1.clientHeight + '", wmd2: "' + wmd2.clientWidth + '", "' + wmd2.clientHeight + '"';
    hiddenDiv.style.display = "";
    

    See demo on JS Fiddle.

    0 讨论(0)
  • 2021-02-13 19:37

    For someone who need this to implement a context menu or hint window:

    The getComputedStyle() isn't seem to work on elements that have dynamic width/height. All you get is auto.

    My approach was to set visibility: hidden and setting display other than none (what would required to show your element).

    I used this 3 step method in a context menu component for calculating where to place the menu relative to the click position to always be on-screen:

    1. set visibility: hidden and remove display: none (set to what it will be when the menu finally shown)
    2. get the dimensions
    3. remove visibility: hidden

    It will probably still not work when the parent also has display: none but that wasn't an issue for this use case as one can not (should not) access a context menu of an object that is not shown anyway.

    0 讨论(0)
  • 2021-02-13 19:41

    You can add this :

    var wmd1Style = window.getComputedStyle(wmd1);
    o.innerHTML = 'wmd1: "' + parseInt(wmd1Style['width'], 10) + '", "' + parseInt(wmd1Style['height'], 10) + '", wmd2: "' + wmd2.clientWidth + '", "' + wmd2.clientHeight + '"';
    
    0 讨论(0)
提交回复
热议问题