Git Product home page Git Product logo

Comments (23)

TomDeSmet avatar TomDeSmet commented on June 3, 2024 2

I extended the .closed class by adding height: 0 and overflow: hidden and that looks much better.

from accordion.

Alhadis avatar Alhadis commented on June 3, 2024 1

It sounds like you're instantiating the Accordion on the document's load event, which happens when everything on the page has finished loading (scripts, images, stylesheets, etc). For a page with a heavy amount of assets, the flicker will be visible. I'd suggest using the DOMContentLoaded event instead, which fires once the page's source has been loaded into memory:

document.addEventListener("DOMContentLoaded", () => {
	new Accordion() // etc
});

Do you have a link to where the Accordion is being used?

from accordion.

TomDeSmet avatar TomDeSmet commented on June 3, 2024 1

That worked great! Thanks.

from accordion.

Alhadis avatar Alhadis commented on June 3, 2024

It depends. What sort of content are you loading? Simple images?

from accordion.

TomDeSmet avatar TomDeSmet commented on June 3, 2024

No, just a lot of text. But it takes a second or 2 to load and do its transforms. I now fade it in after a certain delay but I need to do a scrollToView also and it would be much more accurate when I know everything is in place and I can ditch the timeout.

from accordion.

Alhadis avatar Alhadis commented on June 3, 2024

Geweldig! 😀 Let me know if you have any other questions or issues.

from accordion.

TomDeSmet avatar TomDeSmet commented on June 3, 2024

I fear I was a bit too quick. I thought this solution worked, but I just noticed I can't click any of the items anymore, they don't fold open. But I don't get any error either.
The flash of unstyled content is gone, but the accordion just doesn't work anymore.

from accordion.

Alhadis avatar Alhadis commented on June 3, 2024

Could you post your source code or a link, please? There's a very broad range of factors to consider here, only a few of which are related to this component.

from accordion.

TomDeSmet avatar TomDeSmet commented on June 3, 2024

It's a whole lot of code in our build stack, but the reduced structure is this.
The only things that are being used are Flickety caroucel and vue-axios, vee-validate, etc.
But those have nothing to do with the accordion so I took them out for clarity. I'm pretty sure they don't interfere.

app-reduced.txt

from accordion.

Alhadis avatar Alhadis commented on June 3, 2024

Alright, the first thing that struck me was the potential race condition. A Promise's .then() method will run after the current thread has finished executing, possibly after the DOMContentLoaded event fires. In fact, the event may have already fired before the script executes.

You could try this instead, which executes .then(() => …) as soon as either of the two Promises has a chance to finish...

