I’d like to use a sidebar type navigation, similar in appearance and functionality as the one used on the Bootstrap 3 documentation page.
I’ve tried to dissect it from the HTML source and CSS, but it’s not easy as the CSS has been minimized, but I’ve managed to copy/paste it into a Codepen-pen:
There’s a page entitled Bootstrap docs sidebar explained which goes through the entire code for it, so I followed the examples and entered the code into a new codepen, but it doesn’t work like in the explanation. I’ve ensured that I’ve used Boostrap 3 as was likely they’d used here, but still no go:
The person who documented this [also made it available in JSFiddle: http://jsfiddle.net/KyleMit/v6zhz/53/
I tried to copy the HTML, CSS and JS from it and pasted it into an empty Codepen, but alas it doesn’t work there:
I’ve scratched my head for a while to figure this out and it seems scrollspy isn’t part of the problem, but Affix.
According to the Bootstrap docs (“Migrating to Version 4”), Affix has been removed (which was part of Bootstrap 3), hence the issues I’m experiencing.
Dropped the Affix jQuery plugin.
We recommend using position: sticky instead. See the HTML5 Please entry for details and specific polyfill recommendations. One suggestion is to use an @supports rule for implementing it (e.g., @supports (position: sticky) { ... } )/
If you were using Affix to apply additional, non- position styles, the polyfills might not support your use case. One option for such uses is the third-party ScrollPos-Styler library.
From what I can see, this is the CSS code which affects Affix:
.fixed {
position: fixed;
}
I believe the above tells me that I need to replace the Affix functionality in BS3 with something else, such as the polyfill from the HTML5 Please page, which is called StickyFill.
But then I read it’s no longer needed for modern browsers, and I’m not sure if this relates to my specific case where position: fixed is used, not position: sticky. Also I don’t want to lose support for older browsers.
Reading on I see Scrollpos-styler might be the solution I’m looking for. But then I read this (scroll down on that Scrollpos-Styler page):
Differentiation and Limitations
This script is designed to modify attributes OTHER THAN an element’s position. It doesn’t work well when changing positioning of an element. Switching between position:relative and position:fixed is exactly what position:sticky is designed for, and this script in no viable alternative. Refer to the documentation for details, and use polyfills for older browsers.
So in the end I’m utterly confused. What exactly do I need to do regarding Affix?
Here’s my forked Codepen with the CDN links updated to Bootstrap 4.6 and the header navbar updated, but otherwise unchanged (UPDATE: no longer true as I’ve tried this out among other things, but without any success): https://codepen.io/CodeDecoder/pen/dyRpPPX
You don’t seem to be following all the instructions from here:
or here:
It looks like you need slim version of jquery for the scrollspy plugin.
The js is activated is with data attributes on the elements concerned and you need to attach them to the body tag. The body would also need position:relative applied. It’s in the documentation on the page I linked to.
It’s quite tricky to implement because you have to have it all pointing in the right place so I suggest that you start with the “Example with nested nav” from that above page and copy the html. Next view source and copy the relevant js or make sure you have the right files linked to from a cdn etc.
The nav will work with position:fixed but I’d need to double check that position:sticky will work also (position:sticky requires a different approach with the html and I have given you a codepen with a position:sticky example in another thread).
Look at the CSS on that bootstrap page using the devtools and see what css is being applied so that you can copy it.
As I said at the start bootstrap does not alleviate the need to have a deep understanding of CSS so its best if you keep trying yourself before I offer a solution. You can see from the examples on that bootstrap page that the nav is working and highlighted by the scrollspy (although it doesn’t collapse or open as that is your job to write in css using the class that the js adds).
If you can’t get anything to work then I will try and put up a stand alone version of the bootstrap example to show it working on its own. I’m a little pushed for time as these things do take a while to build even for an experienced user.
Here’s a fully working example that you can fork and play with.
I suggest that you play around with this for a few days until you understand what is happening. It is also worth spending a considerable amount of time going through the bootstrap documentation as its not something you can easily digest in an afternoon and you need to constantly refer to it and test the demos.
Even though I am pretty good at CSS it took me an hour or so to get that codepen working because I had to keep referring to the bootstrap documentation. (It would have only taken me minutes in vanilla css to do this though (apart from the js interactions).
Hope it helps anyway but I am away again for a few days from tomorrow.
Thank you!
I really appreciate you taking the time spent making it work in Boostrap 4.
I’ve started by comparing the original (Boostrap 3-based) code with your edited one and will take it from there. Since I’m not very experienced in neither CSS or JS I think it’ll take me a while to get the grips of this, but I’m certainly going to give it a go.
Thanks again!
I noticed something strange going on when clicking on the button (nav-pill) of your pen: click on “Item-1” and the sub-items don’t open, nor is the pill highlighted until you scroll down a bit. Then try to click on “Item-1-2” and the one above (Item-1-2) gets highlighted although the page is scrolled correctly. Likewise try the other buttons for a similar result.
I’ve forked it and played around with the code, attempting to understand how it all works (not quite there yet, but I now have a better understanding of which sections do what) and have modified it to make it more like that of the original Bootstrap 3 docs sidebar.
I don’t know if I’ve misunderstood something, but no matter what I’ve tried I couldn’t change the appearance of the nav-pills so I replaced them all with my own “nav-button” class and styled accordingly. For some reason the problems above are gone as well. I’ve commented all my changes and additions, and it appears to work as intended. I’m sure I could do a better job with the CSS, but other than that, does the HTML and CSS look OK?
I was really only interested in the scroll spy aspect and the automatic opening of the menu as the item came into view.
Because there is a sticky header I added a scroll-margin-top so that the item stays visible below the sticky header but that seems to be what is confusing the scroll spy JS.
No problem
I think I’ve found a CSS solution which appears to work (replacing the above code):
/* make room for the nav bar */
body {
margin-top: 40px;
}
/* make room for the nav bar */
h1[id],
h2[id],
h3[id],
h4[id],
h5[id],
h6[id],
dt[id]{
padding-top: 60px;
margin-top: -40px;
}
Below is a new fork of your pen with the new CSS applied.
As far as I can see it now works as intended.
I’ve also added smooth-scrolling (JS), but for that to work I had to replace the “slim” Jquery with the normal one (jquery.min.js).
Thanks for confirming
Do you mind if I use this sidebar nav for my own website? As you see I’ve made several changes (and will probably make some more), but thought I’d ask since you’re the original author.
The problem with that approach is that the sticky navbar starts down the page and leaves an unsightly gap until you scroll.
Here’s a better method.
/* hack for offset as data-offset not working in scroll spy */
.myContainer h4:before,
.myContainer h5:before{
content:"";
display:block;
padding-top:85px;
margin-top:-85px;
pointer-events:none;
}
I looked at the documentation in bootstrap scroll spy and there is actually a data-offset attribute which is supposed to work but alas it does not seem to work even though they say it does It seems to work on bootstrap3 but no one seems to have a demo in bootstrap4.
You could have just used one line of css for most modern browsers (which I have added to my pen).
html {
scroll-behavior: smooth;
}
Yes all my code is free as long as you don’t blame me for anything that goes wrong
Yes, I see what you mean.
Understanding it is over my head but absolutely looks better
I looked at the documentation in bootstrap scroll spy and there is actually a data-offset attribute which is supposed to work but alas it does not seem to work even though they say it does
Yes, I found this too in various discussions where they suggested using the offset feature, but I never got it to work either.
You could have just used one line of css for most modern browsers (which I have added to my pen).
html {
scroll-behavior: smooth;
}
Yes, I know about that one, but I added the JS for compatibility with older browsers (for instance Safari 13 which I’m still using).
Having added the smooth-scroll JS, should I then remove the above (scroll-behaviour:smooth;), or keep both (so the browser can choose which one to use)?
Yes all my code is free as long as you don’t blame me for anything that goes wrong
If you want to use both then you’d need your js to detect if the browser supports scroll behavior and if the answer is no then call your smooth scroll instead. Probably easier just to remove the css if you are using the js.
Note that the author of smooth scroll advises not to use it these days.
I see the css smooth scroll as an enhancement so it is no real loss to the 25% of browsers that don’t support it yet. Adding extra code that 75% of browsers don’t need doesn’t sound logical to me especially as support for the native scrolling will increase as time goes by.
Yes, I completely agree -especially since I noticed that the smooth-scroll JS adds a “flickering” problem while scrolling (especially when doing long scrolls). Take a look at my edited sidebar with JS:
And the exact same sidebar without smooth-scroll JS:
I’d say the flickering severely takes away the user-experience, and like you say this is really an enhancement, and not something that is needed for functionality (it’s easy to get overly caught up in all of this when designing!). So I think I’ll go with scroll-behavior: smooth; and leave it at that.
It’s all starting to function pretty well now, and I’ve even managed to style it similar to the original BS3 docs sidebar as first intended (see the above two pens).
Although that takes up less real-estate than using “nav-pills” I’m not sure if I’ll have enough space for my entire FAQ’s index in that sidebar. Apart from a regular scrollbar (I’m not too fond of that), is there a smart way to be able to scroll downwards in the sidebar if it extends below the bottom of the screen?
I noticed that when scrolling down to the bottom of the page the sidebar moves upwards (exposing the bottom-most items which were previously hidden), but it extends above and on top of the top-navbar (in Firefox 92). I’m guessing it’s a simple matter of fixing in CSS, but at the same time it looks like there might be a simple solution of a compromise of function and appearance.
PS: what’s the JS code for? It looks like it has something to do with the offset problem -is this in addition to the latest CSS code to make it all work?
I was testing the js offset from the js initiation. I already tried it with the html attribute version so I thought I’d test if the js intititiation was any different.
There are two ways to initiate the scroll spy and one is to add the required attributes in the body tag (as I did originally) and the the js looks for these and initiates the scroll spy on the required element. The second way to initiate it is to just do it directly from js without the attributes on the body. It’s essentially the same thing in the end.
Aha! Similar to moving layers (in Photoshop etc) forward or back. Neat!
I see what you mean. So they both work equally well it seems.
Found what you’re talking about described in the docs here.
On another note, do you know what can cause flicker to the top navbar?
First, here’s your original code, but with several more items added:
and here’s a fork of the above, but with the general appearance changed:
Notice how the top navbar flickers when you click on an two items far from each other (i.e. click on “Item 1”, then “Item 14”). It could be a browser thing (I’m using Firefox 93.0 on a Mac), but it’s strange that your original design doesn’t cause any flicker in the same browser.
I’ve also been giving some thought on what to do with a large number of main items which could cause the bottom ones to go past the lower end of the screen, depending on the browser window size/media type.
I’m not too fond of adding a scrollbar because of added clutter, but a compromise would perhaps be to automatically add a scrollbar to the sidebar-nav if (and only if) its content extends below the visible window). It appears this CSS code should do it: overflow: scroll;
(CSS layout -overflow).
I haven’t had time to try it out yet, but are there other, better suited solutions to accessing something that goes past the visible window area without causing extra clutter or disturbing elements?
Looks like a bug in Firefox. I believe its the scroll spy position:relative on the body that causes it. There was a similar bug logged on Firefox about position sticky.
Its fine in chrome.
Unfortunately I don’t really have the means to test thoroughly as I am away for another three weeks and not at my usual computer.
You would need overflow:auto not scroll and then set a max-height for the nav bar that is 100vh minus 6rem. e.g. max-height:calc(100vh - 6rem). Where 6 rem would be the top position of your nav so adjust to suit.
That’s awesome! Thanks -your help is very much appreciated
Here’s the CSS for adding for this to work.
As you say the “rem” value needs to be adjusted to suit the height of the navbar, so I changed this to only have the scrollbar appear when the browser height is below that of all my sidebar items.
I’ve also customized the scrollbar appearance (only the sidebar-nav scrollbar) making it thinner among other things. There are different codes for Firefox and webkit browsers:
/* sidebar nav -stays in same location while scrolling */
.sticky-column {
position: -webkit-sticky;
position: sticky;
top: 5rem;
/* scrollbar appears with screens not high enough
to display entire sidebar nav,
otherwise hidden */
overflow: auto;
/* change "rem" value to height of
when scrollbar appears */
max-height: calc(100vh - 6rem);
/* scrollbar appearance (Firefox only) */
scrollbar-width: thin;
scrollbar-color: red white;
/* scrollbar on left side */
/* direction: rtl; */
}
/* scrollbar appearance (webkit browsers) */
/* width */
.sticky-column::-webkit-scrollbar {
width: 7px;
}
/* Track */
.sticky-column::-webkit-scrollbar-track {
box-shadow: inset 0 0 5px grey;
border-radius: 10px;
}
/* Handle */
.sticky-column::-webkit-scrollbar-thumb {
background: red;
border-radius: 10px;
}
/* Handle on hover */
.sticky-column::-webkit-scrollbar-thumb:hover {
background: orange;
}
Here’s my sidebar again with the scrollbar added. It’s not wroking perfectly because the sidebar-nav doesn’t stick to the top unless you scroll the contents down to item 1. I haven’t yet figured out why/how this happens, but I think it has something to do with how I’ve set up columns/rows:
Here on the other hand it works much better. This is the actual layout I want to use for my site (obviously without any content yet) and here the sidebar nav stays in place at the top:
But I wonder if I’ve made a structural mistake in my layout as the sidebar DIV I’ve coloured pink also has the topmost DIVs (1, 2, A) in the content column show up pink as well. Those are the DIV boxes which represent various content such as images, Bootstrap cards, text etc. Most of those content-boxes are coloured (“bg-success” and “bg-warning”) in order to see them better, but I didn’t expect the sidebar-nav column to extend over to the content section column… Maybe someone reading can explain why?
Firefox bugs: yes, it does look like there’s a bug causing the header-flickering when scrolling, and perhaps there’s a workaround once I figure out exactly what’s causing it, but otherwise I’ll just leave it at that.
There might be another bug I’ve discovered in Firefox: often when I’ve made some changes in my sidebar-nav code within Codepen and saved it, the sidebar doesn’t work properly. Either the sub-tems don’t expand (i.e. item 1-1) or mouse-hovering over the items is gone. The solution is to reload the browser page (sometimes multiple times). I’ve briefly read about CSS resets and wonder if this might be something I need to look closer into?
Sticky items are only sticky in their current context. The container is the context for this sticky nav and therefore the nav only sticks when the container scrolls and the navs top position matches the value you set.
If you look at the context (highlighted here by devtools) you can see where the sticky nav starts.
If you wanted it to start at the top then the container must start at the top also (e.g. Put that heading in the right column and allow the nav to be at the top).
You have coloured pink .leftrow which despite its name is not a left row but a whole container for both columns. You see the pink on divs 1,2,A simply because they are the ones that don’t have a background color. All the other divs are pink underneath the backgrounds you have set…
You should have applied pink to .sticky-column instead.
Try clearing your cache after making changes.
Resets will not have anything to do with your issue and are just a means of getting some standard padding, margin on various elements plus a load of mostly unnecessary stuff. If you simply control every element you use then you won’t have issues. Resets can be good to study to see what elements need to be addressed but once you know about these things then you can just address things as you build.
I see what you mean.
Having now added borders and sorted out the colouring it makes understanding it easier.
Tried that, but didn’t make any difference. Maybe yet another Firefox bug, or something that happens only when trying it out in Codepen. It might go away when I do the final coding locally in a text editor.
OK, so for general Bootstrap use this isn’t anything I need to be concerned with?
It appears to have been more of an issue many years ago when I started looking into Bootstrap.
So to summarize: now I’ve got several sidebar layouts working pretty well and giving me choices depending on the amount of sidebar items and general functionality…
A) Sidebar-nav with auto-scrollbar
(scrollbar for sidebar-nav appears whenever the screen isn’t high enough to display all items. Is hidden otherwise)
Very nice! Works generally very well now.
B) Sidebar-nav with auto-scrollbar, alignment below header title
(same as “A” but with room for a header title above both the content and sidebar area)
Works well too, but for some reason the scrolling aligns to the top of the top-navbar and not underneath it. Adjusting the scrollspy alignment padding-top: and margin-top: values don’t change this.
Does it have something to do with where scrollspy “looks”?
body {
position: relative;
}
C) Sidebar-nav with auto-scrollbar, auto-hiding top-navbar when scrolling down
(auto-hiding top navbar means more vertical room for sidebar items) https://codepen.io/CodeDecoder/pen/gOxRNoV
Great in theory but doesn’t utilize the extra vertical space available once the top-navbar has been hidden. Maybe there’s a way to auto-expand the sidebar according to the available space, and still have the scrollbar appear when there’s no available space left?
D) Sidebar-nav with auto-scrollbar, auto-hiding top-navbar when scrolling down/reappars when scrolling up
(same as “C” but here the top navbar reappears when scrolling up a bit) https://codepen.io/CodeDecoder/pen/KKvXvKN
Same problem as with “C”. Also a problem where the top-navbar blocks the topmost sidebar items when being in the midst of the content somewhere and scrolling up a bit (so the top-navbar reappears).
It would be neat if the sidebar would automatically expand downwards IF there is a need for it instead of its scrollbar appearing, then IF there still isn’t enough room for all its items the scrollbar will appear.
And for this particular top-navbar setup, have the sidebar automatically slide up or down according to if the top-navbar is present or not.
Is there any way all this can be done, in CSS perhaps?
Also, I’m welcoming all suggestions and comments on which method would be most useful/functional for visitors.