【问题标题】:Change style header/nav with Intersection Observer (IO)使用 Intersection Observer (IO) 更改样式标题/导航
【发布时间】:2019-09-07 13:24:38
【问题描述】:

Fiddle latest


我从scroll event 方法开始这个问题,但由于使用IntersectionObserver 的建议,这似乎是更好的方法,我试图让它以这种方式工作。


目标是什么:

我想更改header 的样式(color+background-color),具体取决于通过寻找(我在想?)它的@ 观察到的当前div/section 987654329@ 或 data 将覆盖默认的 header 样式(black on white)。


标题样式:

font-color:

根据内容 (div/section),默认 header 应该能够将 font-color 更改为仅两种可能的颜色:

  • 黑色
  • 白色

background-color:

根据内容的不同,background-color 可以有无限的颜色或透明,所以最好单独解决,这些可能是最常用的背景颜色:

  • 白色(默认)
  • 黑色
  • 没有颜色(透明)

CSS:

header {
  position: fixed;
  width: 100%;
  top: 0;
  line-height: 32px;
  padding: 0 15px;
  z-index: 5;
  color: black; /* default */
  background-color: white; /* default */
}

带有默认标题的 Div/section 示例,内容没有变化:

<div class="grid-30-span g-100vh">
    <img 
    src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1.414 1'%3E%3C/svg%3E"
    data-src="/images/example_default_header.jpg" 
    class="lazyload"
    alt="">
</div>

Div/section 示例更改内容标题:

<div class="grid-30-span g-100vh" data-color="white" data-background="darkblue">
    <img 
    src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1.414 1'%3E%3C/svg%3E"
    data-src="/images/example_darkblue.jpg" 
    class="lazyload"
    alt="">
</div>

<div class="grid-30-span g-100vh" data-color="white" data-background="black">
    <img 
    src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1.414 1'%3E%3C/svg%3E"
    data-src="/images/example_black.jpg" 
    class="lazyload"
    alt="">
</div>

交叉口观察者方法:

var mq = window.matchMedia( "(min-width: 568px)" );
if (mq.matches) {
  // Add for mobile reset

document.addEventListener("DOMContentLoaded", function(event) { 
  // Add document load callback for leaving script in head
  const header = document.querySelector('header');
  const sections = document.querySelectorAll('div');
  const config = {
    rootMargin: '0px',
    threshold: [0.00, 0.95]
  };

  const observer = new IntersectionObserver(function (entries, self) {
    entries.forEach(entry => {
      if (entry.isIntersecting) {
        if (entry.intersectionRatio > 0.95) {
          header.style.color = entry.target.dataset.color !== undefined ? entry.target.dataset.color : "black";
          header.style.background = entry.target.dataset.background !== undefined ? entry.target.dataset.background : "white";   
        } else {
        if (entry.target.getBoundingClientRect().top < 0 ) {
          header.style.color = entry.target.dataset.color !== undefined ? entry.target.dataset.color : "black";
          header.style.background = entry.target.dataset.background !== undefined ? entry.target.dataset.background : "white";
          }
        } 
      }
    });
  }, config);

  sections.forEach(section => {
    observer.observe(section);
  });

});

}

【问题讨论】:

  • 你的问题不够清楚。 When entering a page and content (div) has header class added it only changes just after scrolling, but it should change the header directly on entering the page. 当页面加载时,您希望页眉背景和文本是什么颜色?你预计它什么时候会改变,变成什么颜色?
  • With absolutely none class determined the background of default header turns or stays transparent after scrolling. 我完全不明白这意味着什么。请指定预期的行为以及它与当前行为的不同之处(尤其是颜色,因为这似乎是这里的主要问题)。
  • 当您打开项目页面时,您会在某些情况下看到内容(大多数图像设置为 100% 宽度和 100vh 高度),我想添加一个适合内容的类,以便标题/导航保持不变可见,但我现在拥有的代码仅在滚动后才会将标题/导航更改为类
  • 它需要在打开页面时读取类,知道要更改标题,然后滚动部分发生,所以当离开该内容时,它返回到默认标题设置黑色在白色背景上而不是黑色透明现在发生的事情。
  • 在小提琴中你会看到一个例子:第二部分(section-grey)没有确定类但没有完全返回到默认的标题 css 设置

