Reputation: 41
This question is about getting hashed URLs (like mydomain.com/somepage#SomeAnchor
) to scroll out from under a fixed page header, when those URLs are jump targets. It's an offshoot of this answered question – but I'm wondering whether anyone has gotten its answers to fully work on the Tripit Slate docs-publishing framework?
This Slate-based site is not ours, but it shows our predicament:
If you click a link from the left nav, the center text column scrolls to your selected heading. All is well.
But try clicking a link in the body text. E.g., from
http://buddycloud.com/api#accounts, click the push notification
link. You scroll to an entirely different subheading. The target you requested
actually has focus, but it's hidden under the top nav bar. (Scroll up and
you'll see it.)
Our left-nav links work cleanly, like the buddycloud site's. Thanks to Sidnicious' 4086107 answer we've placed an invisible pseudo-element above all our headings, as devised by Nicolas Gallagher. Here's the CSS class:
.jumptarget::before {
content:"";
display:block;
height:85px; /* fixed header height*/
margin:-85px 0 0; /* negative fixed header height */
}
And here's how we apply it to our headings:
## <span class="jumptarget" id="SomeAnchorName"> SomeHeading </span>
Which is what works fine for the left nav. From css-tricks, we've learned why it nevertheless fails for "in-page" hashed links:
When a link includes a hash, like this:
<a href="#section-two">Section Two</a>
...the browser window will scroll...to the minimum possible position to make that element wholly visible. ...flush with the top edge of the browser window. This can be..., in the case of a fixed-position, stay-on-top header, hugely problematic.
Indeed, our fixed top nav looks much like buddycloud's (ours is 82 px high). And our in-page hashed links hide under it, just as theirs so.
With two important exceptions: First, in cases where the target "hashed" URL resides within the same markdown file as the outbound link, the target cleanly peeks out from under the fixed header, just as left-nav links do. (On the source side, Slate stores all content as .md
files.) This localizes the problem: Link targets hide only where Slate has to traverse to a separate target .md
file, and to then concatenate #<SomeAnchorName>
to complete the URL.
Second, we have found a hack that gets all "in-page" hashed links to clear our top header. This involves dual-tagging our headings in HTML, using two spans. The first is an empty dummy span, which sits above the actual heading text to trick the scroll behavior. (It's tagged with our above jumptarget
class.) On the heading itself, we apply a separate span with a class, which corrects a left indent from the first hack. The dual-tagging looks like this:
<h2>
<span class="jumptarget" id="bogusN"> </span>
<span class="jumpleft"> Bogus Heading 2 </span>
</h2>
But although this reveals our "in-page" hashed links, it completely breaks our left nav. Due to some interaction with Slate's tocify
left-nav generator, any headings tagged in this way misbehave as follows: (1) Hide their children in the left nav. (2) When clicked, prevent the jumptarget
class from scrolling them out from under the top header. (3) When clicked, collapse their parent in the left nav.
So in all, our dilemma is that: Our fix for links from our left nav leaves our in-text links broken. Whereas, our fix for the in-text links breaks our left-nav fix.
If anyone has globally solved this on Tripit Slate, or tocify
, or a different framework, we'd be very grateful for pointers. Clean CSS, hacky HTML, or jivey JavaScript – we're agnostic. Thanks!
[Update 7/13/16:] Here's the script that our developer added to layout.erb
, to clear link targets from getting hidden by a persistent header. We're testing whether it works for all links. Comments very much invited:
<script>
var container = $('.page-wrapper .content');
var body = $('body');
var headerHeightPixels = 85;
container.on('click', function(event) {
var target = $(event.target);
if (target.is('a') && target.attr('href').charAt(0) === '#') {
setTimeout(function() {
$('body').scrollTop($('body').scrollTop() - headerHeightPixels)
}, 0);
}
});
</script>
Upvotes: 4
Views: 429
Reputation: 11
Tocify has parameters that can be set that will control the spacing at the top of the scroll area when you click on a link from the left hand panel (the ToC panel that is generated by tocify.js) This is documented here and it is controlled by the scrollTo key in the tocify json. But this only controls the positioning of the scrolling area for the left hand column.
Although you can add the same logic as in tocify to "adjust" the scroll for links in the center panel in the same way that tocify does. For our use, we took a different approach - we scroll the top header off the page when the user starts moving through the slate document. Our rational for this is that once a user starts to scroll down a long slate document, they are using it in anger and we want to give them as much real-estate as possible to get as much relevant information as possible. When we looked at the header, it provided lots of site context and had little to do with the document that was being read. Thus, but floating the top header, the reader gets more real-estate and can always return to it by scrolling up.
Upvotes: 0