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

Optimize homepage #15980

Merged
merged 1 commit into from Jun 21, 2017
Merged

Optimize homepage #15980

merged 1 commit into from Jun 21, 2017

Conversation

wjordan
Copy link
Contributor

@wjordan wjordan commented Jun 20, 2017

This PR makes various small tweaks/updates to the homepage. Half of the changes are helpful in preloading the initial hero-image (moving critical content to appear as early as possible in the loading sequence), the other half are some general cleanup.

Preload first hero image

  • preload first hero image using a preload link tag
  • select _2x.jpg image based on min-width: 1440px instead of devicePixelRatio (prevent non-2x images from being zoomed in too close)
  • use CSS media queries instead of rewriting URLs in JavaScript (necessary for preload link)
  • use CSS animation to fade-in first hero image (better rendering performance, and it can begin fading in immediately before jQuery is loaded)
  • use lazysizes bgset to lazy-load subsequent hero images

Other cleanup

  • remove jquery.placeholder polyfill- no longer needed for modern browsers
  • lazy-load a few more images that may never be rendered (language flag, gallery thumbnails)
  • remove ajax requests made obsolete by page/header redesigns (user_menu, user_hero).
  • Add explicit width/height dimensions to some elements (eliminates jarring/time-consuming page reflow after images are loaded)
  • Move donor-link shuffle to client-side javascript (when HTML is cached, shuffling content in server code doesn't work as expected).

Demo

https://adhoc-optimize-homepage.cdn-code.org/

@wjordan wjordan requested a review from breville June 20, 2017 21:41
#fullwidth#{index} {
background-image: url(#{entry[:image_t]});
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you move this inline CSS to the appropriate .css file?

Copy link
Contributor

Choose a reason for hiding this comment

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

I realize that you have it inlined here to generate the correct URLs for each image. I'd really prefer we use the srcset attribute instead: https://stackoverflow.com/a/28731347.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

  1. This CSS style is dynamically generated based on server-side inputs, so can't be included in a static file.
  2. srcset attribute is for the img element, whereas these images are set with a background-image CSS style, which is a different system that I don't think are compatible. There is an image-set() CSS notation, but it's still just a draft with limited support, and doesn't (yet) support width-based sets (just resolution-based).

@@ -82,9 +82,6 @@

function Petition()
{
// placeholder text for non-HTML5 browsers
$('input[type=text], textarea').placeholder();
$('input[type=email], textarea').placeholder();
Copy link
Contributor

Choose a reason for hiding this comment

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

Not needed? Can this whole function go away (and wherever we call it)?

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 jquery.placeholder polyfill is no longer needed for modern browsers.
  • petition = new Petition(); and petition.signPetition can't go away, so I'm pretty sure the empty function definition needs to remain in order for the JS prototype-class to work (I could be wrong about this though)

// Shuffle donor-slider links.
var ul = document.querySelector('.donor-slider');
for (var i = ul.children.length; i >= 0; i--) {
ul.appendChild(ul.children[Math.random() * i | 0]);
Copy link
Contributor

Choose a reason for hiding this comment

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

Bitwise or (|) intentional? Or should this be ||?

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 bitwise-or truncates a floating-point, to generate a random index-integer from 0 to i-1.

Copy link
Member

Choose a reason for hiding this comment

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

A comment to explain this trick would be handy for newcomers.

@@ -21,3 +20,9 @@
= "#{supporter[:name_s]}"
- else
!= "#{supporter[:name_s]}, "
:javascript
Copy link
Contributor

Choose a reason for hiding this comment

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

Please move this inline JS to an appropriate .js file.

Copy link
Contributor Author

@wjordan wjordan Jun 20, 2017

Choose a reason for hiding this comment

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

Linking external resources pauses page-loading and would negatively impact performance.

See: Render-Blocking JavaScript

@breville
Copy link
Member

re: "select _2x.jpg image based on min-width: 1440px instead of devicePixelRatio (prevent non-2x images from being zoomed in too close)"

Does that mean we no longer load retina images for retina devices with a display narrower than 1440px, such as tablets and phones?

@breville
Copy link
Member

If you visit the page for the first time (or with caching disabled) the second image in the banner rotation isn't available when the first image starts fading out, so you see the first image fade to white before the next image suddenly appears. The second image should be loaded by the time the first image is fading out so that there is a nice cross-fade.

@wjordan
Copy link
Contributor Author

wjordan commented Jun 21, 2017

@breville fwiw, the fading-to-white in between images (it's more noticeable on a low-bandwidth connection) shouldn't be new to this PR, this behavior would have been introduced by #15405.

It will take a bit more work, but should be possible to add logic to fully pre-load the next image in the carousel before initiating the cross-fade.

@wjordan
Copy link
Contributor Author

wjordan commented Jun 21, 2017

Does that mean we no longer load retina images for retina devices with a display narrower than 1440px, such as tablets and phones?

Correct, this is the intended change. The difference is that the device's pixel ratio doesn't matter as much as how many pixels the device actually requires to render the image. This will prevent too many pixels from being sent to high-dpi but low-total-pixel phones, and vice versa, will prevent too few pixels from being sent to normal-dpi but high-total-pixel monitors. This is the current best practice, from what I've been able to find- see Screen Width Optimization Using srcset for some discussion + visual aids.

@breville
Copy link
Member

Good point. That does make sense then.

@wjordan
Copy link
Contributor Author

wjordan commented Jun 21, 2017

@joshlory and @breville thanks both for the detailed feedback! I've decided to better organize the diffs by extracting two separate, more self-contained PRs- one dealing with the hero-images and related CSS, and another dealing with the donor-link shuffling JS, leaving the other (more minor) improvements in this PR. Will add links to both when they're ready.

}
}
});
});
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This ajax call can be removed (and the #petitionexpand div initially set to display: block) now that users are no longer directed to the homepage when logged-in. /dashboardapi/user_hero is implemented with head :not_found unless current_user, so will now always return :not_found, so we can skip this ajax step and always start the page with petition block expanded.

Copy link
Member

Choose a reason for hiding this comment

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

To be clear, the petition should visually still not be expanded.. we still want the user to click "I agree" before expanding to show the whole form. But it makes sense to show the unexpanded petition right away.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

right, the petitionexpand div will be visible (but not expanded) on initial load, the contained form div will not be 'expanded' (via expandPetition()) until user action.

@wjordan
Copy link
Contributor Author

wjordan commented Jun 21, 2017

Finished extracting the hero-image preload into #16002, and removed the donor-link shuffle change for now. I think the remaining items are ready to merge.

- remove jquery.placeholder
- lazy-load more images (language flag, gallery thumbnails)
- remove unnecessary ajax requests
- set image dimensions on elements to avoid reflow on image-loads.
@wjordan wjordan merged commit bacc29b into staging Jun 21, 2017
@wjordan wjordan deleted the optimize-homepage branch June 21, 2017 20:25
@breville
Copy link
Member

breville commented Jun 21, 2017

Just a second thought about using min-width to decide whether to show 2x images or not... doesn't iOS Safari report width/height of 1024x768 on iPad, for example, whether retina or not? I don't think it actually tells us how many pixels there are to display. http://stephen.io/mediaqueries/

@wjordan
Copy link
Contributor Author

wjordan commented Jun 21, 2017

yeah, I think you might be right - the px in min-width: 1440px is (incorrectly) css-pixels while the w in 1440w is (correctly) 'device-pixels', so the width-based media query wouldn't work as I originally described it above. The extracted PR #16002 didn't implement any width-based media query yet (I'll leave that as a future todo) so should be unaffected for now.

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

3 participants