Skip links are little internal navigation links that help users move around a page. It’s possible you’ve never actually seen one before because they’re often hidden from view and used as an accessibility enhancement that lets keyboard users and screen readers jump from the top of the page to the content without have to go through other elements on the page first.
In fact, you can find one right here on CSS-Tricks if you crack DevTools open.

In my opinion, the best way to implement a skip link is to hide it and then bring it into view when it is focused. So, let’s say we have a link in the HTML:
<a class="skip-to-content-link" href="#main">
Skip to content
</a>
…we can give it an absolute position and translate it off the screen:
.skip-to-content-link {
left: 50%;
position: absolute;
transform: translateY(-100%);
}
Then we can bring it back into view when it’s in focus and style it up a bit in the process:
.skip-to-content-link {
background: #e77e23;
height: 30px;
left: 50%;
padding: 8px;
position: absolute;
transform: translateY(-100%);
transition: transform 0.3s;
}
.skip-to-content-link:focus {
transform: translateY(0%);
}
This will hide our link until it is focused and then put it into view when it becomes focused.
Now, allow me to elaborate, starting with this quote from Miles Davis:
Time isn’t the main thing. It’s the only thing.
As I sit down to write this article in a rainy Ireland, I think of the challenge that many users face as they use the web that I take for granted. We put so much thought into creating a great user experience without thinking of all our users and how to meet their needs. Admittedly, a skip link was something I had never heard of until completing a course on Frontend Masters by Marcy Sutton. Since learning the power and simplicity of using a skip link, I decided to make it my mission to spread more awareness — and what platform better than CSS-Tricks!
A solution is an answer to a problem, so what’s the solution for helping keyboard users and screen readers find the content of a page quickly? In short, the solution is time. Giving users the ability to navigate to parts of our website that they are most interested in gives them the power to save valuable time.
Take the Sky News website as an example. It offers a “Skip to content” button that allows users to skip all the navigation items and jump straight to the main content.
You can see this button by navigating to the top of the page using your keyboard. This is similar to the implementation shown above. The link is always in the document but only becomes visible when it’s in focus.
This is the type of skip link we are going to create together in this post.
Our sample website
I built a sample website that we will use to demonstrate a skip link.
The website has a number of navigation links but, in the interest of time, there are only two pages: the home page and the blog page. This is all we need to see how things work.
Identifying the problem
Here’s the navigation we’re working with:

