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

Make the position of top navbar fixed #982

Merged
merged 14 commits into from
Feb 22, 2020
Merged

Conversation

le0tan
Copy link
Contributor

@le0tan le0tan commented Jan 15, 2020

This should provide an alternative solution to #973, without causing too
much trouble.

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

• [X] Enhancement to an existing feature

What is the rationale for this request?

It's a bit strange that MarkBind doesn't fix the top navigation bar, nor re-shows the navbar when scrolled down. Moreover, currently there's no "back-to-top" button, which makes both navigating across the site and searching content a bit tricky. We can fix the top navbar to fix these problems.

What changes did you make? (Give an overview)

Changed the position of the top navbar to be fixed and move the content below down.

Replaced the vue-strap.min.js file from MarkBind/vue-strap#123

Provide some example code that this change will affect:

na

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

na

Testing instructions:

To enable fixed header (or navbar), simply add class="header-fixed" property to the <header> element in header.md

  1. On full width, check if the left and right page navigation div is sticking to the page correctly
  2. On full width, check if the top navbar always shows on top of any other page content
  3. See if the responsive design still works fine (i.e. the collapsed topnav).
  4. Remove class="header-fixed" property to see if the navbar is no longer fixed.

Other things to notice:

  • whether the page nav (on the right) is working properly
  • whether the anchor next to the headings is working properly

Proposed commit message: (wrap lines at 72 characters)

Make top navbar position fixed

Top navbar is responsible for both navigating across the
site and placing the search bar. MarkBind often deals
with long pages thus hiding the top navbar and making
the user to go back to top to see the top navbar may not
be a good design choice.

In this PR I fixed the top navbar's position so that it's
always accessible to the user.

This should provide an alternative solution to MarkBind#973, without causing too
much trouble.
@damithc
Copy link
Contributor

damithc commented Jan 16, 2020

Is this intended to make the top nav bar sticky? If so, ensure that scrolling to anchors works correctly. We used to have a sticky top nav in early days of MarkBind and a complication we had at that time was when we scroll to an anchor in a page, the target position of the page gets hidden behind the top nap (because the top part of the page is occupied by the top nav).

@le0tan
Copy link
Contributor Author

le0tan commented Jan 16, 2020

Is this intended to make the top nav bar sticky? If so, ensure that scrolling to anchors works correctly. We used to have a sticky top nav in early days of MarkBind and a complication we had at that time was when we scroll to an anchor in a page, the target position of the page gets hidden behind the top nap (because the top part of the page is occupied by the top nav).

Thanks for the reminder! I fixed this problem in last commit =)

Copy link
Contributor

@marvinchin marvinchin left a comment

Choose a reason for hiding this comment

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

Hello! Thanks for looking at this 🙂

I've added some thoughts about the approach in the comments. Also, vue-strap.min.js should be updated independently of this PR.

asset/js/setup.js Outdated Show resolved Hide resolved
function setupDummySpans() {
jQuery('<span class="anchor"></span>').insertBefore('h1, h2, h3, h4, h5, h6');
jQuery('span[class="anchor"]').each((index, element) => {
jQuery(element).attr('id', jQuery(element).next().attr('id'));
Copy link
Contributor

Choose a reason for hiding this comment

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

This leads to both the dummy span and the actual heading having the same id. I think we should try to avoid this.
Screenshot 2020-01-17 at 8 42 47 AM

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I removed the id for all headings (if dummy spans are added as their anchors). Is this OK?

@@ -28,6 +40,9 @@ function setupAnchors() {
() => jQuery(heading).find('.fa.fa-anchor').css('visibility', 'hidden'));
}
});

setupDummySpans();
Copy link
Contributor

Choose a reason for hiding this comment

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

Adding dummy spans is an interesting approach, but it does feel a little hackish. I wonder if we can make changes to the scrollToUrlAnchorHeading function to update the scrolling behaviour to do this in a cleaner way?

If this is something that you've already tried, or if you feel otherwise about that approach, feel free to bounce this back to me.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

image

