You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

滚动时导航高亮及滚动加载项目的 Portfolio 网站开发求助

Solution for Your Single-Page Portfolio Site Features

Hey there! Let's break down how to implement those two key features for your long-scroll portfolio—they'll make your site feel polished and performant.


The best way to handle this smoothly (without jank) is using the Intersection Observer API—it's way more efficient than listening to scroll events directly. Here's how to set it up:

Step 1: Basic HTML Structure

Make sure your navigation links point to the id of each project section:

<nav class="navbar">
  <a href="#project1" class="nav-link">Project 1</a>
  <a href="#project2" class="nav-link">Project 2</a>
  <a href="#project3" class="nav-link">Project 3</a>
</nav>

<section id="project1" class="project-section">...</section>
<section id="project2" class="project-section">...</section>
<section id="project3" class="project-section">...</section>

Step 2: CSS for Highlight State

Define your default (gray) and active (blue) styles:

.nav-link {
  color: #888; /* Default gray */
  transition: color 0.3s ease;
}

.nav-link.active {
  color: #007bff; /* Active blue */
}

Step 3: JavaScript with Intersection Observer

This will watch each project section and update the navigation when it enters the viewport:

// Get all project sections and navigation links
const sections = document.querySelectorAll('.project-section');
const navLinks = document.querySelectorAll('.nav-link');

// Set up the observer
const observerOptions = {
  root: null, // Use the viewport as the root
  rootMargin: '-20% 0px -70% 0px', // Trigger when section is 20% from top
  threshold: 0.1
};

const observer = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      // Get the section's id
      const sectionId = entry.target.getAttribute('id');
      // Remove active class from all links
      navLinks.forEach(link => link.classList.remove('active'));
      // Add active class to the corresponding link
      const activeLink = document.querySelector(`.nav-link[href="#${sectionId}"]`);
      if (activeLink) activeLink.classList.add('active');
    }
  });
}, observerOptions);

// Observe each section
sections.forEach(section => observer.observe(section));

Adjust the rootMargin values to tweak when the highlight triggers—this setup starts highlighting when the section is 20% from the top of the viewport, which feels natural for most scroll experiences.


2. Hide Projects Until They Scroll Into View

Again, Intersection Observer is perfect here. We'll hide projects by default and reveal them when they enter the viewport (with a nice fade-in animation for extra flair):

Step 1: CSS for Hidden/Revealed States

.project-section {
  opacity: 0;
  transform: translateY(20px); /* Optional: slide up when revealing */
  transition: opacity 0.6s ease, transform 0.6s ease;
}

.project-section.revealed {
  opacity: 1;
  transform: translateY(0);
}

Step 2: Update the Intersection Observer

Modify the observer we created earlier to handle the reveal, or set up a separate one (I'll combine them for simplicity):

const observer = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      // Reveal the section
      entry.target.classList.add('revealed');
      
      // ... keep the navigation highlight code from earlier here
      const sectionId = entry.target.getAttribute('id');
      navLinks.forEach(link => link.classList.remove('active'));
      const activeLink = document.querySelector(`.nav-link[href="#${sectionId}"]`);
      if (activeLink) activeLink.classList.add('active');
      
      // Optional: Stop observing once revealed to save resources
      observer.unobserve(entry.target);
    }
  });
}, observerOptions);

Now your projects will stay hidden (with opacity 0) until they scroll into the viewport, then smoothly fade in. The transform adds a subtle slide-up effect, but you can remove that if you prefer a simple fade.


Quick Notes

  • If you need to support older browsers (like IE11), you'll need a polyfill for Intersection Observer—you can find one on npm or CDNs.
  • Test the rootMargin values on different screen sizes to make sure the highlight and reveal triggers feel right for your layout.

Hope this gets your portfolio site working exactly how you want it!

内容的提问来源于stack exchange,提问作者EmmaKing

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 03:56:02