css scroll-snap: highlighting the snapped element

I created a horizontal grid containing multiple cards that scroll smoothly using CSS scroll-snap functionality when navigated with a mouse or touchscreen.

The issue arises when attempting to navigate the grid using a keyboard. After moving through the grid with arrow keys, pressing tab causes the view to jump back to the element that received focus, rather than staying on the currently snapped card.

My desired outcome is for tab to focus on the card that is currently in view.

Does anyone have any suggestions on how to achieve this?

Answer №1

From what I can see, there doesn't seem to be a built-in way to handle this at the moment. However, Nils Schwebel's solution may not be the most elegant, but it appears to be the most effective approach.

Below is a functional demonstration:

Keep in mind that I've added some extra styling for clarity, so you might have to extract the relevant sections after testing.

const main = document.getElementById("Main"),
  sections = document.getElementsByClassName("section");

main.addEventListener('scroll', (e) => {
  // Get the current scroll position (top of the viewport)
  let pos = main.scrollTop;
  for (let i = 0, l = sections.length; i < l; i++) {
    // Calculate the position of the middle of the viewport within the section (adjust if snap items are not full-height)
    let relativePos = sections[i].offsetTop - pos + (sections[i].offsetHeight / 2);
    // Check if the calculated point falls within the section
    if (relativePos >= 0 && relativePos < sections[i].offsetHeight) {
      sections[i].focus();
      break;
    }
  }
});
body {
  margin: unset;
}

main {
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
  justify-content: center;
  width: 100%;
  height: 100vh;
  background-color: #222;
  overflow-y: auto;
  scroll-snap-type: y mandatory;
}

section {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100vh;
  scroll-snap-align: center;
}

section:focus {
  border: none;
  outline: none;
}

#s1 {
  background-color: #d72748;
}

#s2 {
  background-color: #b51f7e;
}

#s3 {
  background-color: #e64869;
}

#s4 {
  background-color: #e79946;
}

section h2 {
  color: white;
}
<main id="Main">
  <section class="section" id="s1" tabindex="1" aria-labelledby="a1">
    <h2 id="a1">AREA 1</h2>
  </section>
  <section class="section" id="s2" tabindex="1" aria-labelledby="a3">
    <h2 id="a2">AREA 2</h2>
  </section>
  <section class="section" id="s3" tabindex="1" aria-labelledby="a2">
    <h2 id="a3">AREA 3</h2>
  </section>
  <section class="section" id="s4" tabindex="1" aria-labelledby="a4">
    <h2 id="a4">AREA 4</h2>
  </section>
</main>

Answer №2

To detect if an element is at the top of a scroll view, you can implement a scroll listener and perform the necessary checks. You could consider adapting one of the suggested solutions in this thread: How to check if element is visible after scrolling?

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Mastering the Art of Concise Writing: Tips to

