Seems when I pass a node to ResizeObserver.observe() on DOMContentLoaded event, it invokes immediately. Is it considered a normal behavior?
Yes, this behavior is per spec. They do have this note:
Observation will fire when watched Element is inserted/removed from DOM.
Observation will fire when watched Element display gets set to none.
Observations do not fire for non-replaced inline Elements.
Observations will not be triggered by CSS transforms.
Observation will fire when observation starts if Element is being rendered, and Element’s size is not 0,0.
So in your case, either the element was not yet in the DOM and case 1 will make it fire, either it was already, and case 5 will (though in `DOMContentLoaded, that should be 5 ;).
But following the actual normative specs it appears that in any case the observation should fire initially. We can note that Chrome did quite recently change their behavior to do exactly this in CRBUG 1128016, since prior to that change they did not initially fire on hidden elements.