Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add spinner to be shown before content is completely rendered #590

Merged
merged 8 commits into from Jan 31, 2019

Conversation

marvinchin
Copy link
Contributor

What is the purpose of this pull request? (put "X" next to an item, remove the rest)

• [x] New feature

Resolves #484

What is the rationale for this request?

Time taken for the page to render causes flash of unstyled content. To avoid having the user see the partially rendered page, we instead show a spinner until content is ready.

What changes did you make? (Give an overview)

  • Added an overlay with a spinner to the generated page markup
  • Added method fadeOutSpinner to setup.js to remove the overlay when the page is done rendering
  • Updated the expected site generated to include the spinner markup and related assets

spinner 1
Example of spinner being shown (slow!)

Is there anything you'd like reviewers to focus on?

Testing instructions:

Load any page. The spinner should appear while the page is rendering, and fade out when the page is done rendering.

@marvinchin marvinchin changed the title Add spinner to be shown before content is mounted Add spinner to be shown before content is completely rendered Jan 16, 2019
Copy link
Member

@yamgent yamgent left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • This spinner is shown briefly on every page load - will this be annoying to the user?

A good way to lessen the annoyance to the user would be:

  • To show the spinner only after the loading has taken more than a second.
  • To not fade out when the loading is complete (i.e. remove the fading, regardless of how long it is loading).

Bootstrap already has their own spinner. Please use that one instead. Thanks!

background: white;
display: flex;
justify-content: center;
align-items: center;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Attributes should be listed in the alphabetical order.

asset/css/markbind.css Show resolved Hide resolved
@@ -33,10 +33,15 @@ function setupAnchors() {
});
}

