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

Modal | JS | Add page scrolling option #1304

Merged
merged 8 commits into from Aug 5, 2019

Conversation

danielamorse
Copy link
Collaborator

@danielamorse danielamorse commented Jul 31, 2019

Jira

http://vjira2:8080/browse/BDS-1681

Summary

Allow page scroll behind modal to prevent content from shifting.

Details

Until we have a solid solution for content shifting / page scrolling when modal is open, just let the page scroll. The previous work to prevent the page from scrolling is now conditional based on the preventBodyScrolling prop.

Code changes:

How to test

  • Run locally in Chrome, Safari, and IE.
  • Verify that there is no page content shift when modal opens.
  • Verify that the page scrolls behind the modal (when it is long enough).
  • Flag any issues.

Copy link
Contributor

@sghoweri sghoweri left a comment

Choose a reason for hiding this comment

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

Tested and working as expected. Nice job @danielamorse.

As we chatted about, I'd recommend we make a two small tweaks to this:

  1. Move the two helper functions into @bolt/core/utils for easier maintainability
  2. Try setting the data we're storing for later on the HTML elements as a property vs data attribute (double check to keep me honest on this one 😉)
// If the browser body has scrollbar, set padding on the element the width of the scrollbar
export const setScrollbarPadding = function(element, hasScrollbar, scrollbarWidth) {
  if (!element) {
    return;
  }

  if (hasScrollbar) {
    const originalPaddingRight = element.style.paddingRight;
    const calculatedPadding = window.getComputedStyle(element)[
      'padding-right'
    ];

    // Save original padding value for later
    element.originalPaddingRight = originalPaddingRight;
    element.style.paddingRight = parseFloat(calculatedPadding) + scrollbarWidth + 'px';
  }
}

// Reset the padding on that element after modal is hidden
export const resetScrollbarPadding = function(element) {
  if (!element) {
    return;
  }

  if (typeof element.originalPaddingRight === 'undefined') {
    element.style.paddingRight = '';
  } else {
    element.style.paddingRight = element.originalPaddingRight; // Restore original padding value
  }
}
  1. Make sure our example shows how to account for selecting multiple elements + uses a js- selector
// Arbitrary fixed element, could be .c-page-header
const fixedElements = Array.from(document.querySelectorAll('.js-fixed-position'));

// Listen for 'modal:show' on the body, event will bubble up from the modal
document.body.addEventListener('modal:show', function(e) {
  fixedElements.map(element => {
    setScrollbarPadding(element, e.detail.hasScrollbar, e.detail.scrollbarWidth);
  });
});

// Listen for 'modal:hidden', fires after the modal has animated out
document.body.addEventListener('modal:hidden', function(e) {
  fixedElements.map(element => {
    resetScrollbarPadding(element);
  });
});

@danielamorse danielamorse changed the title Fix/modal content shift fixed position Modal | JS | Add preventBodyScroll option Aug 2, 2019
@@ -58,7 +58,10 @@ properties:
uuid:
type: string
description: Unique ID for modal, randomly generated if not provided.

prevent_body_scroll:
Copy link
Contributor

Choose a reason for hiding this comment

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

@danielamorse would no_body_scroll make more sense here?

*/
export const getScrollbarWidth = () => {
const scrollDiv = document.createElement('div');
scrollDiv.className = 'c-bolt-modal__scrollbar-measure';
Copy link
Contributor

Choose a reason for hiding this comment

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

Make sure to remove this ;)

/**
* Set padding on a given element equal to the browser's scrollbar width, used to prevent content shifting when scrollbars are turned off, e.g. when a modal opens
* @param {HTMLElement} element - The target element
* @param {(string\|number)} scrollbarWidth - The scrollbar width, with or without unit, e.g. 15 or 15px
Copy link
Contributor

Choose a reason for hiding this comment

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

👏 we need to start doing this for all net-new JS coming in. Nice!!

@@ -52,7 +52,7 @@ bolt-modal:not([ready]) {
position: fixed;
top: 0;
left: 0;
width: 100vw;
width: 100%; // Use % instead of vh or modal scrollbar is hidden behind bold scrollbar in IE11
Copy link
Contributor

Choose a reason for hiding this comment

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

+1 for commenting on this

Copy link
Contributor

@sghoweri sghoweri left a comment

Choose a reason for hiding this comment

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

Nice work @danielamorse!

Make sure to nix that one modal-specific class on the new utility function + rename the new modal body scroll prop if you like the proposed name change. Other than that, this looks good to go. 👍

@danielamorse danielamorse changed the title Modal | JS | Add preventBodyScroll option Modal | JS | Add page scrolling option Aug 2, 2019
no_body_scroll:
type: boolean
description: Prevent background page content from scrolling when modal is open
hidden: true
Copy link
Collaborator

Choose a reason for hiding this comment

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

Sort of a nitpick, but can we make the default value (false) explicit the schema?

Copy link
Collaborator

@remydenton remydenton Aug 2, 2019

Choose a reason for hiding this comment

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

Although, now that I think about it, do we ultimately want it to actually default to true? That's the ideal UX after all once we can get it working...

I suppose the way you have it is the path of least resistance though. Don't let me derail it.

@danielamorse
Copy link
Collaborator Author

@sghoweri :

Make sure to nix that one modal-specific class on the new utility function

Done.

@remydenton @sghoweri:

Although, now that I think about it, do we ultimately want it to actually default to true? That's the ideal UX after all once we can get it working...

You both mentioned this point, and I say, if we're going to be strict about breaking changes, the default should be true. Even better, let's not make it a prop until there's actually a need for it. The main use of the prop at this point is just for local development of the future 'no-body-scroll' feature. In light of that, I changed the hidden but publicly available noBodyScroll prop to a private variable (see commit). Everything else works the same. You all ok with that decision?

Copy link
Contributor

@sghoweri sghoweri left a comment

Choose a reason for hiding this comment

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

I’m good with this. @remydenton, any thoughts?

Copy link
Collaborator

@remydenton remydenton left a comment

Choose a reason for hiding this comment

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

Yes! I think that's an excellent choice @danielamorse. The behavior may change in the future (e.g. the background will stop scrolling), but that's not a breaking change if we never had a prop that would let you pick one or the other. And frankly, I don't think you should be able to pick one or the other-- we know which one's the better UX.

@danielamorse danielamorse merged commit edb6343 into master Aug 5, 2019
@danielamorse danielamorse deleted the fix/modal-content-shift-fixed-position branch August 5, 2019 13:47
@sghoweri sghoweri mentioned this pull request Aug 27, 2019
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