Search code examples
htmlcsshyperlinkalignment

How to fix a line of text links near top of page?


Three rows of text links near top of page shift up to top when a link is pressed, obscuring a line of text already at top. How can I anchor the position of the three rows?

<!-- Styles for three rows of header text that shift upwards when I click on any link --!>

 /* Style for the fixed header */
        .header {
            position: sticky;
            top: 0;
            left: 0;
            width: 100%;
            background-color: #f1f1f1;
            padding: 10px;
            z-index: 10000;
            text-align: center;}

  /* Style for each row of links */
       .header-row {
            display: flex;
            justify-content: center;
            margin-bottom: 10px;}

<!-- divs for the three rows of text that shift upwards when any link is pressed--!>

<div class="header">
    <div class="header-row">
        <a href="#text1">One</a>
        <a href="#text2">Two</a>
        <a href="#text3">Three</a>
        <a href="#text4">Four</a>
  </div>

    <div class="header-row">
        <a href="#text5">Five</a>
        <a href="#text6">Six</a>
        <a href="#text7">Seven</a>
        <a href="#text8">Eight</a>
    </div>
 
<!-- The following link -- on third tow -- shifts the page down so the obscured top row of text reappears --!>

  <div class="header-row">
        <a href="#top">Return to table of contents</a>
    </div>
</div>

<!-- Styles for the single row of text links at top of page that disappear when any of the links in the lower three rows are pressed -->

  .fixed-row {
    display: flex;
    justify-content: center; /* Center the links horizontally */
    top: 0;
    left: 0;
    width: 100%;
    background-color: #f1f1f1;
    padding: 10px;
    z-index: 10000;}

.fixed-row a {
    margin-right: 20px;
    text-decoration: none;
    color: #000;
    font-weight: bold;}

<!-- Single row of text links at top of page that disappear when the three rows below it rise --!> 
 <div class="fixed-row">
    <a href="index.html">Page One</a>
    <a href="two.html">Page Two</a>
    <a href="three.html">Page Three</a>
    <a href="main/four.html">Page Four</a>
</div>

I shifted the position of the styles, shifted the position of the "top" anchor and neither worked. I also altered z-index settings, that did not work either.


Solution

  • As for why <a href="#top"> is acting like <a href="#"> and automatically going to the top of the page without something like id="top" being set anywhere, that's new to me. Perhaps it's a newer browser feature/recommendation/expectation.

    <div class="header"> has position: sticky; top: 0;, therefore it "sticks" to the top of the viewport when scrolling.

    <div class="fixed-row"> does not have position declared, therefore it defaults to "static" and scrolls out of view. The top and z-index declarations have no effect because the element is static.

    1. Declare position: sticky for .fixed-row
    2. Calculate the top value for .header by adding the combined top and bottom padding declared for .fixed-row to the height of one line of text.
      Ideally, you'd use 1lh for the value of 1 line-height. Disappointingly, Firefox does not support the lh unit. Can I use lh? However, I find line-height to be 1.125 times the font-size, which is easily represented with the em unit.
    .fixed-row {
      position: sticky;
    }
    
    .header {
      top: calc(1.125em + 20px);
    }
    

    .fixed-row {
      position: sticky;
      top: 0;
      display: flex;
      justify-content: center;
      width: 100%;
      background-color: #f1f1f1;
      padding: 10px;
    }
    
    .fixed-row a {
      margin-right: 20px;
      text-decoration: none;
      color: #000;
      font-weight: bold;
    }
    
    .header {
      position: sticky;
      top: calc(1.125em + 20px);
      width: 100%;
      background-color: #f1f1f1;
      padding: 10px;
      text-align: center;
    }
    
    .header-row {
      display: flex;
      justify-content: center;
      margin-bottom: 10px;
    }
    
    
    
    body {
      margin: 0;
    }
    
    div.content {
      height: 100vh;
      background: silver;
    }
    <div class="fixed-row">
      <a href="index.html">Page One</a>
      <a href="two.html">Page Two</a>
      <a href="three.html">Page Three</a>
      <a href="main/four.html">Page Four</a>
    </div>
    
    <div class="header">
      <div class="header-row">
        <a href="#text1">One</a>
        <a href="#text2">Two</a>
        <a href="#text3">Three</a>
        <a href="#text4">Four</a>
      </div>
    
      <div class="header-row">
        <a href="#text5">Five</a>
        <a href="#text6">Six</a>
        <a href="#text7">Seven</a>
        <a href="#text8">Eight</a>
      </div>
    
      <div class="header-row">
        <a href="#top">Return to table of contents</a>
      </div>
    </div>
    
    
    <div class="content">Content</div>


    This can still cause issues on very narrow viewports when the text wraps into two lines. It would be better to nest the two sections into one sticky parent section.

    nav {
      position: sticky;
      top: 0;
    }
    
    .fixed-row {
      display: flex;
      justify-content: center;
      width: 100%;
      background-color: #f1f1f1;
      padding: 10px;
    }
    
    .fixed-row a {
      margin-right: 20px;
      text-decoration: none;
      color: #000;
      font-weight: bold;
    }
    
    .header {
      width: 100%;
      background-color: #f1f1f1;
      padding: 10px;
      text-align: center;
    }
    
    .header-row {
      display: flex;
      justify-content: center;
      margin-bottom: 10px;
    }
    
    
    
    body {
      margin: 0;
    }
    
    div.content {
      height: 100vh;
      background: silver;
    }
    <nav>
      <div class="fixed-row">
        <a href="index.html">Page One</a>
        <a href="two.html">Page Two</a>
        <a href="three.html">Page Three</a>
        <a href="main/four.html">Page Four</a>
      </div>
    
      <div class="header">
        <div class="header-row">
          <a href="#text1">One</a>
          <a href="#text2">Two</a>
          <a href="#text3">Three</a>
          <a href="#text4">Four</a>
        </div>
    
        <div class="header-row">
          <a href="#text5">Five</a>
          <a href="#text6">Six</a>
          <a href="#text7">Seven</a>
          <a href="#text8">Eight</a>
        </div>
    
        <div class="header-row">
          <a href="#top">Return to table of contents</a>
        </div>
      </div>
    </nav>
    
    <div class="content">Content</div>