function fadeOutSpinner() {
jQuery('#spinner-overlay').fadeOut(100);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As stated earlier, this should be .remove() rather than fade out, to make it more pleasant for the user to navigate.

src/Page.js Outdated

Page.prototype.insertSpinner = function (pageData) {
return `${pageData}\n${SPINNER_HTML}`;
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The addition of the spinner need not be done through code, because the HTML content is always going to be the same.

Please add the spinner directly inside page.ejs instead.

@damithc
Copy link
Contributor

damithc commented Jan 17, 2019

Thanks for tackling this issue @marvinchin

As @yamgent the current implementation somehow gives the impression that the website is 'slow'. The main factor is there is a blank page (and a spinner) shown for a while; other websites don't usually do that.

Although this solution was suggested by me, now I wonder if the current status quo (i.e., showing partial content) is actually better than the solution (w.r.t. user perception)? The main problem with the current status is that the partially rendered menus look ugly/broken. Is there a way to fix that instead so that the partial rendering doesn't look so bad?

@marvinchin
Copy link
Contributor Author

The main cause of the unstyled content appears to be waiting for the vue and vue-strap files to load. This delay is more prominent in dev environment as we aren't doing compression or caching (if this is where the original observation came from, this may be the reason). The delay doesn't seem too visible to me in production.

Users on a slow network might still face this problem. If this is a concern, we could take the approach suggested by @yamgent and show the spinner only if the assets have not been loaded after 1 second.

Happy to further discuss how else we can tackle this problem, or if we should handle it at all!

@damithc
Copy link
Contributor

damithc commented Jan 17, 2019

The delay doesn't seem too visible to me in production.

It depends on the site I think. e.g., this always show a broken page briefly when loading for the first time https://nus-cs2103-ay1819s2.github.io/cs2103-website/

@marvinchin
Copy link
Contributor Author

That's true, first loads might always face this issue as the scripts aren't cached locally yet.

Do you have any thoughts about showing the spinner only after loading for some time then? We should also hide the content until it is fully rendered. This should avoid the user seeing the unstyled content without showing the spinner unless loading is taking too long.

@damithc
Copy link
Contributor

damithc commented Jan 17, 2019

That's true, first loads might always face this issue as the scripts aren't cached locally yet.

Try viewing a different page using the Schedule dropdown of https://nus-cs2103-ay1819s2.github.io/cs2103-website/. The problem happens in every page.

@yamgent
Copy link
Member

yamgent commented Jan 17, 2019

The main problem with the current status is that the partially rendered menus look ugly/broken. Is there a way to fix that instead so that the partial rendering doesn't look so bad?

We can add temporary classes to the components, before vue-strap finishes loading and starts to replace the components with actual implementations.

In the case of a <navbar>, we can try to add Bootstrap navbar classes to it so that at least they are positioned correctly while vue-strap is loading:

$('navbar').addClass('navbar navbar-expand-md fixed-top');

@marvinchin
Copy link
Contributor Author

Do you think we should hide the content entirely until the required assets are done loading? Or is there some other way we should style them? Transitioning from temporary styles to the fully rendered styles may look strange otherwise.

On the note of reducing the time taken to fully render the page, I've taken a closer look at the CS2103 website, and it seems like rendering is blocked until siteData.json is loaded. The problem seems to be that we are loading images etc. before siteData.json. As the siteData.json is used only for search and is not user facing, we might be able to load it asynchronously to avoid it blocking the render.

@yamgent
Copy link
Member

yamgent commented Jan 18, 2019

Do you think we should hide the content entirely until the required assets are done loading? Or is there some other way we should style them? Transitioning from temporary styles to the fully rendered styles may look strange otherwise.

We can add on top of the styles I have mentioned with visibility: hidden; so that they stay hidden but the position of the content do not jump around too much.

I think it is fine to not hide the words, since the user will still be allowed to get a basic sense of the website's content, regardless of whether the style has finished rendering or not. When I visit websites, things that appear "hidden", only to show up later, are usually always ads. :P

@marvinchin
Copy link
Contributor Author

Noted, will make a separate PR for these changes! Thanks for the inputs! 🙂

@marvinchin marvinchin force-pushed the add-spinner branch 2 times, most recently from 0c191cd to 4c9afce Compare January 19, 2019 07:33
@marvinchin
Copy link
Contributor Author

Hi @yamgent @damithc I've made the changes requested. To summarise, we 1. hide content until it is ready to be rendered fully, and 2. show a spinner if rendering is not completed after 1 second.

Please do let me know if this behaviour is acceptable or if I should make any other changes!

<link rel="stylesheet" href="<%- asset.bootstrapVue %>">
<link rel="stylesheet" href="<%- asset.fontAwesome %>" >
<link rel="stylesheet" href="<%- asset.glyphicons %>" >
<link rel="stylesheet" href="<%- asset.highlight %>">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These should not be moved to the bottom:

  1. The convention is to put stylesheets at the head.
  2. Authors may need to override the stylesheets, and they currently do that by adding additional stylesheets in head. Moving it to the bottom prevents them from overriding the stylesheets.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason I moved them to the bottom is to reduce the time taken to start showing the spinner. Otherwise, we have to wait for the other much larger assets to load before the spinner is shown. On slower connections this delay can be several seconds.

If this issue is not a concern, I will remove these changes!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The main bottleneck of the loading process is vue-strap and bulky/embedded page content and assets (e.g. youtube videos). Stylesheets themselves are fine and do not usually take up most of the loading time.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will remove these changes!

<link rel="stylesheet" href="<%- asset.markbind %>">
<link rel="stylesheet" href="<%- asset.layoutStyle %>">
<% if (siteNav) { %><link rel="stylesheet" href="<%- asset.siteNavCss %>"><% } %>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment as previous

@marvinchin marvinchin force-pushed the add-spinner branch 2 times, most recently from 3355782 to d7f63cc Compare January 23, 2019 08:04
Copy link
Member

@yamgent yamgent left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My apologies, I missed this PR because I didn't realise that it has been updated.

@yamgent yamgent added this to the v1.17.1 milestone Jan 26, 2019
@marvinchin
Copy link
Contributor Author

Thanks for looking at it!

Also, just to update - @damithc wants to compare the difference in perceived load times between showing the spinner vs just showing the semi-rendered page. If showing the spinner makes the page load look slower, we may choose not include this feature. I'll keep you posted once he has decided whether or not to go ahead with this!

@yamgent yamgent removed this from the v1.17.1 milestone Jan 26, 2019
@marvinchin
Copy link
Contributor Author

@damithc has given the go ahead to include this.

Thanks everyone for looking at this!

@pyokagan
Copy link

Does this mean the website will "forever be loading" if Javascript is disabled?

Not sure how I feel about that, the SE-EDU website currently works without Javascript so it'll be sad if the learning resources page can't be viewed just because the reader has javascript disabled :-/

@marvinchin
Copy link
Contributor Author

@yamgent I believe we spoke about this and the decision was that we can assume our users use JavaScript. Do you think this use case is something we should account for?

If it is, we can modify the CSS and use some inline JavaScript to show this spinner only to users with JavaScript enabled.

@pyokagan
Copy link

pyokagan commented Jan 26, 2019

afaik usually server side rendering is used to deal with the FOUC problem.

(Notice how https://se-edu.github.io/learningresources/ doesn't have any FOUC 😛 ) Scratch that, it has FOUC now after the update. Go look at an archive or something.

@yamgent
Copy link
Member

yamgent commented Jan 26, 2019

Vue, a major framework used by MarkBind, is using JavaScript. Website visitors can be assumed to be using JavaScript.

If the concern is that users with JavaScript disabled do not know why the web page is blank, we can add a warning message on the overlay to ask the user to enable JavaScript.

@pyokagan
Copy link

No, the concern is that this unnecessarily handicaps MarkBind and prevents it from being used in websites that do not need any of the flashy Javascript-required features.

https://vuepress.vuejs.org/ doesn't need the reader to have Javascript, why should MarkBind?

@marvinchin
Copy link
Contributor Author

marvinchin commented Jan 26, 2019

If supporting users who have javascript disabled is a concern, we may also need to think about how to make the other parts of the site work without javascript (e.g. dropdowns and search). In the meantime, we could make the overlay and spinner visible only on browsers with javascript enabled to avoid having the page be entirely unusable for these users using the approach I suggested above. Alternatively, if we don't foresee this enhancement bringing much value to users we could just shelve it for now.

SSR might be a possible approach to avoid FOUC, but I think that may require further investigation on how to integrate it into MarkBind. However, I'm not sure where that lies in the current priorities for the 2.0 release.

Just my $0.02!

@yamgent
Copy link
Member

yamgent commented Jan 27, 2019

No, the concern is that this unnecessarily handicaps MarkBind and prevents it from being used in websites that do not need any of the flashy Javascript-required features.

Yes, you are right in that we can be more gentle to website that generally do not rely on dynamic content or dynamic features that MarkBind provides.

https://vuepress.vuejs.org/ doesn't need the reader to have Javascript, why should MarkBind?

Thanks for mentioning the vuepress project. I checked their project and I think their idea of using Vue as a server-side rendering, rather than client-side rendering, is pretty nice since it allows them to reduce their reliance on JavaScript to purely just dynamic features. This is certainty an idea we can consider exploring in the future, so that Vue and vue-strap no longer need to be bundled together with MarkBind websites.


@marvinchin

In the meantime, we could make the overlay and spinner visible only on browsers with javascript enabled to avoid having the page be entirely unusable for these users using the approach I suggested above.

Pardon me for forgetting if we discuss this before, but if we do it in this order, the un-rendered content will flash for a second before the overlay is enabled right? I don't think that will look very nice to the user.

Alternatively, if we don't foresee this enhancement bringing much value to users we could just shelve it for now.

Thanks for offering to shelve the enhancement, if we indeed end up doing so, do check with Prof to see if you can claim credit for the work you have done for this PR.

For the issue of the partial rendering temporary "breaking" the website, you can still consider the method that I have suggested earlier to make the website less ugly:

We can add temporary classes to the components, before vue-strap finishes loading and starts to replace the components with actual implementations.

In the case of a <navbar>, we can try to add Bootstrap navbar classes to it so that at least they are positioned correctly while vue-strap is loading:

$('navbar').addClass('navbar navbar-expand-md fixed-top');

@damithc
Copy link
Contributor

damithc commented Jan 27, 2019

Thanks for mentioning the vuepress project. I checked their project and I think their idea of using Vue as a server-side rendering, rather than client-side rendering, is pretty nice since it allows them to reduce their reliance on JavaScript to purely just dynamic features. This is certainty an idea we can consider exploring in the future, so that Vue and vue-strap no longer need to be bundled together with MarkBind websites.

It's worth investigating, especially if it can solve the FOUC probem, which is a pretty serious problem as it affect adoption.
If we don't apply it across MarkBind immediately, maybe we can consider using it for the TopNav, as that seems to me the main cause of FOUC at the moment?

@yamgent
Copy link
Member

yamgent commented Jan 27, 2019

If we don't apply it across MarkBind immediately, maybe we can consider using it for the TopNav, as that seems to me the main cause of FOUC at the moment?

Sure, that seems like a reasonable start. @marvinchin interested?

@marvinchin
Copy link
Contributor Author

Sure, I could look at that and hopefully have something up by this/next week!

Also, I've updated the PR to only show the loading overlay for users with javascript enabled, without having the flash of content before the spinner is shown (thanks @yamgent for pointing me in the right direction).

@yamgent yamgent added this to the v1.17.2 milestone Jan 28, 2019
@yamgent
Copy link
Member

yamgent commented Jan 31, 2019

@marvinchin there is a merge conflict with this PR, would need you to resolve it, thanks!

@marvinchin marvinchin force-pushed the add-spinner branch 2 times, most recently from 4bd8215 to 68bebb1 Compare January 31, 2019 03:18
@marvinchin
Copy link
Contributor Author

@yamgent fixed!

@yamgent yamgent merged commit a721784 into MarkBind:master Jan 31, 2019
@marvinchin marvinchin deleted the add-spinner branch March 20, 2019 14:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants