Выделить элемент в указателе на основе видимого в данный момент содержимого во время прокрутки

На моей html-странице у меня есть оглавление с атрибутом CSS position: fixed;, и я хотел бы выделить (жирным или курсивом) текущую позицию чтения / отображения при прокрутке страницы.

                             | yada yada yada ...
1. Section 1                 |
 1.1 Subsection 1            | 1.2 Subsection 2
 1.2 Subsection 2 <-- bold   |   
2. Section 2                 | Lorem ipsum dolor sit amet,
[...]                        | consectetur adipisici elit
                             | [...]

Я хотел бы, чтобы это было просто, а CSS - если это вообще возможно - предпочтительнее JS. Сайт создается Hugo, но ответ не обязательно должен быть конкретным для Hugo.

Большое спасибо!


P.s. В случае конкретного ответа Хьюго: токен генерируется с использованием {{ partial "table-of-contents" . }}

table-of-contents.html

<!-- ignore empty links with + -->
{{ $headers := findRE "<h[1-6].*?>(.|\n])+?</h[1-6]>" .Content }}
<!-- at least one header to link to -->
{{ $has_headers := ge (len $headers) 1 }}
<!-- a post can explicitly disable Table of Contents with toc: false -->
{{ $show_toc := (eq $.Params.toc true) }}
{{ if and $has_headers $show_toc }}
<div class="table-of-contents toc bd-callout">
    <!-- TOC header -->
    <h4 class="text-muted">Table of Contents</h4>
    {{ range $headers }}
        {{ $header := . }}
        {{ range first 1 (findRE "<h[1-6]" $header 1) }}
            {{ range findRE "[1-6]" . 1 }}
                {{ $next_heading := (int .) }}
                <!-- generate li array of the proper depth -->
                {{ range seq $next_heading }}
                    <ul class="toc-h{{ . }}">
                {{end}}
                {{ $base := ($.Page.File.LogicalName) }}
                {{ $anchorId := ($header | plainify | htmlEscape | urlize) }}
                {{ $href := delimit (slice $base $anchorId) "#" | string }}
                <a href="{{ relref $.Page $href }}">
                    <li>{{ $header | plainify | htmlEscape }}</li>
                </a>
                <!-- close list -->
                {{ range seq $next_heading }}
                    </ul>
                {{end}}
            {{end}}
        {{end}}
    {{ end }}
</div>
{{ end }}

person Suuuehgi    schedule 21.04.2018    source источник


Ответы (1)


В scroll вы можете отслеживать видимость ваших заголовков контента, если элементы заголовка и индекса вашего контента имеют атрибуты id или data в соглашении об именах.

Затем тот, который виден, вы можете найти в индексе, используя соглашение об именах, и добавить к нему класс выделения.

Вот рабочий пример: https://jsfiddle.net/az6z8rze/24/

Настоящая уловка здесь - это функция isElementInViewport. Вы можете использовать его как и легко адаптировать упрощенный пример для вложенного индекса.

function isElementInViewport (el) {
    
    //special bonus for those using jQuery
    if (typeof $ === "function" && el instanceof $) {
        el = el[0];
    }
		
    var rect     = el.getBoundingClientRect(),
        vWidth   = window.innerWidth || doc.documentElement.clientWidth,
        vHeight  = window.innerHeight || doc.documentElement.clientHeight,
        efp      = function (x, y) { return document.elementFromPoint(x, y) };     

    // Return false if it's not in the viewport
    if (rect.right < 0 || rect.bottom < 0 
            || rect.left > vWidth || rect.top > vHeight)
        return false;

    // Return true if any of its four corners are visible
    return (
          el.contains(efp(rect.left,  rect.top))
      ||  el.contains(efp(rect.right, rect.top))
      ||  el.contains(efp(rect.right, rect.bottom))
      ||  el.contains(efp(rect.left,  rect.bottom))
    );
}


var handler = function(){
  var visible = 0;
  [1,2,3,4].forEach(function(id){
    if(isElementInViewport($('#'+id))) visible = id;
  })
  
  if(visible){
  	$('#index div').removeClass('active');
    $('#index-'+visible).addClass('active');
  }
};



//jQuery
$(window).on('DOMContentLoaded load resize scroll', handler);
#index{
  width: 100%;
  position: fixed;
  top:0;
  left:0;
  background: white;
}

.active{
  font-weight: bold;
  color: green;
}

#content{
  padding-top: 90px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div id="index">
  <div id="index-1">Section One</div>
  <div id="index-2">Section Two</div>
  <div id="index-3">Section Three</div>
  <div id="index-4">Section Four</div>
</div>

<div id="content">
  <div id="1">
    <h1>Section 1</h1>
    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ipsum quisquam inventore, magnam maxime explicabo maiores reiciendis, repellendus soluta necessitatibus, vero recusandae! Delectus minima, dolore necessitatibus autem. Eveniet harum, asperiores obcaecati.
    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Velit blanditiis suscipit delectus aut neque libero ducimus corporis, cum ipsum a, vitae sed aperiam doloribus quos accusamus harum rem hic totam?
    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Perferendis, inventore eligendi sed quam omnis ipsam nesciunt quis debitis dignissimos natus molestias rem eos! Fugiat voluptates a nam laudantium porro quisquam!
  </div>
  
    <div id="2">
    <h1>Section Two</h1>
    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ipsum quisquam inventore, magnam maxime explicabo maiores reiciendis, repellendus soluta necessitatibus, vero recusandae! Delectus minima, dolore necessitatibus autem. Eveniet harum, asperiores obcaecati.
    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Velit blanditiis suscipit delectus aut neque libero ducimus corporis, cum ipsum a, vitae sed aperiam doloribus quos accusamus harum rem hic totam?
    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Perferendis, inventore eligendi sed quam omnis ipsam nesciunt quis debitis dignissimos natus molestias rem eos! Fugiat voluptates a nam laudantium porro quisquam!
  </div>
  
    <div id="3">
    <h1>Section Three</h1>
    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ipsum quisquam inventore, magnam maxime explicabo maiores reiciendis, repellendus soluta necessitatibus, vero recusandae! Delectus minima, dolore necessitatibus autem. Eveniet harum, asperiores obcaecati.
    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Velit blanditiis suscipit delectus aut neque libero ducimus corporis, cum ipsum a, vitae sed aperiam doloribus quos accusamus harum rem hic totam?
    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Perferendis, inventore eligendi sed quam omnis ipsam nesciunt quis debitis dignissimos natus molestias rem eos! Fugiat voluptates a nam laudantium porro quisquam!
  </div>
  
    <div id="4">
    <h1>Section Four</h1>
    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ipsum quisquam inventore, magnam maxime explicabo maiores reiciendis, repellendus soluta necessitatibus, vero recusandae! Delectus minima, dolore necessitatibus autem. Eveniet harum, asperiores obcaecati.
    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Velit blanditiis suscipit delectus aut neque libero ducimus corporis, cum ipsum a, vitae sed aperiam doloribus quos accusamus harum rem hic totam?
    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Perferendis, inventore eligendi sed quam omnis ipsam nesciunt quis debitis dignissimos natus molestias rem eos! Fugiat voluptates a nam laudantium porro quisquam!
  </div>
</div>

Кредиты: isElementInViewport ответ взят из этого ответа

person Shaunak    schedule 21.04.2018