Promise.race([
	main(),
	new Promise(done => document.addEventListener("DOMContentLoaded", done),
]).then(

... but I don't recommend that, since I see you're using Vue. That complicates things.

UI libraries which use a virtual DOM for controlling page elements don't mix well with vanilla/pure JS. They tend to do weird things with page elements when rendering content… it's quite likely that Vue is interfering with the Accordion class's handles on page elements.

Long story short, you shouldn't be mixing two flavours of components this way. I recommend using either a Vue component or vanilla components (like this one), but not both.

I have no experience with Vue though, and I'm only going by my experience with React, so take my assumptions about Vue with a grain of salt.

from accordion.

TomDeSmet avatar TomDeSmet commented on June 3, 2024

Well, if it can help, I'm not using Vue to render everything and definitely not the page where I'm using the accordion.
Everything gets rendered using Twig (server side), I'm only using Vue as a replacement for JQuery on certain parts of the website.

from accordion.

Alhadis avatar Alhadis commented on June 3, 2024

BTW, here's a crude but useful hack for "snapshotting" the current physical state of the DOM:

copy(function(){
	const snapshots = new Map();
	for(const el of document.querySelectorAll("*"))
		snapshots.set(el, window.getComputedStyle(el).cssText);

	for(const [el, style] of snapshots)
		el.style.cssText = style;

	return document.documentElement.outerHTML
		.replace(/<\/?script(?=\s|>)/gi, "$&-dummy")
		.replace(/<style(?=\s|>)/gi, "$& disabled");
}());

That'll copy a gargantuan (~13-100 MBs) amount of HTML to your clipboard, which holds a static representation of each element's computed appearance. <style> and <script> elements are disabled to avoid altering the rendered snapshot when opening it locally.

Dump the results to a file named index.html. Gzip it and upload it to file.io (I predict it'll be too big to upload to GitHub). Send me the link and that might help me get a better picture of what's on your page, and how things are physically structured.

Note: This snippet won't capture the state of embedded content or the shadow DOM, but it'll work in a pinch for recording the state of a dynamically-generated DOM.

from accordion.

Alhadis avatar Alhadis commented on June 3, 2024

I'm only using Vue as a replacement for JQuery on certain parts of the website.

In that case, I recommend constructing the Accordion instances from within the Vue.app's initialiser function (assuming it has something similar to jQuery's $(document).ready function.

Because you're mixing page events with asynchronous code, predicting the order of either is a recipe for disaster. OTOH, it could also be something as simple as overlapping elements and unwanted styling. I'll figure it out better if I can see the rendered CSS/HTML to verify it isn't layout related.

from accordion.

TomDeSmet avatar TomDeSmet commented on June 3, 2024

I tried adding it to the mounted() function of my Vue instance, but that did the same.

You can check the page here: (link removed)
The flash of unstyled content is a bit more brief here, because the page has caching, but it's still noticeably there.

Thanks for your quick help so far btw!

from accordion.

Alhadis avatar Alhadis commented on June 3, 2024

Bedankt! Laat zien dan...

Give me a moment to dig through this.

from accordion.

Alhadis avatar Alhadis commented on June 3, 2024

Alright, there's over a megabyte of assets being loaded, both before and after the text (which is also long enough to cause a delay). The script containing the Accordion component is at the very bottom of the page, and is being loaded asynchronously (<script type="module"> may fire after the DOMContentReady event has been triggered, which makes my initial suggestion useless).

Without going into asset management and resource bundling, a solution might be to load the Accordion before the page (inside the <head>), and load it synchronously so it blocks the loading of the rest of the page. The delay this adds should be negligible of only the Accordion is loaded (obviously after minifying it). The benefit is that it enables you to instantiate an Accordion as soon as its elements are loaded into memory:

<div class="accordion"></div>
<script>
	new Accordion(document.currentScript. previousElementSibling);
</script>

This should solve the worst of the FOUC. It isn't an ideal solution, and it's normally the complete opposite of how scripts should be loaded (lazily and asynchronously, or at the end of the page), but for pages of non-trivial size like this, the hit to page loading time is next-to-nothing compared to the jarring FOUC. :)

Click here if you need IE support

Note: Internet Explorer doesn't support the document.currentScript property, so if IE support is necessary, change the above snippet to this instead:

<div class="accordion"></div>
<script>
	new Accordion(
		(document.currentScript || document.scripts[document.scripts.length - 1]).
		previousElementSibling
	);
</script>

Alternatively, adding this polyfill to the start of the document should work (haven't tested it though):

<!DOCTYPE html>
<html>
<script>
	"use strict";
	if(!("currentScript" in document))
		Object.defineProperty(Document.prototype, "currentScript", {
			configurable: true,
			enumerable: true,
			get: function(){
				var last = document.scripts.length - 1;
				return document.scripts[last];
			}
		});
</script>

from accordion.

TomDeSmet avatar TomDeSmet commented on June 3, 2024

The 1MB of assets was due to my purgecss not working correctly. Thanks for noticing :)

However, I don't understand what new Accordion(document.currentScript. previousElementSibling); does?

from accordion.

Alhadis avatar Alhadis commented on June 3, 2024

Putting that immediately after the accordion's closing HTML tag means the Accordion is created as soon as possible, which is ultimately all you can do to reduce FOUC. This isn't the Accordion's fault: any component will suffer from lengthy load times when their contents are above-the-fold.

I just noticed I can't click any of the items anymore, they don't fold open. But I don't get any error either.

I see your page is working fine now. Can you no longer reproduce the earlier error?

from accordion.

TomDeSmet avatar TomDeSmet commented on June 3, 2024

I can, I just put it back as it was because the client is viewing it and I purged my css and enabled caching + gzip compression to speed everything up.

from accordion.

Alhadis avatar Alhadis commented on June 3, 2024

Could you point out which of the accordions is having this problem? Or are they all broken?

Ik spreek twintig nederlandse woorden ofzo, so my ability to follow the page is a bit limited 😉

from accordion.

TomDeSmet avatar TomDeSmet commented on June 3, 2024

It adds a nice personal touch to helpdesk issues :)

All the accordions are having the issue.

from accordion.

Alhadis avatar Alhadis commented on June 3, 2024

Any specific pages? I'm confused that I'm not witnessing this on my end. 😕

Aanyyyway, better ditch my original solution about the DOMContentLoaded handler. I should've asked if you were loading scripts asynchronously before suggesting that... 😁

I'll see if there's a better way to fight that FOUC...

from accordion.

Alhadis avatar Alhadis commented on June 3, 2024

Try adding an initial class of closed to each accordion fold. I noticed the folds are visible at startup because height isn't being set to 0px (and an explicit height is needed for overflow: hidden to have any effect…).

The result is that each fold has an effective height of 0px on page-load, leaves unclipped content to overlap every each other fold. Not a good look…

from accordion.

Related Issues (19)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.