52

I want to get the height of a div in order to make the height of another div matching it. I used the method clientHeight, but It doesn't return me the good value (smaller value). Actually, It seems to return a height before all elements are charged. After some research online, I tried to put a window.load() to delay until everything is charged but it doesn't work as well. Some ideas ?

mounted () {
  this.matchHeight()
},
matchHeight () {
  let height = document.getElementById('info-box').clientHeight
}
<div class="columns">
  <div class="left-column" id="context">
  <p>Some text</p>
  </div>
  <div class="right-column" id="info-box">
    <img />
    <ul>
      some list
    </ul>
  </div>
</div>
Mayank Kumar Chaudhari
  • 16,027
  • 10
  • 55
  • 122
Juliane Blier
  • 597
  • 1
  • 6
  • 9
  • https://stackoverflow.com/a/526352/2316112 – Philipp Sander Jul 06 '17 at 12:22
  • 3
    Can you create a reproduction? It seems to work fine: https://jsfiddle.net/wostex/63t082p2/84/ (if you return height from your method of course, because in your code you return nothing). – Egor Stambakio Jul 06 '17 at 12:26
  • Actually my component has lots of lines and methods. I simplified it here. But I don't understand why it returns a number smaller than the actual height (when inspecting the element). Is it a loading problem ? Shouldn't mounted run the method when everything is loaded ? – Juliane Blier Jul 06 '17 at 12:56
  • If it works find in the simple case but not in the case with lots more code then it's very possible that some of the other code is running late in the load process and modifying the DOM in such a way as to change the height. If that's the case, then you need to call your matchHeight method even later in the load process after the DOM modifying code has executed. – RonC Jul 06 '17 at 13:23
  • But mounted is the last step just at the moment where the component is loaded, no ? There is no modification after rendering. It is just display – Juliane Blier Jul 06 '17 at 14:23
  • by the way this is easily achievable with css flex – valerio0999 Mar 15 '19 at 13:38
  • We need to get various heights on load so we can dynamically run stuff and adjust it later on - how to get heights of child components from top-level component? Did not find a way yet ... – trainoasis Apr 09 '21 at 12:12
  • img load is even after mounted, which may change size of img element. – Liang Yan Jun 13 '22 at 08:40

5 Answers5

73

The way you are doing it is fine. But there is another vue specific way via a ref attribute.

 mounted () {
   this.matchHeight()
 },
 matchHeight () {
   let height = this.$refs.infoBox.clientHeight;
 }

    <div class="columns">
        <div class="left-column" id="context">
            <p>Some text</p>
        </div>
        <div class="right-column" id="info-box" ref="infoBox"></>
            <img />
            <ul>
                some list
            </ul>
        </div>
    </div>

In this case, since you are just getting the value it really doesn't matter whether you use your original getElementById approach or the vue specific ref approach. However if you were setting the value on the element then it's much better to use the ref approach so that vue understands that the value has changed and won't possibly overwrite the value with the original value if it needs to update that node in the DOM.

You can learn more here: https://v2.vuejs.org/v2/api/#vm-refs

Update

A few people had left comments that the above solution didn't work for them. That solution provided the concepts but not full working code as example, so I have augmented my answer with the code below which demonstrates the concepts.

var app = new Vue({
    el: '#app',
    data: function () {
        return {
            leftColStyles: { },
            lines: ['one', 'two','three']
        }
    },
    methods: {
        matchHeight() {
            var heightString = this.$refs.infoBox.clientHeight + 'px';
            Vue.set(this.leftColStyles, 'height', heightString); 
        }
    },
    mounted() {
        this.matchHeight();
    }

});
.columns{width:300px}
.left-column {float:left; width:200px; border:solid 1px black}
.right-column {float:right; border:solid 1px blue; }
<div id="app">
    <div class="columns">
        <div class="left-column" id="context" v-bind:style="leftColStyles">
            <p>Some text</p>
        </div>
        <div class="right-column" id="info-box" ref="infoBox"> 
            <img />
            <ul>
                <li v-for="line in lines" v-text="line"></li>
            </ul>
        </div>
    </div>

</div>

 <script src="https://unpkg.com/vue@2.6.12/dist/vue.min.js"></script>
 

Here is a screenshot of the results in the browser:

enter image description here

Note:
My answer assumes that you are loading vue.js from a cdn or locally into the browser and executing it there. If instead you are running your code via the cli and my answer is not working for you, please see @mayank1513's answer instead.

tony19
  • 125,647
  • 18
  • 229
  • 307