Is there a way to write more concisely, maybe even in a single line? this.xxx = smt.filter(item => item.Id === this.smtStatus.ONE); this.yyy = smt.filter(item => item.Id === this.smtStatus.TWO); this.zzz = smt.filter(item => item.Id == ...

Changing the theme of a toggle button in Jquery Mobile when the button is pressed

I have a group of buttons with a specific class <div class="prog-day"> <div class="prog-clear" data-role="controlgroup" data-type="horizontal> <a href="#" data-role="button" data-mini="true" data-theme="b">Clear</a> ...

When using the require() function in Node.js, the period "." is not being recognized as part of the command and

I recently encountered a problem while working on my project and reorganizing my files. I noticed that the "." in my requires are not being parsed correctly. Upon running my program, an error message is displayed: Error: Module './src/map/createMa ...

The issue of page content failing to refresh when loaded using AJAX technology

My script utilizes AJAX to dynamically load specific pages on a website. These pages display information that updates based on the current time. However, I have encountered an issue where the page content remains static when loaded through AJAX, almost as ...

considering multiple website addresses as one collective entity for the Facebook like button

Currently, I am tackling an issue on a website that employs a custom CMS which automatically generates URLs based on the titles of articles. The main problem faced by our contributors is that when they update the title of an article, it creates a new URL ...

Passing state to getStaticProps in Next JSLearn how to effectively pass state

I am currently fetching games from IGDB database using getStaticProps and it's all working perfectly. However, I now have a new requirement to implement game searching functionality using a text input field and a button. The challenge I'm facing ...

Effortless Ways to Automatically Accept SSL Certificates in Chrome

It has been quite some time that I have been attempting to find a way to automatically accept SSL certificates. Unfortunately, I haven't had any success yet. The scenario is this: I am working on selenium tests and every time I run the test on Chrome, ...

Align text vertically next to an image

I am facing a challenge with aligning text vertically next to an image floated left. I have tried various solutions recommended on different platforms, but none seem to work for me. Despite following the suggestions provided in this particular solution, I ...

What causes the Vuetify checkbox to trigger twice when clicked in a Vue.js application?

I am facing an issue with a table that contains checkboxes in every row. I want to trigger some logic when a checkbox is clicked. In some cases, I need to tick multiple rows when a checkbox is clicked, so I have set the checkboxes as readonly and handle th ...

Modify the color scheme of the parent div by selecting the child div (using only CSS and HTML)

I am working with a nested div structure, where one is contained inside the other: <div class="outer"> <div class="inner"> </div> </div> It looks something like this: https://i.sstatic.net/r5qbD.png I ...

What is the best way to know which API will return the result the fastest?

If we were to make 2 API calls, each taking around 6ms to return JSON data, what would be the sequence in which they provide the resulting data? The official JavaScript documentation mentions using Promise.all to manage multiple API calls. ...

Ways to verify the application of CSS hyphens using Chrome's developer tools

I cannot seem to get automatic hyphens to work via CSS. I have applied the following CSS: body { -moz-hyphens: auto; -ms-hyphens: auto; -o-hyphens: auto; -webkit-hyphens: auto; hyphens: auto; } Despite adding this CSS, my text is not being hyph ...

Crushing jQuery's Sortable/Droppable

Having a little issue here. I want to be able to toggle the sortable plugin's behavior by clicking a button - basically switching between sort mode and view mode. I've attempted to achieve this with the following code: function enterSortMode(){ ...

Angular2 bootstrapping of multiple components

My query pertains to the following issue raised on Stack Overflow: Error when bootstrapping multiple angular2 modules In my index.html, I have included the code snippet below: <app-header>Loading header...</app-header> <app-root>L ...

What is the best way to design a group of radio buttons with corresponding labels at the top

I'm looking to create a structure like this in HTML: https://i.sstatic.net/wLcZs.png Does anyone know how I can achieve this layout so that the labels are aligned properly with the radio buttons? My main challenge is getting the horizontal labels ab ...

Change the classes of the body prior to the initial rendering

I know this may seem like a difficult task, and I understand that what I want to achieve might be nearly impossible. My goal is to incorporate a dark/light mode switch on my website. The challenge lies in the fact that the site consists of static files on ...

Is there a way to modify a specific key value in all embedded objects using Mongoose?

I'm currently working on a chat application and I'm facing a challenge with implementing the 'seen' functionality. I need to update all chat messages in the database by setting the 'seen' column to true. Here is the schema st ...

Web Browser cross-origin AJAX requests

Recently, I developed an Internet Explorer extension that injects a script every time a page is accessed. The purpose of this script is to send an AJAX request to my localhost. However, I have encountered a roadblock where the request only works if it&apos ...

What are effective ways to eliminate script tags from a webpage?

I have implemented tags on my website that users can use to interact with the site. My goal is to figure out how to make the browser only read text from a specific file I write, without any HTML. This should be restricted to certain sections of my websit ...

In a React application, adjusting the main container height to 100vh results in the window.scrollY position being set to

I was facing problems with flashing on the Safari/Firefox browsers. By setting the main container height to max-height: 100vh, I managed to resolve the flickering issue. However, I am also looking for a solution to keep track of the window.scrollY positi ...