3

I'm trying to use a MutationObserver to observe when a span changes height (when the text inside of the span changes size). But no mutations seem to be raised, even though inspecting the span's offsetHeight property does show a change. Are property changes not observed?

let mutationobserverconfig = {
  attributes: true,
  childList: true,
  subtree: true
}; 

function onmutation(mutations) {

  for (let mutation of mutations) {
    log("resizemutationobserver");
    // for
  }

  // onmutation
}

let resizemutationobserver;

function addresizemutationobserver(element, callback) {

// callback is in the module using this function


  resizemutationobserver = new MutationObserver(onmutation);
  let targetnode = $(element)[0];
  resizemutationobserver.observe(targetnode, mutationobserverconfig); //

}
Ted Fitzpatrick
  • 910
  • 1
  • 8
  • 18
  • 2
    I think you want ResizeObserver: https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver – Alex K Oct 04 '19 at 20:16
  • @AlexK Good suggestion. You might want to post that as an answer. – Emiel Zuurbier Oct 04 '19 at 20:18
  • I need to support IE 11 :-(. Caniuse shows ResizeObserver as not supported – Ted Fitzpatrick Oct 04 '19 at 20:24
  • @TedFitzpatrick how is the text in the span changing size? – Alex K Oct 04 '19 at 20:25
  • There are multiple ways: via css, also via a browser's font sizing controls. I'm using the detector for some responsive designs. I had a detector working fine until the newest mobile safari, so I thought I'd try something based on MutationObserver. – Ted Fitzpatrick Oct 04 '19 at 20:32
  • Mutation observers have a pretty niche use case and it has an unwieldy API. Don't use it unless you have to. Appending a resize event listener is more than enough for your needs – Andrew Oct 04 '19 at 20:38
  • @Andrew I thought resize event listener only applies to the body element? I'll need to try attaching it to the span. – Ted Fitzpatrick Oct 04 '19 at 20:43
  • @TedFitzpatrick Event listeners work on whatever you decide to append it to. – Andrew Oct 04 '19 at 20:44
  • Hmmm, I just tried $(testspan).on("resize",event=>{console.log('resize')}); No dice. I'll try pure vanilla js to attach the listener – Ted Fitzpatrick Oct 04 '19 at 20:52
  • @TedFitzpatrick Turns out I'm wrong. You can only append it to the window. I made the mistake in assuming that any html element can have any event listener appended to it. https://developer.mozilla.org/en-US/docs/Web/API/Window/resize_event – Andrew Oct 04 '19 at 20:58
  • Yeah window. I did try vanilla js just to try it. I half expected it to work in Chrome but no luck. I still have my crazy scientist hat on :-) Now I understand why NPM packages offering this functionality make use of requestanimationframe and lots of browser sniffing. – Ted Fitzpatrick Oct 04 '19 at 21:04
  • It depends on the technology you use, but if you can piggyback off of some type of update cycle (in React it would be `componentWillUpdate`), you can store the existing dimension and then compare it with the current – Andrew Oct 04 '19 at 21:15
  • Oooooo I love your thinking @Andrew gonna try React right now – Ted Fitzpatrick Oct 04 '19 at 21:39
  • My last comment about this question. React's componentWillUpdate is called on setState, so even with React I'd need to use polling. Anyways, thanks for the thoughts everyone – Ted Fitzpatrick Oct 04 '19 at 23:29
  • @TedFitzpatrick, inspect the code that's causing the change and see if it makes some other side effects which you can detect. – wOxxOm Oct 05 '19 at 06:34
  • @wOxxOm thanks for the idea. At this point, I'm re-examining what mobile Safari is actually doing with it's "aA" resize control. I did try a solution using IntersectionObserver and it worked, but not in mobile Safari. I'll comment here with a link to an answered question when I've developed a solution. – Ted Fitzpatrick Oct 08 '19 at 20:52
  • As promised, solution: https://stackoverflow.com/questions/58313462/does-ios-mobile-safari-provide-a-javascript-event-or-a-media-query-for-its-font/58329983#58329983 – Ted Fitzpatrick Oct 10 '19 at 19:36

2 Answers2

2

In this question it is important to differentiate between attribute and property. This is explained in this answer in detail.

The HTML elements have attributes, and some of them are reflected by properties of the corresponding DOM interface (node).

The interface has some additional properties (e.g. offsetHeight) which have no matching HTML attributes.

As the MutationObserver observes changes made to attributes, it won't monitor changes of offsetHeight.


To monitor changes of the size of an element, you can use a ResizeObserver instead (by now it has reached wide support).

FZs
  • 16,581
  • 13
  • 41
  • 50
1

ResizeObserver is the correct API to use, but if you have a span you'll need to set it to be an inline-block element :

span.some-text 
{
   display: inline-block
}

block would work too, but then it would just reflect the size of its parent container.

Simon_Weaver
  • 140,023
  • 84
  • 646
  • 689