RonC
  • 31,330
  • 19
  • 94
  • 139
  • Thanks, I tried your solution but same problem. I noticed the div containing the list is not taken into account. It only return the height with the image. But the list has a v-if="someVariable", it seems to be the reason, no ? – Juliane Blier Jul 06 '17 at 13:12
  • Whats the problem? – RonC Jul 06 '17 at 13:14
  • That the list is not taken into account. As if it wasn't displayed, but it is. – Juliane Blier Jul 06 '17 at 13:46
  • Is the list generated server side or client side (for example with a v-for)? – RonC Jul 06 '17 at 16:11
  • This does not work for my navbar. The `mounted()` height is 49 px. But when I inspect the height in the dom its 110. obviously after everything is loaded. This project only has vue. no other js or nothing else happening on the component or any other component, so clearly `mounted()` does not run after everything has been built. – christopher clark Nov 14 '17 at 17:28
  • @christopherclark - I probably should have left a comment letting you know that because of your comment I updated my answer to include full working code. – RonC Dec 05 '17 at 14:13
  • 1
    @gman, why did you change my code from a fully working example to three snipits? Only thing really changed is the order the code is presented and the `html` `head` and `body` tags. Seems like the edited version is less useful to people then the original code I provided. Given your reputation, no doubt you had a positive purpose in mind in making the changes... – RonC Feb 01 '18 at 16:32
  • @McWayWeb I approved your edit to add $el but then when I clicked the "Run code snipit" button in the answer it produces this error "Cannot read property 'clientHeight' of undefined". So I'm reverting the edit. – RonC Oct 17 '20 at 13:46
  • How can you access refs of child components? – trainoasis Apr 09 '21 at 12:10
  • @trainoasis - That's a great question which should be asked as it's own StackOverflow questions. – RonC Apr 09 '21 at 12:14
22

Took a lot of time ⌚ resolving the issue. Initially I tried to follow answer by Ron C. Trying to get this.$refs.infoBox.clientHeight; just didn't work - it gave undefined.

Then I explored the this.$refs.infoBox object.

Wow!!! I don't know how the code he wrote works for him and all others, but there wasn't any property called clientHeight. Finally got it inside $el.

so we need to replace this.$refs.infoBox.clientHeight; with this.$refs.infoBox.$el.clientHeight;

This just worked well for me.

Update

While using nuxt this.$refs.infoBox.$el.clientHeight; didn't work. but Ron C's answer works for this case. this.$refs.infoBox.$el.clientHeight; seems to work while using @vue/cli

RonC
  • 31,330
  • 19
  • 94
  • 139
Mayank Kumar Chaudhari
  • 16,027
  • 10
  • 55
  • 122
  • 1
    What you are seeing is very interesting and baffling to me. McWayWeb recently proposed a change to my answer to add in the $el in the way you suggest. I initially approved that edit but then it broke my answer so that the "Run code snipit" button produces this error "Cannot read property 'clientHeight' of undefined". So I reverted the edit, and it now works again. I really curious, when you click the "Run code snipit" button in my answer, does it run without error and are the two boxes the same height? – RonC Oct 17 '20 at 13:59
  • I run it on my machine with the latest vue and vue-cli – Mayank Kumar Chaudhari Oct 17 '20 at 14:08
  • Very interesting. I just updated my answer to use the latest version of vue, 2.6.12, it was using 2.2.5, and the answer still works when you click the "Run code snipit" button. So maybe there is a difference between running the code via the cli vs in the browser? Pretty odd. – RonC Oct 17 '20 at 14:46
  • Please try with vue cli 4.0+. I needed answer that works for my website and I mentioned what worked for me and what did not. I don't know how it works on this snippet. To be specific I was using firefox browser developer tools and vue devtools as well – Mayank Kumar Chaudhari Oct 17 '20 at 16:08
  • 1
    I wasn't being critical. Just trying to understand. I don't use the cli, in my case I load vue as a js file from a cdn and it runs in the browser. May takeaway from this is that your answer is the one people need if using the cli and my answer is the one they need if loading vue as a js file from a cdn or locally. It's good to have both answers here. – RonC Oct 17 '20 at 16:12
  • May be. Will try to verify that and update my answer once I get enough time. Thanks for the discussion. – Mayank Kumar Chaudhari Oct 17 '20 at 16:14
  • No need, I think the comments here and the two answers will lead people to the one that will work for them. – RonC Oct 17 '20 at 16:15
  • 1
    It shouldn't have anything to do with vue-cli, but with where you add the ref to. Is it a Vue component, then the ref points to the component itself, which has an $el property. If the ref is placed on a regular HTML tag, then there is no Vue component, so the ref points directly to the HTML element. – shabushabu Feb 06 '21 at 22:23
5

I would use flexbox to achieve equal height columns https://css-tricks.com/snippets/css/a-guide-to-flexbox/

.container {
   display: flex;
}
.column {
   border: 1px solid;
   padding: 20px;
   width: 150px;
}
<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>

<body>
    <div class="container">
        <div class="column">
            Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer ac dui sed erat venenatis fermentum. Nulla tempus, magna
            sit amet ornare fringilla, ligula quam faucibus urna
        </div>
        <div class="column">
            Lorem ipsum dolor sit amet, consectetur adipiscing elit.
        </div>
    </div>
</body>
</html>
Cata John
  • 1,371
  • 11
  • 19
drimbo
  • 59
  • 1
  • 1
0

FYI - had the issue accessing $el as well (had undefined). With vue/typescript - the following worked ok:

console.log('scriptPanel: mounted: sizes: ', (this.$refs.scriptSheet! as any).$el.clientHeight)
Suraj Rao
  • 29,388
  • 11
  • 94
  • 103
0

In my Case it found clientHeight as per below path

this.$refs.infoBox.$el.nextElementSibling.clientHeight

Prakash Rajotiya
  • 1,013
  • 5
  • 11