Comments (23)
I extended the .closed class by adding height: 0 and overflow: hidden and that looks much better.
from accordion.
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.
That worked great! Thanks.
from accordion.
It depends. What sort of content are you loading? Simple images?
from accordion.
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.
Geweldig! 😀 Let me know if you have any other questions or issues.
from accordion.
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.
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.
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.
from accordion.
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.
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.
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.
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.
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.
Bedankt! Laat zien dan...
Give me a moment to dig through this.
from accordion.
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.
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.
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.
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.
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.
It adds a nice personal touch to helpdesk issues :)
All the accordions are having the issue.
from accordion.
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.
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)
- Rewrite code in ECMAScript 6 HOT 2
- Update height if contents change HOT 6
- Enter and spacebar to open/close accordion item HOT 22
- README - bundled demos link broken HOT 1
- Where is demo? HOT 5
- Deep linking HOT 6
- No easy way to add/remove folds after construction HOT 3
- Anyway to access the click event? HOT 2
- Responsive heightOffset HOT 3
- Height not updating when closing an accordion nested in another
- Feature: Only open one accordion at a time, collapse others? HOT 3
- Incorrect heights set for nested accordions with pre-opened folds
- Borders aren't considered when calculating fold heights HOT 1
- To-do list
- Option to allow only one fold to be open at a time HOT 3
- Strange type rendering issue with Chrome 55 / Mac 10.10.5 HOT 14
- Doesn't work on IE HOT 11
- Great Plugin HOT 3
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from accordion.