In total, we have eight navigation items that a keyboard user and screen reader must tab through before reaching the main content below the navigation.
That’s the problem. The navigation may be irrelevant for the user. Perhaps the user was given a direct link to an article and they simply want to get to the content.
This is a perfect use case for a skip link.
Creating the link
There are a couple of approaches to creating a Skip to content link. What I like to do is similar to the Sky News example, which is hiding the link until it is focused. That means we can drop the link at or near the top of the page, like inside the <header>
element.
<header>
<a class="skip-link" href='#main'>Skip to content</a>
<!-- Navigation-->
</header>
This link has a .skip-link
class so we can style it. Thehref
attribute points to #main
, which is the ID we will add to the <main>
element that comes further down the page. That’s what the link will jump to when clicked.
<header>
<a class="skip-link" href='#main'>Skip to content</a>
<!-- Navigation-->
</header>
<!-- Maybe some other stuff... -->
<main id="main">
<!-- Content -->
</main>
Here’s what we have if we simply drop the link into the header with no styling.
This does not look great, but the functionality is there. Try navigating to the link with your keyboard and pressing Enter when it’s in focus.
Now it’s time to make it look pretty. We must first fix the positioning and only show our skip link when it is in focus.
.skip-link {
background: #319795;
color: #fff;
font-weight: 700;
left: 50%;
padding: 4px;
position: absolute;
transform: translateY(-100%);
}
.skip-link:focus {
transform: translateY(0%);
}
The magic here is in the transform
property, which is hiding and showing our skip link depending on whether it is focused or not. Let’s make it look a little nicer with a quick transition on the transform
property.
.skip-link {
/* Same as before */
transition: transform 0.3s;
}
It will now transition into view which makes that bit better.
You should now (hopefully) have what I have below:
As you can see, the skip link bypasses the navigation and jumps straight down to the <main>
element when clicked.
It’s OK to use more than one link!
Right now, the link only serves one purpose and that is skip to the content of our website. But we don’t have to stop there.
We can go even further and create a skip link that has more options, such as a way to jump to the footer of the site. As you might imagine, this is quite similar to what we’ve already done.
Let’s make the blog page of the example site a little more usable by using multiple skip links. It’s common for blogs to use AJAX that loads in more posts when reaching the bottom of the page. This can make it very difficult to get to the footer of the website. That’s the problem we want to solve in this case.
So let’s add a second link that bypasses all that auto-loading business and jumps the user straight to a #footer
element on the page.
<div class="skip-link" >
Skip to <a href='#main'>content</a> or <a href='#footer'>footer</a>
</div>
We also need to amend our CSS a little and use the :focus-within
pseudo selector.
.skip-link {
transform: translateY(-100%);
}
.skip-link:focus-within {
transform: translateY(0%);
}
This is saying if anything within our .skip-link element has focus, then we show it. Sadly, neither Internet Explorer nor Opera Mini support focus-within, but its coverage is pretty darn good and there is a polyfill available.
This browser support data is from Caniuse, which has more detail. A number indicates that browser supports the feature at that version and up.
Desktop
Chrome | Firefox | IE | Edge | Safari |
---|---|---|---|---|
60 | 52 | No | 79 | 10.1 |
Mobile / Tablet
Android Chrome | Android Firefox | Android | iOS Safari |
---|---|---|---|
117 | 117 | 117 | 10.3 |
Last thing we need to do is make sure there’s an ID on our footer element so the link has something to jump to.
<footer id="footer">
Here’s what this gives us:
If we wanted to go one step further (and I’d encourage it), we could style each link a little differently so users can distinguish between the two. Both links in this example are plain white which works great for a single button that does a single thing, but it’d be clearer that we’re dealing with two links if they were presented differently.
Jumping to conclusions
Are you using skip links on your site? Or, if not, does this convince you to use one? I hope it’s clear that skip links are a great value add when it comes to the accessibility of a site. While it’s not a silver bullet that solves every accessibility need, it does solve some use cases that make for a much more polished user experience.
Here are some prominent sites that are using this or a similar technique:
Great post, thank you for writing it!
Another nice thing you can do with skip links is to provide them before sections of content that contain lots of interactive items, or items that can be tough to navigate through (such as table of contents and
iframe
s).The idea here is the same as a skip to main content link, in that you provide a mechanism to skip past something that can be repetitive and/or laborious to navigate through. Instead of skipping to the main content of the page you just skip past only the item and continue flow immediately after it. For example:
Please make sure to test with your target users’ browsers (look at your logs, for example). You may find you need to adjust the code to allow it to work properly.
For example: open IE11, Tab to the skip link, press Enter to activate it, and then press Tab again.
While the viewport may visually move the target of the skip link into view, that does not mean keyboard focus has moved.
Yes, this is annoying. Even more so since skip links have been around since 1998 and while some browsers have fixed this bug (Chrome took two tries), some won’t and some users are on old locked-down machines.
A workaround is to add
tabindex="-1"
to the<main>
:WebAIM mentions these quirks in its 2013 article. Hampus Sethfors has video examples of other weirdness from 2018 but be careful with the solutions listed without looking at your users’ browser breakdown first.
Adrián, you nailed there! Thanks for your instructions
Thanks for the tip. Can you elaborate on why tabindex=”-1″ fixes this?
Ah great tip!
FS, following an anchor link only moves focus if the item can accept focus. In this example,
<main>
is not a control nor interactive content, so it does not accept focus. Addingtabindex="-1"
allows it to accept focus without putting it in the tab order of the page. If you usedtabindex="0"
then it would be a tab-stop when tabbing through the page, which nobody wants.To see this in action, take the example pen (I linked the debug view so it works in IE11), test it as I outlined in my original comment, and then modify it in dev tools with the two
tabindex
values while repeating the keyboard test. It is a bit difficult to see since there are no focus styles for the Begin button or, well, anything in the example.Hopefully that will clear up the differences.
I’m not a Facebook fan, but they have a really good multi-link version.
As this just came up with a client, I want to note it here too…
This post shows how to make a visible skip link, which is good. A skip link must become visible when you tab to it. You have to see it has focus. Not doing so is a violation of WCAG SC 2.4.7 Focus Visible (AA). Keyboard-only or sighted screen reader users need this.
In newsletter #191 is paid attention to this article of Paul Ryan. Also the skip link in this CSS-tricks site is mentioned (“especially for screen readers” ) in the newsletter. That is true.
But in the CSS-tricks site the skip link for keyboard users (= not endless tabbing through all menu items) … is forgotten! Paul Ryan is targetting to both: screen reader users and keyboard users.
I guess the solution is to add in the CSS-tricks styles:
Hmm, agree with Adrian but…
Technically this is a more complete approach:
I would like to mention that the fixed position in skip links keep shows in papers while you print the website.
so technically as we try to keep our website accessible for all users we broke something without taking care of it.
check the thread https://twitter.com/Muhnad_a/status/1255204759583285250
How to produce it:
– open codepen in Debug mode.
– print the page(cmd+p) on mac (ctr+p) on windows.
– check the print page you will notice the ‘sjip to content’ is printed in the page.
Good point, well made.
I’ve added:
Since this was written I’ve furthered the solution to encompass all page links.
I proposed 3 options to fix this on PR https://github.com/Muhnad/skip-links/pull/5
one of them was hiding the element in the print mode exactly as you did.
I thought on it as UX and I found making the position fixed for the links is not the best thing so I switched to the make the links in absolute position.
Nice explanation, but… sorry, I don’t quite get it ;-(. What exactly do you mean please by “You can see this button by navigating to the top of the page using your keyboard“?
I ask this seemingly stupid question since I can’t quite reproduce the behavior that is shown in the animations. Until recently I clicked the top area of the page and then hit the tab key.
But that way, I can only use a skip link if there is no other link on the page. Because: As soon as I put a second link (an ordinary link that is always visible, no skip link) into the HTML, e.g. of the first code pen, my first tab action on the rendered page will target the new (i.e. ordinary) link, but no longer the skip link as it was before. In this case the skip link is only reachable for me by tabbing back from the ordinary link that was targeted in the first way. Same behavior applies to the codepen in the section “creating the link” after the skip link has been made invisible by the additional styles.
What am I doing wrong?
Currently, in Chrome, with the “Skip To Content” link tag inside a sticky header, whenever it receives focus, the page scrolls upwards about half a screen. Is anyone else getting that behavior?