I think adding a dummy node is quite common in terms of anchoring... Above is the example in Docusarus, they also adopted this approach (only difference is they use instead of and they put the anchor inside of ).

Adding dummy spans is an interesting approach, but it does feel a little hackish. I wonder if we can make changes to the scrollToUrlAnchorHeading function to update the scrolling behaviour to do this in a cleaner way?

If I understand it correctly, isn't scrollToUrl.. only called once after the Vue instance is mounted?

Copy link
Contributor

Choose a reason for hiding this comment

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

That makes sense, thanks for the explanation :)

- Adopt the height offset to the actual height of <header>
- Provide "fixed" prop for <navbar> component
Copy link
Contributor

@marvinchin marvinchin left a comment

Choose a reason for hiding this comment

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

Added a couple more comments!

I'm personally not a fan of dynamically injecting CSS into the page, but I'm honestly not too sure what the conventions around this are.

Maybe @Chng-Zhi-Xuan has some thoughts about this?

function setupAnchors() {
const navBarSelector = jQuery('nav, .navbar');
const isFixed = navBarSelector.attr('style').includes('position: fixed;');
Copy link
Contributor

Choose a reason for hiding this comment

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

Can navBarSelector.attr('style') be undefined?
Screenshot 2020-01-19 at 11 41 10 PM

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It would be undefined when the navbar is not fixed. I committed a patch on this. Thanks!

asset/js/setup.js Outdated Show resolved Hide resolved
jQuery(heading).removeAttr('id'); // to avoid duplicated id problem
const headingHeight = jQuery(heading).height();
const heightOffset = navbarHeight + headingHeight;
const spanCss = `span#${spanId} { margin-top: calc(-${heightOffset}px - .5rem);\n`
Copy link
Contributor

Choose a reason for hiding this comment

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

Just wondering - why do we need to use the heading height in the calculation? Docusaurus seems to just use a static value. Would just using the height of the navbar + some clearance suffice for us? This would allow us to just use a static style instead of adding CSS dynamically like this.

I'd love to fiddle around with this a bit more to see what works, but I think the undefined attr('style') mentioned above seems to break the netlify demo. 😛 Let me know if you want me to take another look at this after you have fixed the issue.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@damithc mentioned a case where he added some extra stuff in the header: https://nus-cs2103-ay1920s1.github.io/website/index.html
In this case we have to dynamically calculate the height.

(I used a fixed number in the previous PR...

Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm, I'm still not sure how the heading height takes into account additional things in the header. Do you have a test site with this that I can look at?

I've fiddled around with this a bit and I think this is a way we can do it without having to dynamically compute the headingHeight for each individual heading.

  1. Move the dummy anchor span above the heading (instead of below it)
  2. Set display: block and position: relative - we want to "float" this span above the actual heading, so that when this span is at the top of the page, our heading will be under the navbar
  3. Set top to be negative the height of the navbar

This is what the outcome would look like:
Screenshot 2020-01-20 at 5 48 53 PM

This way, we can just use a common class for all anchors, instead of having to define a style separately for each anchor.

Copy link
Contributor

@marvinchin marvinchin left a comment

Choose a reason for hiding this comment

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

I've played with this feature a little bit, and it seems to break in some cases:

  • When there are additional things in the header besides the navbar (note the div with the text HELLO above the navbar):
    header-with-extra-stuff
  • When the window is resized:
    fixed-nav-bar

I think it might be necessary for us to make the entire header fixed, and not just the navbar.

Let's also update the user guide for the to explain how to use the fixed navbar (or header) feature. It might also be a good idea to update one of the test sites to use this feature so that it is easier to test and catch future regressions.

@le0tan
Copy link
Contributor Author

le0tan commented Jan 20, 2020

@marvinchin I requested changes to the functionality, can you take a look if it's OK? I'll get to write the documentation and tests right after your approval on the functions.

When the window is resized: ...

This problem still exists in the new solution, just much less obvious - the navbar height increases as some of the text wraps around.

Copy link
Contributor

@marvinchin marvinchin left a comment

Choose a reason for hiding this comment

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

Thanks for making the changes. I've added a couple more comments.

Also, I left a comment in an earlier comment chain about the approach for implementing the dummy anchor span but I'm not sure if you've seen it. Do you have any thoughts about that? Happy to discuss if you have any concerns.

header.header-fixed {
position: fixed;
width: 100%;
z-index: 9999;
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there a reason why 9999 was chosen? We seem to be using z-index: 1000 for the navbar. Should we just stick to that instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's just an arbitrary large integer, shouldn't matter much.

asset/js/setup.js Outdated Show resolved Hide resolved
asset/js/setup.js Outdated Show resolved Hide resolved
@damithc
Copy link
Contributor

damithc commented Feb 3, 2020

How's this going? Looking forward to use this feature as it can save a lot of scrolling up to the top of the web page.

@yamgent
Copy link
Member

yamgent commented Feb 15, 2020

How is this PR coming along? The corresponding vue-strap PR has been waiting for a few iterations as this PR is not done yet.

@le0tan
Copy link
Contributor Author

le0tan commented Feb 15, 2020 via email

@le0tan
Copy link
Contributor Author

le0tan commented Feb 16, 2020

Although ideally the top navbar should remain the same height in spite of the responsive layout, I did find some edge cases resulted by wrapped text:
image
We can mitigate such unexpected behavior by adding some extra top to it:
image

@openorclose
Copy link
Contributor

http://osvaldas.info/examples/auto-hide-sticky-header/?reactive

How about this?

If user scrolls down, header disappears, when user scrolls up / clicks a link then the header appears as fixed.

@le0tan
Copy link
Contributor Author

le0tan commented Feb 21, 2020

http://osvaldas.info/examples/auto-hide-sticky-header/?reactive

How about this?

If user scrolls down, header disappears, when user scrolls up / clicks a link then the header appears as fixed.

that could be another PR as another option I guess?

@le0tan
Copy link
Contributor Author

le0tan commented Feb 22, 2020

@yamgent I took @marvinchin 's advice and this PR is now ready for review.

@yamgent
Copy link
Member

yamgent commented Feb 22, 2020

I am not on the desktop right now, so I am trusting you that this is working fine right now 👍

The changes on the corresponding vue-strap will be ready by next release (which is hopefully tomorrow).

@yamgent yamgent added this to the v2.10.1 milestone Feb 22, 2020
@yamgent yamgent merged commit b900962 into MarkBind:master Feb 22, 2020
yamgent added a commit to yamgent/markbind that referenced this pull request Feb 23, 2020
@yamgent
Copy link
Member

yamgent commented Feb 23, 2020

...and we forgot to update the expected test files for the changes made. :P

Updated in 3953dc8.

@damithc
Copy link
Contributor

damithc commented Feb 23, 2020

@le0tan Does this mean the topNav should stick to the top of the viewport by default? I tried this version on CS2113 website but the topNav didn't stick.

@damithc
Copy link
Contributor

damithc commented Feb 27, 2020

@le0tan Does this mean the topNav should stick to the top of the viewport by default? I tried this version on CS2113 website but the topNav didn't stick.

@le0tan any updates?

Tejas2805 added a commit to Tejas2805/markbind that referenced this pull request Feb 27, 2020
* 'master' of https://github.com/MarkBind/markbind:
  Update tests
  Allow using 'none' footer attribute in frontmatter (MarkBind#1002)
  Support line numbers for code blocks (MarkBind#991)
  2.11.0
  Update test files due to changes in PR MarkBind#982
  Update vue-strap version to v2.0.1-markbind.36
  Make highlighting bold (MarkBind#1045)
  Support markdown for header attr in dropdown (MarkBind#1029)
  Add '_site' to the ignored folders in site.json (MarkBind#1046)
  Use path.join instead of string interpolation (MarkBind#1052)
  Implement box markdown header attributes parsing (MarkBind#1025)
  Make the position of top navbar fixed (MarkBind#982)
  Exclude *.md files from being copied over on build (MarkBind#1010)

# Conflicts:
#	docs/css/main.css
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

5 participants