Ich vermute, dass du die Klassenzuweisung und das Auslesen der Abmessungen nicht in einem Run-To-Completion-Codeblock ausführst, sondern verteilt über asynchrone Funktionsaufrufe hinweg.
Du weißt doch, dass ich JS Laie bin - wirf' mir doch bitte nicht solche "Fachbegriffe" an den Kopf! ;-)
Ein Run-To-Completion-Codeblock ist eine Einheit Code, die garantiert bis zu Ende ausgeführt wird und nicht von asynchronen Aufrufen (Klicks, AJAX-Anfragen, Timeouts, etc) unterbrochen werden kann.
Ursprünglich wollte ich das schlicht in meiner $(document).ready(function(){}) machen.
Das ist zum Beispiel ein asyncrhoner Task, man muss also auf die Ausführungsreihenfolge achten:
var i = 0;
$(document).ready(function(){
console.log(i++);
});
console.log(i++);
setTimeout() wird hier also nicht den gewünschten Effekt haben (zumindest kann man sich darauf nicht verlassen). Das Positive daran ist, dass man setTimeout gar nicht benötigte, wie gesagt, findet der Reflow blockierend und unmittelbar in Folge der DOM-Manipulation statt, es ist möglich mit der nächsten Anweisung sofort die neuen Abmessungen auszulesen.
Das halte ich bis zum Beweis des Gegenteils erstmal für ein Gerücht ...! ;-)
Du hast schon das "jQuery" im Betreff gelesen? :-P
Klar, aber für jQuery gelten die selben Regeln, die für Vanilla-JavaScript auch gelten. Es könnte natürlich sein, dass jQuery aus Perfomance-Gründen versucht den Reflow weg zu optimieren, dafür wäre es notwendig, die Klasse in einem asynchronen Task zu vergeben, das ginge zum Beispiel mit setImmediate() oder requestAnimationFrame(). Diese These lässt sich aber durch einen weiteren Test falsifizieren:
http://jsfiddle.net/s9h6g2tt/
Aber nun gut, das tut der Sache ja keinen Abbruch. Aber den Umstand, dass ich ja extra geschrieben habe, dass dann ein Multi-Column Style auf das Element angewendet wird, könnte doch von Bedeutung für das "Problem/ Phänomen" sein, oder nicht?
Für den JavaScript-Teil in deiner Frage ist das irrelevant, der Reflow findet statt, weil eine HTML-Klasse vergeben wird. Welche CSS-Regeln nun konkret angewendet werden müssen, entscheidet sich während des Reflows und kann nicht auf magische Weise vom Browser voraus geahnt werden.
Allerdings ist die Information hier trotzdem nicht vollkommen unnütz, denn vielleicht ergibt sich die Möglichkeit eine Lösung ohne JavaScript zu finden.
lass uns das hier im öffentlichen Raum machen, so können auch andere davon profitieren. Niemand erwartet von dir, dass du deinen gesamten Code publik machst, es genügt ein reduziertes Beispiel, an dem wir das von dir beobachtete Verhalten, reproduzieren können.
Reduziertes Beispiel ist immer so eine Sache ..., wenn bei der Reduktion auch das "Problem" verschwindet.
Das ist doch auch schon mal was, dann weißt du zumindest schon mal, in welchem Teil des Codes der Fehler nicht steckt.
Und es ist ein Teil in einem etwas umfangreicheren Layout, das u.a. (in dem relevanten Teil) Flexbox Elemente, absolut positionierte Elemente und dann eben auch das Multi-Column Element enthält.
Ich denke, du kannst dir ungefähr vorstellen, dass ich da nicht mal eben ein entsprechendes Beispiel erstellen kann.
Gibt es denn wenigstens eine Live-Seite, an der wir dein Problem beobachten können?
In meiner "Ahnungslosigkeit habe ich das halt so versucht:
var scrollParent = $('#outer');
var scrollElement = $('#inner');
var baseHeight = scrollParent.prop('clientHeight');
var scrolledHeight = scrollElement.prop('scrollHeight');
var baseWidth = scrollElement.width();
if(scrolledHeight > baseHeight) {
scrollParent.addClass('scroll');
var scrolledWidth = scrollElement.prop('scrollWidth');
console.log("baseWidth: " + baseWidth);
console.log("scrolledWidth: " + scrolledWidth);
}
scrolledWidth liefert dann zwar einen anderen Wert als baseWidth, ist aber nicht die tatsächliche Breite des Elements.
Du vergleichst hier Eigenschaften, die du unterschiedlich gemessen hast. Bei der deiner ersten Messung greifst du auf .width() zu, bei deiner zweiten Messung auf .prop('scrollWidth'). Dass diese sich unterscheiden, ist nicht weiter verwunderlich. Du solltest zunächst in Erfahrung bringen, welche Messgröße für dich interessant ist. Ansonsten vergleichst du sprichwörtlich Äpfel mit Birnen.
Diese erhalte ich (zuverlässig) erst, wenn ich es in eine externe Funktion auslagere, und auch dann braucht es noch eine setTimeout() Funktion, damit es "funktioniert".
Nein, zuverlässig ist die Messung mit Sicherheit nicht, die Gründe dafür habe ich ja schon erklärt. Es sind zufällig die erwarteten Messwerte, weil kein anderer asynchroner Task dazwischen funkt. Sogesehen ist dieser Workaround eine tickende Zeitbombe. Der nächste Klick vom Nutzer, die nächste Ajax-Abfrage oder die nächste Code-Änderung wird hier zu unerwartetem Verhalten führen.