标签: javascript html css intersection-observer


【解决方案1】:

您应该看看Intersection Observer (IO),而不是听滚动事件。 这是为了解决像你这样的问题。而且它比监听滚动事件然后自己计算位置要高效得多。

首先,here is a codepen 显示了您的问题的解决方案。 我不是这个 codepen 的作者,我可能会做一些不同的事情,但它肯定会向您展示如何解决问题的基本方法。

我会改变的事情:您可以在示例中看到,如果您将 99% 的速度滑到一个新部分,标题会发生变化,即使新部分也不会完全可见。

现在不碍事,一些解释它是如何工作的(注意,我不会盲目地从 codepen 复制粘贴,我也会将 const 更改为 let,但使用更适合您的项目的任何内容。

首先,您必须指定 IO 的选项:

let options = {
  rootMargin: '-50px 0px -55%'
}

let observer = new IntersectionObserver(callback, options);

在示例中,一旦元素距离进入视图 50 像素,IO 就会执行回调。我不能从头顶推荐一些更好的值,但如果我有时间,我会尝试调整这些参数,看看是否能得到更好的结果。

在他们定义内联回调函数的 codepen 中,我只是这样写,以便更清楚地知道发生了什么。

IO 的下一步是定义一些要观察的元素。在您的情况下,您应该为您的 div 添加一些类,例如 &lt;div class="section"&gt;

let entries = document.querySelectorAll('div.section');
entries.forEach(entry => {observer.observe(entry);})

最后你要定义回调函数:

entries.forEach(entry => {
    if (entry.isIntersecting) {
     //specify what should happen if an element is coming into view, like defined in the options. 
    }
  });

编辑:正如我所说,这只是一个让您入门的示例,它不是您复制粘贴的完整解决方案。在基于可见部分的 ID 的示例中,当前元素被突出显示。您必须更改此部分,以便根据您在元素上设置的某些属性设置颜色和背景颜色,而不是将活动类设置为例如第三个元素。我建议使用data attributes

编辑 2: 当然你可以继续只使用滚动事件,来自 W3C 的 the official Polyfill 使用滚动事件来模拟旧浏览器的 IO。只是监听滚动事件和计算位置不是高性能,尤其是在有多个元素的情况下。所以如果你关心用户体验,我真的推荐使用 IO。只是想添加此答案以显示此类问题的现代解决方案是什么。

编辑 3: 我花时间创建了一个基于 IO 的示例,这应该可以帮助您入门。

基本上我定义了两个阈值:一个是 20%,一个是 90%。如果元素在视口中占 90%,则可以假设它将覆盖标题。所以我将标题的类设置为视图中 90% 的元素。

第二个阈值是 20%,这里我们必须检查元素是从顶部还是从底部进入视图。如果它从顶部可见 20%,那么它将与标题重叠。

调整这些值并调整您所看到的逻辑。

const sections = document.querySelectorAll('div');
const config = {
  rootMargin: '0px',
  threshold: [.2, .9]
};

const observer = new IntersectionObserver(function (entries, self) {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      var headerEl = document.querySelector('header');
      if (entry.intersectionRatio > 0.9) {
        //intersection ratio bigger than 90%
        //-> set header according to target
        headerEl.className=entry.target.dataset.header;      
      } else {
        //-> check if element is coming from top or from bottom into view
        if (entry.target.getBoundingClientRect().top < 0 ) {
          headerEl.className=entry.target.dataset.header;
        }
      } 
    }
  });
}, config);

sections.forEach(section => {
  observer.observe(section);
});
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}

.g-100vh {
height: 100vh
}

header {
  min-height: 50px;
  position: fixed;
  background-color: green;
  width: 100%;
}
  
header.white-menu {
  color: white;
  background-color: black;
}

header.black-menu {
  color: black;
  background-color: white;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>


<header>
 <p>Header Content </p>
</header>
<div class="grid-30-span g-100vh white-menu" style="background-color:darkblue;" data-header="white-menu">
    <img 
    src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1.414 1'%3E%3C/svg%3E"
    data-src="/images/example_darkblue.jpg" 
    class="lazyload"
    alt="<?php echo $title; ?>">
</div>

<div class="grid-30-span g-100vh black-menu" style="background-color:lightgrey;" data-header="black-menu">
    <img 
    src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1.414 1'%3E%3C/svg%3E"
    data-src="/images/example_lightgrey.jpg" 
    class="lazyload"
    alt="<?php echo $title; ?>">
</div>

【讨论】:

  • 首先感谢您抽出宝贵时间提供帮助,但是您刚刚向我展示的 codepen 示例并不是我真正想要的,它适用于导航选项卡选择,我不需要那个.如果内容添加了类,则只需标题/导航在滚动时更改类并在打开页面时收听类。并在根本没有添加任何类时显示默认标题。
  • 您不必使用导航标签,也可以只更改整个导航栏。在 codepen 中,它检查 active 类,并根据可见的元素突出显示当前部分。您可以跳过这部分并根据可见的部分更改颜色。我会将这部分编辑到我的答案中。
  • 它在我的情况下不起作用,放置在我的标题中的所有导航的颜色和背景仅由一个“类”(标题)决定。在您的方法中,例如,当内容很暗并且我需要标题/导航在透明背景上为白色时,这是不可能的,因为它侦听为每个列表项设置的 data-ref 似乎对于我需要的东西来说是全面的。
  • 完全可以,你可以根据自己的具体需要调整逻辑。你知道哪个元素正在进入视野,你可以随心所欲地对其做出反应。检查它的类名或其他一些属性,无论你需要什么,并相应地设置你的颜色。如果页面已经滚动,IO 还可以解决您在页面加载时设置正确颜色的问题。
  • 当我在内容上使用 data-ref="white-menu" 并将 id 设置为整个标题/导航而不是每个列表项时,我可能只能使用一个类(在这种情况下为 id)来更改其外观,因为当我将它设置为 data-ref="black-menu"` 时,我需要黑色透明取决于它不听的内容,因为标题已经有一个只听白色菜单的 id
【解决方案2】:

我可能不完全理解这个问题,但至于你的例子 - 你可以通过使用 mix-blend-mode css 属性来解决它,而根本不使用 javascript。

例子:

header {background: white; position: relative; height: 20vh;}
header h1 {
  position: fixed;
  color: white;
  mix-blend-mode: difference;
}
div {height: 100vh; }
<header>
  <h1>StudioX, Project Title, Category...</h1>
</header>
<div style="background-color:darkblue;"></div>
<div style="background-color:lightgrey;"></div>

【讨论】:

  • 这可能是个好主意,但在极少数情况下会使用它。例如,如果您只希望标题从黑色变为白色,则无论部分颜色是什么。
  • @QuentinD 这不是 OP 最初试图做的吗...?
  • "根据内容的不同,背景颜色可以有无限的颜色或者是透明的"所以如果背景颜色是红色,标题就不能是黑色或白色
  • 正如我在这个答案中开始的那样:“我可能不完全理解这个问题,但至于你的例子......”你可以想象这个问题从被问到的那一刻起就有几个编辑- 等等,你不需要想象 - 你可以点击弯曲的箭头......无论如何,谢谢你的评论(和反对票) - 我会尽力在未来的答案上做到最好。保重。
【解决方案3】:

我遇到过同样的情况,我实现的解决方案非常精确,因为它不依赖于百分比,而是依赖于真实元素的边界框:

class Header {
  constructor() {
    this.header = document.querySelector("header");
    this.span = this.header.querySelector('span');
    this.invertedSections = document.querySelectorAll(".invertedSection");

    window.addEventListener('resize', () => this.resetObserver());

    this.resetObserver();
  }

  resetObserver() {
    if (this.observer) this.observer.disconnect();

    const {
      top,
      height
    } = this.span.getBoundingClientRect();

    this.observer = new IntersectionObserver(entries => this.observerCallback(entries), {
        root: document,
      rootMargin: `-${top}px 0px -${window.innerHeight - top - height}px 0px`,
    });

    this.invertedSections.forEach((el) => this.observer.observe(el));
  };

  observerCallback(entries) {
    let inverted = false;
    entries.forEach((entry) => {
      if (entry.isIntersecting) inverted = true;
    });
    if (inverted) this.header.classList.add('inverted');
    else this.header.classList.remove('inverted');
  };
}

new Header();
header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  padding: 20px 0;
  text-transform: uppercase;
  text-align: center;
  font-weight: 700;
}
header.inverted {
  color: #fff;
}

section {
  height: 500px;
}
section.invertedSection {
  background-color: #000;
}
<body>
  <header>
    <span>header</span>
  </header>
  <main>
    <section></section>
    <section class="invertedSection"></section>
    <section></section>
    <section class="invertedSection"></section>
  </main>
</body>

它的作用其实很简单:我们不能使用 IntersectionObserver 知道header 和其他元素何时交叉(因为root 必须是被观察元素的父元素),但我们可以计算出header 的位置和大小将rootMargin 添加到观察者。

有时,标题比它的内容高(因为填充和其他东西)所以我计算标题中span 的边界框(我希望它只有在 this em> 元素与黑色部分重叠)。

因为窗口的高度可以改变,我必须在窗口调整大小时重置 IntersectionObserver。

这里root属性设置为document是因为sn-p的iframe限制(否则你可以不定义这个字段)。

使用rootMargin,我指定我希望观察者在哪个区域寻找交叉点。

然后我观察每个黑色部分。在回调函数中,我定义了 至少一个 部分是否重叠,如果这是真的,我在标题中添加一个inverted className。

如果我们可以在rootMargin 属性中使用像calc(100vh - 50px) 这样的值,我们可能不需要使用resize 监听器。

我们甚至可以通过添加侧 rootMargin 来改进这个系统,例如,如果我的黑色部分只有窗口宽度的一半,并且可能与标题中的跨度相交,也可能不相交,具体取决于其水平位置。

【讨论】:

  • 感谢分享你的魔法!
【解决方案4】:

@昆汀 D

我在互联网上搜索了类似的内容,发现此代码是满足我需求的最佳解决方案。

因此我决定在它的基础上创建一个通用的“观察者”类,它可以在许多需要 IntesectionObserver 的情况下使用,包括更改标题样式。 我没有对它进行太多测试,仅在一些基本情况下,它对我有用。我没有在有水平滚动的页面上测试过。

以这种方式使用它很容易,只需将其保存为 .js 文件并将其包含/导入到您的代码中,就像插件一样。 :) 我希望有人会觉得它有用。

如果有人找到更好的想法(尤其是对于“横向”网站),很高兴在这里看到它们。

编辑:我没有做出正确的“未观察”,所以我修正了它。

/* The Intersection Observer API provides a way to asynchronously observe changes in the intersection of a target element with an ancestor element or with a top-level document's viewport.

ROOT:
It is not necessary for the root to be the ancestor element of the target. The root is allways the document, and the so-called root element is used only to get its size and position, to create an area in the document, with options.rootMargin.
Leave it false to have the viewport as root.

TARGET:
IntersectionObserver triggers when the target is entering at the specified ratio(s), and when it exits at the same ratio(s).

For more on IntersectionObserverEntry object, see:
https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API#targeting_an_element_to_be_observed

IntersectionObserverEntry.time               // Timestamp when the change occurred
IntersectionObserverEntry.rootBounds         // Unclipped area of root
IntersectionObserverEntry.intersectionRatio  // Ratio of intersectionRect area to boundingClientRect area
IntersectionObserverEntry.target             // the Element target
IntersectionObserverEntry.boundingClientRect // target.boundingClientRect()
IntersectionObserverEntry.intersectionRect   // boundingClientRect, clipped by its containing block ancestors, and intersected with rootBounds

THRESHOLD:
Intersection ratio/threshold can be an array, and then it will trigger on each value, when in and when out.
If root element's size, for example, is only 10% of the target element's size, then intersection ratio/threshold can't be set to more than 10% (that is 0.1).

CALLBACKS:
There can be created two functions; when the target is entering and when it's exiting. These functions can do what's required for each event (visible/invisible).
Each function is passed three arguments, the root (html) element, IntersectionObserverEntry object, and intersectionObserver options used for that observer.

Set only root and targets to only have some info in the browser's console.

For more info on IntersectionObserver see: https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API

Polyfill: <script src="https://polyfill.io/v3/polyfill.js?features=IntersectionObserver"></script>
or:
https://github.com/w3c/IntersectionObserver/tree/main/polyfill


Based on answer by Quentin D, answered Oct 27 '20 at 12:12
https://stackoverflow.com/questions/57834100/change-style-header-nav-with-intersection-observer-io

root     - (any selector) - root element, intersection parent (only the first element is selected).
targets  - (any selector) - observed elements that trigger function when visible/invisible.
inCb     - (function name) - custom callback function to trigger when the target is intersecting.
outCb    - (function name) - custom callback function to trigger when the target is not intersecting.
thres    - (number 0-1) - threshold to trigger the observer (e.g. 0.1 will trigger when 10% is visible).
unobserve- (bolean) - if true, the target is unobserved after triggering the callback.

EXAMPLE:
(place in 'load' event listener, to have the correct dimensions)

var invertedHeader = new Observer({
   root: '.header--main', // don't set to have the viewport as root
   targets: '[data-bgd-dark]',
   thres: [0, .16],
   inCb: someCustomFunction,
});
*/

class Observer {
   constructor({
      root = false,
      targets = false,
      inCb = this.isIn,
      outCb = this.isOut,
      thres = 0,
      unobserve = false,
   } = {}) {
      // this element's position creates with rootMargin the area in the document
      // which is used as intersection observer's root area.
      // the real root is allways the document.
      this.area = document.querySelector(root); // intersection area
      this.targets = document.querySelectorAll(targets); // intersection targets
      this.inCallback = inCb; // callback when intersecting
      this.outCallback = outCb; // callback when not intersecting
      this.unobserve = unobserve; // unobserve after intersection
      this.margins; // rootMargin for observer
      this.windowW = document.documentElement.clientWidth;
      this.windowH = document.documentElement.clientHeight;

      // intersection is being checked like:
      // if (entry.isIntersecting || entry.intersectionRatio >= this.ratio),
      // and if ratio is 0, "entry.intersectionRatio >= this.ratio" will be true,
      // even for non-intersecting elements, therefore:
      this.ratio = thres;
      if (Array.isArray(thres)) {
         for (var i = 0; i < thres.length; i++) {
            if (thres[i] == 0) {
               this.ratio[i] = 0.0001;
            }
         }
      } else {
         if (thres == 0) {
            this.ratio = 0.0001;
         }
      }

      // if root selected use its position to create margins, else no margins (viewport as root)
      if (this.area) {
         this.iArea = this.area.getBoundingClientRect(); // intersection area
         this.margins = `-${this.iArea.top}px -${(this.windowW - this.iArea.right)}px -${(this.windowH - this.iArea.bottom)}px -${this.iArea.left}px`;
      } else {
         this.margins = '0px';
      }

      // Keep this last (this.ratio has to be defined before).
      // targets are required to create an observer.
      if (this.targets) {
         window.addEventListener('resize', () => this.resetObserver());
         this.resetObserver();
      }
   }

   resetObserver() {
      if (this.observer) this.observer.disconnect();

      const options = {
         root: null, // null for the viewport
         rootMargin: this.margins,
         threshold: this.ratio,
      }

      this.observer = new IntersectionObserver(
         entries => this.observerCallback(entries, options),
         options,
      );

      this.targets.forEach((target) => this.observer.observe(target));
   };

   observerCallback(entries, options) {
      entries.forEach(entry => {
         // "entry.intersectionRatio >= this.ratio" for older browsers
         if (entry.isIntersecting || entry.intersectionRatio >= this.ratio) {
            // callback when visible
            this.inCallback(this.area, entry, options);

            // unobserve
            if (this.unobserve) {
               this.observer.unobserve(entry.target);
            }
         } else {
            // callback when hidden
            this.outCallback(this.area, entry, options);
            // No unobserve, because all invisible targets will be unobserved automatically
         }
      });
   };

   isIn(rootElmnt, targetElmt, options) {
      if (!rootElmnt) {
         console.log(`IO Root: VIEWPORT`);
      } else {
         console.log(`IO Root: ${rootElmnt.tagName} class="${rootElmnt.classList}"`);
      }
      console.log(`IO Target: ${targetElmt.target.tagName} class="${targetElmt.target.classList}" IS IN (${targetElmt.intersectionRatio * 100}%)`);
      console.log(`IO Threshold: ${options.threshold}`);
      //console.log(targetElmt.rootBounds);
      console.log(`============================================`);
   }
   isOut(rootElmnt, targetElmt, options) {
      if (!rootElmnt) {
         console.log(`IO Root: VIEWPORT`);
      } else {
         console.log(`IO Root: ${rootElmnt.tagName} class="${rootElmnt.classList}"`);
      }
      console.log(`IO Target: ${targetElmt.target.tagName} class="${targetElmt.target.classList}" IS OUT `);
      console.log(`============================================`);
   }
}

【讨论】:

    【解决方案5】:

    这仍然需要调整,但您可以尝试以下方法:

    const header = document.getElementsByTagName('header')[0];
    
    const observer = new IntersectionObserver((entries) => {
    	entries.forEach((entry) => {
        if (entry.isIntersecting) {
        	  header.style.color = entry.target.dataset.color || '';
            header.style.backgroundColor = entry.target.dataset.background;
        }
      });
    }, { threshold: 0.51 });
    
    [...document.getElementsByClassName('observed')].forEach((t) => {
        t.dataset.background = t.dataset.background || window.getComputedStyle(t).backgroundColor;
        observer.observe(t);    
    });
    body {
      font-family: arial;
      margin: 0;
    }
    
    header {
      border-bottom: 1px solid red;
      margin: 0 auto;
      width: 100vw;
      display: flex;
      justify-content: center;
      position: fixed;
      background: transparent;  
      transition: all 0.5s ease-out;
    }
    
    header div {
      padding: 0.5rem 1rem;
      border: 1px solid red;
      margin: -1px -1px -1px 0;
    }
    
    .observed {
      height: 100vh;
      border: 1px solid black;
    }
    
    .observed:nth-of-type(2) {
      background-color: grey;
    }
    
    .observed:nth-of-type(3) {
      background-color: white;
    }
    <header>
      <div>One</div>
      <div>Two</div>
      <div>Three</div>
    </header>
    
    <div class="observed">
      <img src="http://placekitten.com/g/200/300">
      <img src="http://placekitten.com/g/400/300">
    </div>
      
    <div class="observed" data-color="white" data-background="black">
      <img src="http://placekitten.com/g/600/300">
    </div>
    
    <div class="observed" data-color="black" data-background="white">
      <img src="http://placekitten.com/g/600/250">
    </div>

    CSS 确保每个观察到的部分占用 100vw,并且当其中任何一个部分以至少 51% 的百分比进入视野时,观察者会执行其操作。

    在回调中,标题的背景色被设置为相交元素的背景色。

    【讨论】:

    • 感谢您回答这个悬而未决的问题。我刚刚尝试了您的代码,但它不起作用。同样在示例中,它在向后滚动时不会返回到默认标题。该方法似乎是我解释的方式,将颜色和背景分开处理
    • 它没有返回到默认状态是由于它触发的时间 - 每当目标之一进入视野至少 50%(阈值)。这意味着它在回滚之前最后一次触发是在第二个 div 上。如果您坚持使用交叉观察器,则需要摆弄配置,但我怀疑滚动监听器,正如您最初的意图,会更适合您的目标,因为固定的标题总是相交的。
    • 在用户:cloned 告诉我 IO 获得了更多关于它的信息之后,它是一种比滚动功能上的旧监听器更现代的方法,它是他的垮台,但即使如果它没有完全按照我想要的方式工作。固定标题没有任何时间相交的问题,事实并非如此。有很多使用交叉点观察器在滚动上更改固定标题的示例:youtu.be/RxnV9Xcw914
    • 据我了解您的目标,您希望在用户向下滚动时更改标题的样式。我试图指出的问题是选择目标:文档根总是相交的,任何其他元素都会像我的示例中那样具有挑剔的行为。您可能会尝试在标题下方添加一个不可见的别名元素,但我认为观看 yOffset 会容易得多。对于像投资组合这样的小项目,性能问题应该可以忽略不计。
    • 在滚动时更改并不总是如此,有时标题会保持其默认状态。因此,例如项目有蓝色背景,我想添加white-menubackground-color="blue" 或保持透明,这取决于项目内容。因此,当向下滚动内容(视频图像)时,每一个都会告诉标题相交时应该是什么,或者什么都不做,并保留默认标题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-06-04
    • 1970-01-01
    • 2015-12-24
    相关资源
    最近更新 更多